import discord from discord.ext import commands from huggingface_hub import hf_hub_download import gradio as gr from dotenv import load_dotenv import os import threading import asyncio # Load environment variables load_dotenv() if os.path.exists("assets") is False: os.makedirs("assets", exist_ok=True) hf_hub_download( "not-lain/assets", "lofi.mp3", repo_type="dataset", local_dir="assets" ) song = "assets/lofi.mp3" # Bot configuration intents = discord.Intents.default() intents.message_content = True bot = commands.Bot(command_prefix="!", intents=intents) class MusicBot: def __init__(self): self.is_playing = False self.voice_client = None self.keepalive_task = None self.last_context = None async def voice_keepalive(self, voice_client): """Keeps the voice connection alive by periodically playing audio""" print("Starting voice keepalive task") while True: if voice_client.is_connected() and not self.is_playing: await self.play_next(self.last_context) await asyncio.sleep(15) else: await asyncio.sleep(1) async def join_voice(self, ctx): if ctx.author.voice: channel = ctx.author.voice.channel if self.voice_client is None: self.voice_client = await channel.connect() self.last_context = ctx if self.keepalive_task: self.keepalive_task.cancel() self.keepalive_task = asyncio.create_task( self.voice_keepalive(self.voice_client) ) else: await self.voice_client.move_to(channel) else: await ctx.send("You need to be in a voice channel!") async def play_next(self, ctx): if not self.is_playing: self.is_playing = True try: audio_source = discord.FFmpegPCMAudio(song) def after_playing(e): self.is_playing = False self.voice_client.play(audio_source, after=after_playing) except Exception as e: print(f"Error playing file: {e}") await ctx.send("Error playing the song.") self.is_playing = False async def stop_playing(self, ctx): try: if self.keepalive_task: self.keepalive_task.cancel() self.keepalive_task = None if self.voice_client: if self.voice_client.is_playing(): self.voice_client.stop() self.is_playing = False self.last_context = None if self.voice_client.is_connected(): await self.voice_client.disconnect(force=False) self.voice_client = None return True return False except Exception as e: print(f"Error during cleanup: {e}") self.is_playing = False self.voice_client = None self.last_context = None self.keepalive_task = None return False music_bot = MusicBot() @bot.event async def on_ready(): print(f"Bot is ready! Logged in as {bot.user}") print("Syncing commands...") try: await bot.tree.sync(guild=None) # Set to None for global sync print("Successfully synced commands globally!") except discord.app_commands.errors.CommandSyncFailure as e: print(f"Failed to sync commands: {e}") except Exception as e: print(f"An error occurred while syncing commands: {e}") @bot.tree.command(name="play", description="Play the sample music") async def play(interaction: discord.Interaction): await interaction.response.defer() ctx = await bot.get_context(interaction) await music_bot.join_voice(ctx) if not music_bot.is_playing: await music_bot.play_next(ctx) await interaction.followup.send("Playing sample music!") else: await interaction.followup.send("Already playing!") @bot.tree.command(name="skip", description="Skip the current song") async def skip(interaction: discord.Interaction): # Check if user is in a voice channel if not interaction.user.voice: await interaction.response.send_message( "You must be in a voice channel to use this command!" ) return # Check if bot is in a voice channel if not music_bot.voice_client: await interaction.response.send_message("No song is currently playing!") return # Check if user is in the same channel as the bot if interaction.user.voice.channel != music_bot.voice_client.channel: await interaction.response.send_message( "You must be in the same voice channel as the bot!" ) return if music_bot.voice_client and music_bot.is_playing: music_bot.is_playing = False # Reset playing state music_bot.voice_client.stop() await interaction.response.send_message("Skipped current song!") else: await interaction.response.send_message("No song is currently playing!") @bot.tree.command(name="leave", description="Disconnect bot from voice channel") async def leave(interaction: discord.Interaction): # Check if user is in a voice channel if not interaction.user.voice: await interaction.response.send_message( "You must be in a voice channel to use this command!" ) return # Check if bot is in a voice channel if not music_bot.voice_client: await interaction.response.send_message("I'm not in any voice channel!") return # Check if user is in the same channel as the bot if interaction.user.voice.channel != music_bot.voice_client.channel: await interaction.response.send_message( "You must be in the same voice channel as the bot!" ) return await interaction.response.defer() ctx = await bot.get_context(interaction) try: success = await music_bot.stop_playing(ctx) if success: await interaction.followup.send("Successfully disconnected! 👋") else: await interaction.followup.send( "Failed to disconnect properly. Please try again." ) except Exception as e: print(f"Error during leave command: {e}") await interaction.followup.send("An error occurred while trying to disconnect.") def run_discord_bot(): bot.run(os.getenv("DISCORD_TOKEN")) # Create the Gradio interface with gr.Blocks() as iface: gr.Markdown("# Discord Music Bot Control Panel") gr.Markdown("Bot is running in background") if __name__ == "__main__": # Start the Discord bot in a separate thread bot_thread = threading.Thread(target=run_discord_bot, daemon=True) bot_thread.start() # Run Gradio interface in the main thread iface.launch(debug=True)