From fcc3635b9f24051ae07ed597632597e20372c889 Mon Sep 17 00:00:00 2001 From: SamlonDev Date: Tue, 20 May 2025 05:45:23 +0200 Subject: initial push --- cogs/music/join.py | 13 +++++++ cogs/music/leave.py | 13 +++++++ cogs/music/loop.py | 22 +++++++++++ cogs/music/play.py | 53 ++++++++++++++++++++++++++ cogs/music/play_compressed.py | 88 +++++++++++++++++++++++++++++++++++++++++++ cogs/music/queue.py | 22 +++++++++++ cogs/music/skip.py | 47 +++++++++++++++++++++++ 7 files changed, 258 insertions(+) create mode 100644 cogs/music/join.py create mode 100644 cogs/music/leave.py create mode 100644 cogs/music/loop.py create mode 100644 cogs/music/play.py create mode 100644 cogs/music/play_compressed.py create mode 100644 cogs/music/queue.py create mode 100644 cogs/music/skip.py (limited to 'cogs/music') 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 @@ +import discord +from discord.ext import commands + +class Join(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @commands.slash_command(name="join", description="dołącza do kanalu") + async def join(self, ctx): + await ctx.voice_client.connect() + +def setup(bot): + 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 @@ +import discord +from discord.ext import commands + +class Leave(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @commands.slash_command(name="kick", description="kickuje bota z kanalu") + async def kick(self, ctx): + await ctx.voice_client.disconnect() + +def setup(bot): + 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 @@ +from discord.ext import commands + +class Loop(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.looping = {} + + def is_looping(self, guild_id): + return self.looping.get(guild_id, False) + + def set_looping(self, guild_id, value): + self.looping[guild_id] = value + + @commands.slash_command(name="loop", description="włącz/wyłącz loopowanie dla bieżącej melodyji") + async def loop(self, ctx): + guild_id = ctx.guild.id + looping = not self.is_looping(guild_id) + self.set_looping(guild_id, looping) + await ctx.respond(f"looping jest teraz {'włączony' if looping else 'wyłączony'}.") + +def setup(bot): + 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 @@ +import discord +from discord.ext import commands +import asyncio +from youtubesearchpython import VideosSearch + +class Play(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @commands.slash_command(name="grajcuj", description="grajcuj melodyje") + async def play(self, ctx, *, search: str): + await ctx.defer() + if not (ctx.author.voice and ctx.author.voice.channel): + await ctx.followup.send("nie jesteś w kanale głosowym") + return + channel = ctx.author.voice.channel + if ctx.voice_client is not None: + vc = ctx.voice_client + await vc.move_to(channel) + else: + vc = await channel.connect() + videos_search = VideosSearch(search, limit=1) + result = videos_search.result() + if not result['result']: + await ctx.followup.send("nie znaleziono wideo dla twojego wyszukiwania.", ephemeral=True) + return + video = result['result'][0] + video_id = video['id'] + title = video['title'] + url = video['link'] + proc = await asyncio.create_subprocess_exec( + "yt-dlp", "-f", "bestaudio", "-g", "--no-cache-dir", url, + stdout=asyncio.subprocess.PIPE + ) + stdout, _ = await proc.communicate() + stream_url = stdout.decode().strip() + FFMPEG_OPTIONS = { + 'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', + 'options': '-vn' + } + audio = discord.FFmpegPCMAudio( + stream_url, + before_options=FFMPEG_OPTIONS['before_options'], + options=FFMPEG_OPTIONS['options'] + ) + if not vc.is_playing(): + vc.play(audio) + await ctx.followup.send(f"gra: {title}") + else: + await ctx.followup.send(f"dodano do koleyjki: {title}") + +def setup(bot): + 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 @@ +import discord +from discord.ext import commands +import asyncio +import os +import subprocess +from youtubesearchpython import VideosSearch + +class GrajcujZkompresowane(commands.Cog): + def __init__(self, bot): + self.bot = bot + + def prepend_title_to_file(self, file_path, title): + try: + with open(file_path, 'rb') as original: + data = original.read() + with open(file_path, 'wb') as modified: + modified.write(f"{title}\n".encode('utf-8')) + modified.write(data) + except Exception as e: + print(f"Failed to prepend title: {e}") + + def compress_audio(self, input_path): + base, ext = os.path.splitext(input_path) + output_path = f"{base}_compressed{ext}" + ffmpeg_command = f"ffmpeg -i {input_path} -ar 8000 -ac 1 -b:a 500 -acodec libmp3lame -q:a 9 {output_path}" + subprocess.run(ffmpeg_command, check=True, shell=True) + return output_path + + @commands.slash_command(name="grajcuj_zkompresowane", description="grajcuj zkompresowane melodyje") + async def grajcuj_zkompresowane(self, ctx, *, search: str): + await ctx.defer() + if not (ctx.author.voice and ctx.author.voice.channel): + await ctx.followup.send("nie jesteś w kanale głosowym") + return + channel = ctx.author.voice.channel + if ctx.voice_client is not None: + vc = ctx.voice_client + await vc.move_to(channel) + else: + vc = await channel.connect() + bot_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + music_dir = os.path.join(bot_dir, "temp", "music") + if not os.path.exists(music_dir): + os.makedirs(music_dir) + videos_search = VideosSearch(search, limit=1) + result = videos_search.result() + if not result['result']: + await ctx.followup.send("Could not find a video for your search.", ephemeral=True) + return + video = result['result'][0] + video_id = video['id'] + title = video['title'] + url = video['link'] + filename = f"{video_id}.mp3" + file_path = os.path.join(music_dir, filename) + compressed_file_path = os.path.join(music_dir, f"{video_id}_compressed.mp3") + if os.path.exists(compressed_file_path): + found_file = compressed_file_path + found_title = title + else: + if not os.path.exists(file_path): + cmd = [ + "yt-dlp", + "-x", + "--audio-format", "mp3", + "-o", file_path, + url + ] + process = await asyncio.create_subprocess_exec(*cmd) + await process.communicate() + self.prepend_title_to_file(file_path, title) + if not os.path.exists(compressed_file_path): + try: + compressed_file_path = self.compress_audio(file_path) + except subprocess.CalledProcessError as e: + await ctx.followup.send(f"skompresowanie nie powiodło się: {str(e)}", ephemeral=True) + return + found_file = compressed_file_path + found_title = title + title = found_title + if not vc.is_playing(): + vc.play(discord.FFmpegPCMAudio(found_file)) + await ctx.followup.send(f"gra (zkompresowane): {title}") + else: + await ctx.followup.send(f"dodano do koleyjki (zkompresowane): {title}") + +def setup(bot): + 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 @@ +from discord.ext import commands + +class Queue(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.queues = {} + + def get_queue(self, guild_id): + return self.queues.setdefault(guild_id, []) + + @commands.slash_command(name="koleyjka", description="pokazuje koleyjke") + async def queue(self, ctx): + guild_id = ctx.guild.id + queue = self.get_queue(guild_id) + if queue: + queue_str = "\n".join(f"{i+1}. {title}" for i, (_, title, _) in enumerate(queue)) + await ctx.respond(f"koleyjka:\n{queue_str}") + else: + await ctx.respond("koleyjka jest pustawa") + +def setup(bot): + 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 @@ +from discord.ext import commands +import discord + +class Skip(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.queues = {} + + def get_queue(self, guild_id): + return self.queues.setdefault(guild_id, []) + + def play_next(self, ctx, vc, guild_id): + queue = self.get_queue(guild_id) + if queue: + _, _, file_path = queue[0] + def after_playing(error=None): + if queue: + queue.pop(0) + if queue: + _, _, next_file = queue[0] + if not vc.is_playing(): + vc.play(discord.FFmpegPCMAudio(next_file), after=after_playing) + if not vc.is_playing(): + vc.play(discord.FFmpegPCMAudio(file_path), after=after_playing) + + @commands.slash_command(name="pomiń", description="przeskocz do nastepnej melodyji") + async def pomin(self, ctx): + guild_id = ctx.guild.id + vc = ctx.voice_client + if vc and vc.is_playing(): + queue = self.get_queue(guild_id) + if queue: + queue.pop(0) + if queue: + vc.stop() + self.play_next(ctx, vc, guild_id) + await ctx.respond("przeskoczono do nastepnej melodyji") + else: + await ctx.respond("koleyjka jest pustawa") + await vc.disconnect() + else: + await ctx.respond("nic nie gra") + else: + await ctx.respond("nic nie gra") + +def setup(bot): + bot.add_cog(Skip(bot)) \ No newline at end of file -- cgit v1.2.3