import discord from discord import app_commands from discord.ext import commands import asyncio import os from dotenv import load_dotenv from ytdl import YTDLSource # Load environment variables load_dotenv() TOKEN = os.getenv('DISCORD_TOKEN') GUILD_ID = os.getenv('GUILD_ID') class MusicBot(commands.Cog): def __init__(self, bot): self.bot = bot self.queue = [] self.current = None self.volume = 1.0 # Domyślna głośność ustawiona na 100% (1.0) self.loop_current = False self.last_channel = None def load_saved_channel_id(self): if os.path.exists("config.json"): try: import json with open("config.json", "r") as f: data = json.load(f) return data.get("text_channel_id") except Exception as e: print(f"Error loading config: {e}") return None def save_channel_id(self, channel_id): try: import json data = {} if os.path.exists("config.json"): with open("config.json", "r") as f: data = json.load(f) data["text_channel_id"] = channel_id with open("config.json", "w") as f: json.dump(data, f, indent=4) except Exception as e: print(f"Error saving config: {e}") def get_notification_channel(self): if self.last_channel: return self.last_channel saved_id = self.load_saved_channel_id() if saved_id: channel = self.bot.get_channel(int(saved_id)) if channel: self.last_channel = channel return channel voice_client = self.bot.voice_clients[0] if self.bot.voice_clients else None if voice_client and voice_client.channel: for tc in voice_client.channel.guild.text_channels: if tc.permissions_for(voice_client.channel.guild.me).send_messages: self.last_channel = tc return tc return None async def ensure_voice(self, interaction): if not interaction.user.voice: await interaction.response.send_message( "Nie jesteś połączony z kanałem głosowym.", ephemeral=True ) return False if interaction.guild.voice_client is None: await interaction.user.voice.channel.connect() elif interaction.guild.voice_client.channel != interaction.user.voice.channel: await interaction.response.send_message( "Jestem już połączony z innym kanałem głosowym.", ephemeral=True ) return False return True @app_commands.command(name="play", description="Odtwórz utwór z YouTube") @app_commands.describe(query="Link YouTube lub zapytanie wyszukiwania") async def play(self, interaction: discord.Interaction, query: str): """Odtwórz utwór z YouTube""" if not await self.ensure_voice(interaction): return await interaction.response.defer() self.last_channel = interaction.channel try: player = await YTDLSource.from_url(query, loop=self.bot.loop, stream=True) if interaction.guild.voice_client.is_playing(): self.queue.append(player) await interaction.followup.send( f"Dodano do kolejki: {player.title}", ephemeral=False ) else: self.current = player interaction.guild.voice_client.play( player, after=lambda e: asyncio.run_coroutine_threadsafe( self.play_next(), self.bot.loop ) ) await interaction.followup.send( f"Teraz odtwarzane: {player.title}", ephemeral=False ) except Exception as e: await interaction.followup.send( f"Wystąpił błąd: {e}", ephemeral=True ) async def play_next(self): voice_client = self.bot.voice_clients[0] if self.bot.voice_clients else None if not voice_client: self.current = None return if self.loop_current and self.current: try: url = self.current.data.get('webpage_url') or self.current.url player = await YTDLSource.from_url(url, loop=self.bot.loop, stream=True) self.current = player voice_client.play( self.current, after=lambda e: asyncio.run_coroutine_threadsafe( self.play_next(), self.bot.loop ) ) await self.send_to_last_channel(f"Teraz odtwarzane (zapętlone): {self.current.title}") return except Exception as e: print(f"Error repeating song: {e}") if len(self.queue) > 0: self.current = self.queue.pop(0) voice_client.play( self.current, after=lambda e: asyncio.run_coroutine_threadsafe( self.play_next(), self.bot.loop ) ) await self.send_to_last_channel(f"Teraz odtwarzane: {self.current.title}") else: self.current = None await self.send_to_last_channel("Kolejka jest pusta.") async def send_to_last_channel(self, text): channel = self.get_notification_channel() if channel: try: await channel.send(text) except Exception as e: print(f"Failed to send message: {e}") @app_commands.command(name="queue", description="Pokaż aktualną kolejkę") async def show_queue(self, interaction: discord.Interaction): """Pokaż aktualną kolejkę""" if not self.queue: await interaction.response.send_message( "Kolejka jest pusta.", ephemeral=True ) return queue_list = "\n".join([f"{i + 1}. {item.title}" for i, item in enumerate(self.queue)]) await interaction.response.send_message( f"Aktualna kolejka:\n{queue_list}", ephemeral=False ) @app_commands.command(name="skip", description="Pomiń aktualny utwór") async def skip(self, interaction: discord.Interaction): """Pomiń aktualny utwór""" if interaction.guild.voice_client.is_playing(): interaction.guild.voice_client.stop() await interaction.response.send_message( "Pominięto aktualny utwór.", ephemeral=False ) else: await interaction.response.send_message( "Nic nie jest odtwarzane.", ephemeral=True ) @app_commands.command(name="pause", description="Wstrzymaj odtwarzanie") async def pause(self, interaction: discord.Interaction): """Wstrzymaj odtwarzanie""" if interaction.guild.voice_client.is_playing(): interaction.guild.voice_client.pause() await interaction.response.send_message( "Odtwarzanie wstrzymane.", ephemeral=False ) else: await interaction.response.send_message( "Nic nie jest odtwarzane.", ephemeral=True ) @app_commands.command(name="resume", description="Wznów odtwarzanie") async def resume(self, interaction: discord.Interaction): """Wznów odtwarzanie""" if interaction.guild.voice_client.is_paused(): interaction.guild.voice_client.resume() await interaction.response.send_message( "Odtwarzanie wznowione.", ephemeral=False ) else: await interaction.response.send_message( "Odtwarzanie nie jest wstrzymane.", ephemeral=True ) @app_commands.command(name="stop", description="Zatrzymaj odtwarzanie i wyczyść kolejkę") async def stop(self, interaction: discord.Interaction): """Zatrzymaj odtwarzanie i wyczyść kolejkę""" if interaction.guild.voice_client.is_playing(): interaction.guild.voice_client.stop() self.queue.clear() self.current = None await interaction.response.send_message( "Zatrzymano odtwarzanie i wyczyszczono kolejkę.", ephemeral=False ) @app_commands.command(name="volume", description="Zmień głośność odtwarzacza") @app_commands.describe(volume="Poziom głośności (1-100)") async def volume(self, interaction: discord.Interaction, volume: int): """Zmień głośność odtwarzacza""" if interaction.guild.voice_client is None: return await interaction.response.send_message( "Nie połączono z kanałem głosowym.", ephemeral=True ) if 0 < volume <= 100: self.volume = volume / 100 interaction.guild.voice_client.source.volume = self.volume await interaction.response.send_message( f"Zmieniono głośność na {volume}%", ephemeral=False ) return None else: await interaction.response.send_message( "Wprowadź wartość z przedziału od 1 do 100.", ephemeral=True ) return None @app_commands.command(name="nowplaying", description="Pokaż aktualnie odtwarzany utwór") async def now_playing(self, interaction: discord.Interaction): """Pokaż aktualnie odtwarzany utwór""" if self.current: await interaction.response.send_message( f"Teraz odtwarzane: {self.current.title}", ephemeral=False ) else: await interaction.response.send_message( "Nic nie jest obecnie odtwarzane.", ephemeral=True ) @app_commands.command(name="leave", description="Odłącz bota od kanału głosowego") async def leave(self, interaction: discord.Interaction): """Odłącz bota od kanału głosowego""" if interaction.guild.voice_client is not None: await interaction.guild.voice_client.disconnect() self.queue.clear() self.current = None await interaction.response.send_message( "Rozłączono z kanału głosowego.", ephemeral=False ) else: await interaction.response.send_message( "Nie jestem na kanale głosowym.", ephemeral=True ) @app_commands.command(name="loop", description="Włącz/wyłącz zapętlanie aktualnego utworu") async def loop_command(self, interaction: discord.Interaction): """Włącz/wyłącz zapętlanie aktualnego utworu""" self.loop_current = not self.loop_current state = "włączone" if self.loop_current else "wyłączone" await interaction.response.send_message( f"Zapętlanie aktualnego utworu zostało {state}.", ephemeral=False ) class MyBot(commands.Bot): def __init__(self): intents = discord.Intents.default() intents.message_content = True intents.voice_states = True super().__init__(command_prefix="!", intents=intents) async def setup_hook(self): await self.add_cog(MusicBot(self)) if GUILD_ID: guild = discord.Object(id=int(GUILD_ID)) self.tree.copy_global_to(guild=guild) await self.tree.sync(guild=guild) print(f"Synced commands to guild {GUILD_ID}") else: await self.tree.sync() print("Synced commands globally") async def on_ready(self): print(f'Logged in as {self.user.name} ({self.user.id})') print('------') bot = MyBot()