aboutsummaryrefslogtreecommitdiffstats
path: root/cogs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--cogs/compression.py88
-rw-r--r--cogs/music/join.py13
-rw-r--r--cogs/music/leave.py13
-rw-r--r--cogs/music/loop.py22
-rw-r--r--cogs/music/play.py53
-rw-r--r--cogs/music/play_compressed.py88
-rw-r--r--cogs/music/queue.py22
-rw-r--r--cogs/music/skip.py47
-rw-r--r--cogs/ping_commands.py60
-rw-r--r--cogs/tts.py47
-rw-r--r--cogs/vc_logs.py83
11 files changed, 536 insertions, 0 deletions
diff --git a/cogs/compression.py b/cogs/compression.py
new file mode 100644
index 0000000..dfd96ae
--- /dev/null
+++ b/cogs/compression.py
@@ -0,0 +1,88 @@
1import discord
2from discord.ext import commands
3import asyncio
4import mimetypes
5import os
6import subprocess
7import tempfile
8
9def filetype(filename):
10 mime_type, _ = mimetypes.guess_type(filename)
11 if mime_type:
12 if mime_type.startswith('video/'):
13 return "Video"
14 elif mime_type.startswith('audio/'):
15 return "Audio"
16 elif mime_type.startswith('image/'):
17 return "Image"
18 return "Unknown"
19
20class Compression(commands.Cog):
21 def __init__(self, bot):
22 self.bot = bot
23
24 @commands.slash_command(
25 name="kompresja",
26 description="skompresuj wideło albo dźwienk :)",
27 )
28 @discord.option(
29 "plik",
30 description="plik do skompresowania",
31 required=True,
32 type=discord.Attachment
33 )
34 async def compression(self, ctx, plik):
35 await ctx.defer()
36 # Save files to temp directory inside the bot's root directory
37 bot_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
38 temp_dir = os.path.join(bot_dir, "temp")
39 if not os.path.exists(temp_dir):
40 os.makedirs(temp_dir)
41 file_path = os.path.join(temp_dir, plik.filename)
42 await plik.save(file_path)
43
44 input_path = file_path
45 output_path = os.path.join(temp_dir, f"better_{plik.filename}")
46 file_type = filetype(file_path)
47 if file_type == "Video":
48 # Execute ffmpeg command to compress video
49 ffmpeg_command = f"ffmpeg -i {input_path} -c:v libx264 -crf 51 -b:v 100 -vf 'fps=10' -preset ultrafast -c:a libopus -b:a 500 {output_path}"
50 elif file_type == "Audio":
51 ffmpeg_command = f"ffmpeg -i {input_path} -ar 8000 -ac 1 -b:a 16k -acodec libmp3lame -q:a 9 {output_path}"
52 elif file_type == "Image":
53 # Use ImageMagick's magick to heavily compress image (JPEG/PNG/GIF)
54 # For JPEG: quality 5, strip metadata, resize to 30% of original size
55 # For PNG: magick to JPEG, then compress
56 # For GIF: optimize and reduce colors
57 ext = os.path.splitext(input_path)[1].lower()
58 if ext in [".jpg", ".jpeg"]:
59 img_command = f"magick {input_path} -strip -resize 30% -quality 5 {output_path}"
60 elif ext == ".gif":
61 # Optimize GIF: reduce colors, optimize layers, and resize
62 img_command = f"magick {input_path} -coalesce -resize 30% -colors 32 -strip -layers Optimize {output_path}"
63 else:
64 # magick non-JPEG images to JPEG for maximum compression
65 output_path = os.path.splitext(output_path)[0] + ".jpg"
66 img_command = f"magick {input_path} -strip -resize 30% -quality 5 {output_path}"
67 ffmpeg_command = img_command
68 else:
69 await ctx.respond("Plik jest nieobsługiwany", ephemeral=True)
70 return
71
72 try:
73 subprocess.run(ffmpeg_command, check=True, shell=True)
74 # Upload compressed file
75 await ctx.respond(file=discord.File(output_path))
76 # Delete compressed file
77 os.remove(input_path)
78 os.remove(output_path)
79 except subprocess.CalledProcessError as e:
80 await ctx.respond(f"Compression failed: {str(e)}", ephemeral=True)
81 if os.path.exists(input_path):
82 os.remove(input_path)
83 if os.path.exists(output_path):
84 os.remove(output_path)
85
86
87def setup(bot):
88 bot.add_cog(Compression(bot)) \ No newline at end of file
diff --git a/cogs/music/join.py b/cogs/music/join.py
new file mode 100644
index 0000000..91a0b18
--- /dev/null
+++ b/cogs/music/join.py
@@ -0,0 +1,13 @@
1import discord
2from discord.ext import commands
3
4class Join(commands.Cog):
5 def __init__(self, bot):
6 self.bot = bot
7
8 @commands.slash_command(name="join", description="dołącza do kanalu")
9 async def join(self, ctx):
10 await ctx.voice_client.connect()
11
12def setup(bot):
13 bot.add_cog(Join(bot)) \ No newline at end of file
diff --git a/cogs/music/leave.py b/cogs/music/leave.py
new file mode 100644
index 0000000..0be2068
--- /dev/null
+++ b/cogs/music/leave.py
@@ -0,0 +1,13 @@
1import discord
2from discord.ext import commands
3
4class Leave(commands.Cog):
5 def __init__(self, bot):
6 self.bot = bot
7
8 @commands.slash_command(name="kick", description="kickuje bota z kanalu")
9 async def kick(self, ctx):
10 await ctx.voice_client.disconnect()
11
12def setup(bot):
13 bot.add_cog(Leave(bot)) \ No newline at end of file
diff --git a/cogs/music/loop.py b/cogs/music/loop.py
new file mode 100644
index 0000000..5f51c7e
--- /dev/null
+++ b/cogs/music/loop.py
@@ -0,0 +1,22 @@
1from discord.ext import commands
2
3class Loop(commands.Cog):
4 def __init__(self, bot):
5 self.bot = bot
6 self.looping = {}
7
8 def is_looping(self, guild_id):
9 return self.looping.get(guild_id, False)
10
11 def set_looping(self, guild_id, value):
12 self.looping[guild_id] = value
13
14 @commands.slash_command(name="loop", description="włącz/wyłącz loopowanie dla bieżącej melodyji")
15 async def loop(self, ctx):
16 guild_id = ctx.guild.id
17 looping = not self.is_looping(guild_id)
18 self.set_looping(guild_id, looping)
19 await ctx.respond(f"looping jest teraz {'włączony' if looping else 'wyłączony'}.")
20
21def setup(bot):
22 bot.add_cog(Loop(bot)) \ No newline at end of file
diff --git a/cogs/music/play.py b/cogs/music/play.py
new file mode 100644
index 0000000..1eafbca
--- /dev/null
+++ b/cogs/music/play.py
@@ -0,0 +1,53 @@
1import discord
2from discord.ext import commands
3import asyncio
4from youtubesearchpython import VideosSearch
5
6class Play(commands.Cog):
7 def __init__(self, bot):
8 self.bot = bot
9
10 @commands.slash_command(name="grajcuj", description="grajcuj melodyje")
11 async def play(self, ctx, *, search: str):
12 await ctx.defer()
13 if not (ctx.author.voice and ctx.author.voice.channel):
14 await ctx.followup.send("nie jesteś w kanale głosowym")
15 return
16 channel = ctx.author.voice.channel
17 if ctx.voice_client is not None:
18 vc = ctx.voice_client
19 await vc.move_to(channel)
20 else:
21 vc = await channel.connect()
22 videos_search = VideosSearch(search, limit=1)
23 result = videos_search.result()
24 if not result['result']:
25 await ctx.followup.send("nie znaleziono wideo dla twojego wyszukiwania.", ephemeral=True)
26 return
27 video = result['result'][0]
28 video_id = video['id']
29 title = video['title']
30 url = video['link']
31 proc = await asyncio.create_subprocess_exec(
32 "yt-dlp", "-f", "bestaudio", "-g", "--no-cache-dir", url,
33 stdout=asyncio.subprocess.PIPE
34 )
35 stdout, _ = await proc.communicate()
36 stream_url = stdout.decode().strip()
37 FFMPEG_OPTIONS = {
38 'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5',
39 'options': '-vn'
40 }
41 audio = discord.FFmpegPCMAudio(
42 stream_url,
43 before_options=FFMPEG_OPTIONS['before_options'],
44 options=FFMPEG_OPTIONS['options']
45 )
46 if not vc.is_playing():
47 vc.play(audio)
48 await ctx.followup.send(f"gra: {title}")
49 else:
50 await ctx.followup.send(f"dodano do koleyjki: {title}")
51
52def setup(bot):
53 bot.add_cog(Play(bot)) \ No newline at end of file
diff --git a/cogs/music/play_compressed.py b/cogs/music/play_compressed.py
new file mode 100644
index 0000000..3297110
--- /dev/null
+++ b/cogs/music/play_compressed.py
@@ -0,0 +1,88 @@
1import discord
2from discord.ext import commands
3import asyncio
4import os
5import subprocess
6from youtubesearchpython import VideosSearch
7
8class GrajcujZkompresowane(commands.Cog):
9 def __init__(self, bot):
10 self.bot = bot
11
12 def prepend_title_to_file(self, file_path, title):
13 try:
14 with open(file_path, 'rb') as original:
15 data = original.read()
16 with open(file_path, 'wb') as modified:
17 modified.write(f"{title}\n".encode('utf-8'))
18 modified.write(data)
19 except Exception as e:
20 print(f"Failed to prepend title: {e}")
21
22 def compress_audio(self, input_path):
23 base, ext = os.path.splitext(input_path)
24 output_path = f"{base}_compressed{ext}"
25 ffmpeg_command = f"ffmpeg -i {input_path} -ar 8000 -ac 1 -b:a 500 -acodec libmp3lame -q:a 9 {output_path}"
26 subprocess.run(ffmpeg_command, check=True, shell=True)
27 return output_path
28
29 @commands.slash_command(name="grajcuj_zkompresowane", description="grajcuj zkompresowane melodyje")
30 async def grajcuj_zkompresowane(self, ctx, *, search: str):
31 await ctx.defer()
32 if not (ctx.author.voice and ctx.author.voice.channel):
33 await ctx.followup.send("nie jesteś w kanale głosowym")
34 return
35 channel = ctx.author.voice.channel
36 if ctx.voice_client is not None:
37 vc = ctx.voice_client
38 await vc.move_to(channel)
39 else:
40 vc = await channel.connect()
41 bot_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
42 music_dir = os.path.join(bot_dir, "temp", "music")
43 if not os.path.exists(music_dir):
44 os.makedirs(music_dir)
45 videos_search = VideosSearch(search, limit=1)
46 result = videos_search.result()
47 if not result['result']:
48 await ctx.followup.send("Could not find a video for your search.", ephemeral=True)
49 return
50 video = result['result'][0]
51 video_id = video['id']
52 title = video['title']
53 url = video['link']
54 filename = f"{video_id}.mp3"
55 file_path = os.path.join(music_dir, filename)
56 compressed_file_path = os.path.join(music_dir, f"{video_id}_compressed.mp3")
57 if os.path.exists(compressed_file_path):
58 found_file = compressed_file_path
59 found_title = title
60 else:
61 if not os.path.exists(file_path):
62 cmd = [
63 "yt-dlp",
64 "-x",
65 "--audio-format", "mp3",
66 "-o", file_path,
67 url
68 ]
69 process = await asyncio.create_subprocess_exec(*cmd)
70 await process.communicate()
71 self.prepend_title_to_file(file_path, title)
72 if not os.path.exists(compressed_file_path):
73 try:
74 compressed_file_path = self.compress_audio(file_path)
75 except subprocess.CalledProcessError as e:
76 await ctx.followup.send(f"skompresowanie nie powiodło się: {str(e)}", ephemeral=True)
77 return
78 found_file = compressed_file_path
79 found_title = title
80 title = found_title
81 if not vc.is_playing():
82 vc.play(discord.FFmpegPCMAudio(found_file))
83 await ctx.followup.send(f"gra (zkompresowane): {title}")
84 else:
85 await ctx.followup.send(f"dodano do koleyjki (zkompresowane): {title}")
86
87def setup(bot):
88 bot.add_cog(GrajcujZkompresowane(bot)) \ No newline at end of file
diff --git a/cogs/music/queue.py b/cogs/music/queue.py
new file mode 100644
index 0000000..29f0c36
--- /dev/null
+++ b/cogs/music/queue.py
@@ -0,0 +1,22 @@
1from discord.ext import commands
2
3class Queue(commands.Cog):
4 def __init__(self, bot):
5 self.bot = bot
6 self.queues = {}
7
8 def get_queue(self, guild_id):
9 return self.queues.setdefault(guild_id, [])
10
11 @commands.slash_command(name="koleyjka", description="pokazuje koleyjke")
12 async def queue(self, ctx):
13 guild_id = ctx.guild.id
14 queue = self.get_queue(guild_id)
15 if queue:
16 queue_str = "\n".join(f"{i+1}. {title}" for i, (_, title, _) in enumerate(queue))
17 await ctx.respond(f"koleyjka:\n{queue_str}")
18 else:
19 await ctx.respond("koleyjka jest pustawa")
20
21def setup(bot):
22 bot.add_cog(Queue(bot)) \ No newline at end of file
diff --git a/cogs/music/skip.py b/cogs/music/skip.py
new file mode 100644
index 0000000..f48218b
--- /dev/null
+++ b/cogs/music/skip.py
@@ -0,0 +1,47 @@
1from discord.ext import commands
2import discord
3
4class Skip(commands.Cog):
5 def __init__(self, bot):
6 self.bot = bot
7 self.queues = {}
8
9 def get_queue(self, guild_id):
10 return self.queues.setdefault(guild_id, [])
11
12 def play_next(self, ctx, vc, guild_id):
13 queue = self.get_queue(guild_id)
14 if queue:
15 _, _, file_path = queue[0]
16 def after_playing(error=None):
17 if queue:
18 queue.pop(0)
19 if queue:
20 _, _, next_file = queue[0]
21 if not vc.is_playing():
22 vc.play(discord.FFmpegPCMAudio(next_file), after=after_playing)
23 if not vc.is_playing():
24 vc.play(discord.FFmpegPCMAudio(file_path), after=after_playing)
25
26 @commands.slash_command(name="pomiń", description="przeskocz do nastepnej melodyji")
27 async def pomin(self, ctx):
28 guild_id = ctx.guild.id
29 vc = ctx.voice_client
30 if vc and vc.is_playing():
31 queue = self.get_queue(guild_id)
32 if queue:
33 queue.pop(0)
34 if queue:
35 vc.stop()
36 self.play_next(ctx, vc, guild_id)
37 await ctx.respond("przeskoczono do nastepnej melodyji")
38 else:
39 await ctx.respond("koleyjka jest pustawa")
40 await vc.disconnect()
41 else:
42 await ctx.respond("nic nie gra")
43 else:
44 await ctx.respond("nic nie gra")
45
46def setup(bot):
47 bot.add_cog(Skip(bot)) \ No newline at end of file
diff --git a/cogs/ping_commands.py b/cogs/ping_commands.py
new file mode 100644
index 0000000..beb9685
--- /dev/null
+++ b/cogs/ping_commands.py
@@ -0,0 +1,60 @@
1import discord
2from discord.ext import commands
3import asyncio
4from yt_dlp import VideosSearch
5
6class PingCommands(commands.Cog):
7 def __init__(self, bot):
8 self.bot = bot
9
10 @commands.Cog.command()
11 async def vc(self, ctx):
12 # join voice channel
13 pass
14
15 @commands.slash_command(name="grajcuj", description="grajcuj melodyje")
16 async def play(self, ctx, *, search: str):
17 await ctx.defer()
18 if not (ctx.author.voice and ctx.author.voice.channel):
19 await ctx.followup.send("nie jesteś w kanale głosowym")
20 return
21 channel = ctx.author.voice.channel
22 if ctx.voice_client is not None:
23 vc = ctx.voice_client
24 await vc.move_to(channel)
25 else:
26 vc = await channel.connect()
27 videos_search = VideosSearch(search, limit=1)
28 result = videos_search.result()
29 if not result['result']:
30 await ctx.followup.send("nie znaleziono wideo dla twojego wyszukiwania.", ephemeral=True)
31 return
32 video = result['result'][0]
33 title = video['title']
34 url = video['link']
35
36 # Get direct audio stream URL
37 proc = await asyncio.create_subprocess_exec(
38 "yt-dlp", "-f", "bestaudio", "-g", url,
39 stdout=asyncio.subprocess.PIPE
40 )
41 stdout, _ = await proc.communicate()
42 stream_url = stdout.decode().strip()
43
44 ffmpeg_options = {
45 "before_options": "-probesize 32k -analyzeduration 0 -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5",
46 "options": "-vn"
47 }
48 audio = discord.FFmpegPCMAudio(
49 stream_url,
50 before_options=ffmpeg_options["before_options"],
51 options=ffmpeg_options["options"]
52 )
53 if not vc.is_playing():
54 vc.play(audio)
55 await ctx.followup.send(f"gra: {title}")
56 else:
57 await ctx.followup.send(f"dodano do koleyjki: {title}")
58
59
60
diff --git a/cogs/tts.py b/cogs/tts.py
new file mode 100644
index 0000000..41dc366
--- /dev/null
+++ b/cogs/tts.py
@@ -0,0 +1,47 @@
1import discord
2from discord.ext import commands
3from gtts import gTTS
4import os
5import datetime
6
7class TTS(commands.Cog):
8 def __init__(self, bot):
9 self.bot = bot
10
11 @commands.slash_command(name="tts", description="Generuje TTS dla danego tekstu")
12 async def tts(self, ctx,
13 text: str = discord.Option(str, "Tekst do przeczytania", required=True),
14 output: str = discord.Option(str, "Wybierz sposób odtwarzania", choices=["file", "vc"], required=True)
15 ):
16 tts = gTTS(text=text, lang='pl')
17 tts.save('tts.mp3')
18 if output == "file":
19 await ctx.respond(file=discord.File('tts.mp3'))
20 os.remove('tts.mp3')
21 elif output == "vc":
22 # Check if user is in a voice channel
23 if not (ctx.author.voice and ctx.author.voice.channel):
24 await ctx.respond("Musisz być na kanale głosowym, aby odtworzyć TTS!", ephemeral=True)
25 os.remove('tts.mp3')
26 return
27 channel = ctx.author.voice.channel
28 # Connect to voice channel if not already connected
29 voice_client = discord.utils.get(self.bot.voice_clients, guild=channel.guild)
30 if not voice_client or not voice_client.is_connected():
31 voice_client = await channel.connect()
32 elif voice_client.channel != channel:
33 await voice_client.move_to(channel)
34 # Play the TTS audio
35 if not voice_client.is_playing():
36 audio_source = discord.FFmpegPCMAudio('tts.mp3', options='-filter:a "volume=6"')
37 voice_client.play(audio_source)
38 # Wait for playback to finish
39 while voice_client.is_playing():
40 await discord.utils.sleep_until(datetime.datetime.now() + datetime.timedelta(seconds=1))
41 os.remove('tts.mp3')
42 else:
43 await ctx.respond("Nieznany sposób odtwarzania.", ephemeral=True)
44 os.remove('tts.mp3')
45
46def setup(bot):
47 bot.add_cog(TTS(bot)) \ No newline at end of file
diff --git a/cogs/vc_logs.py b/cogs/vc_logs.py
new file mode 100644
index 0000000..669be3b
--- /dev/null
+++ b/cogs/vc_logs.py
@@ -0,0 +1,83 @@
1import discord
2from discord.ext import commands
3import datetime
4from gtts import gTTS
5import os
6
7class vc_logs(commands.Cog):
8 def __init__(self, bot):
9 self.bot = bot
10
11 async def play_tts(self, channel, text):
12 # Generate TTS audio
13 tts = gTTS(text=text, lang='pl')
14 tts.save('temp_tts.mp3')
15
16 # Connect to voice channel if not already connected
17 voice_client = discord.utils.get(self.bot.voice_clients, guild=channel.guild)
18 if not voice_client or not voice_client.is_connected():
19 voice_client = await channel.connect()
20 elif voice_client.channel != channel:
21 await voice_client.move_to(channel)
22
23 # Play the TTS audio
24 if not voice_client.is_playing():
25 audio_source = discord.FFmpegPCMAudio('temp_tts.mp3', options='-filter:a "volume=6"')
26 voice_client.play(audio_source)
27 while voice_client.is_playing():
28 await discord.utils.sleep_until(datetime.datetime.now() + datetime.timedelta(seconds=1))
29 os.remove('temp_tts.mp3')
30
31 @commands.Cog.listener()
32 async def on_voice_state_update(self, member, before, after):
33 log_channel = self.bot.get_channel(1213843195457183885)
34 current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
35 tts_text = None
36 tts_channel = None
37 # Ignore if user is a bot
38 if member.bot:
39 return
40 if before.channel is None and after.channel is not None:
41 message = f"[{current_time}] {member.name} dołączył na {after.channel.name}"
42 tts_text = f"{member.display_name} sie zespawnił"
43 tts_channel = after.channel
44 await log_channel.send(message)
45 print(message)
46 elif before.channel is not None and after.channel is None:
47 message = f"[{current_time}] {member.name} rozłączył się z {before.channel.name}"
48 tts_text = f"{member.display_name} jest chujem"
49 tts_channel = before.channel
50 await log_channel.send(message)
51 print(message)
52
53 if before.self_deaf != after.self_deaf:
54 if after.self_deaf:
55 message = f"[{current_time}] {member.name} ogłuchnął się na {after.channel.name}"
56 tts_text = f"{member.display_name} jest bity przez ojca"
57 else:
58 message = f"[{current_time}] {member.name} odgłuchął się na {after.channel.name}"
59 tts_text = f"{member.display_name} uciek od ojca"
60 tts_channel = after.channel
61 await log_channel.send(message)
62 print(message)
63 if tts_text and tts_channel:
64 await self.play_tts(tts_channel, tts_text)
65 return
66
67 if before.self_mute != after.self_mute:
68 if after.self_mute:
69 message = f"[{current_time}] {member.name} wyciszył się na {after.channel.name}"
70 tts_text = f"{member.display_name} idzie robić jajecznice"
71 else:
72 message = f"[{current_time}] {member.name} odciszył się na {after.channel.name}"
73 tts_text = f"{member.display_name} zrobił jajecznice"
74 tts_channel = after.channel
75 await log_channel.send(message)
76 print(message)
77
78 if tts_text and tts_channel:
79 await self.play_tts(tts_channel, tts_text)
80
81
82def setup(bot):
83 bot.add_cog(vc_logs(bot)) \ No newline at end of file