From 4f38a1a89e228f907f1103c8abc3cd135fa3cb59 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 20 Jan 2025 10:35:28 -0500 Subject: [PATCH] Added repeat feature. Fixed the join when playing a song function. --- audio.py | 36 +++++++++++++++++++++++++++++++----- commands.py | 24 +++++++++++++++++++++++- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/audio.py b/audio.py index f4ef658..be4a9b7 100644 --- a/audio.py +++ b/audio.py @@ -13,6 +13,7 @@ voice_clients = {} # Track active voice connections music_queues = {} # Per-guild song queue current_tracks = {} # Currently playing tracks volumes = {} # Volume levels per guild +repeat_modes = {} # Tracks repeat mode per guild: "one", "all", or "off" default_volume = 0.05 # Default volume (5%) USER_DATA_FILE = 'user_data.json' YOUTUBE_API_KEY = os.getenv("YOUTUBE_API_KEY") # Replace with your API key @@ -52,7 +53,12 @@ async def join_voice(interaction: discord.Interaction): if guild_id not in voice_clients: voice_clients[guild_id] = await channel.connect() - await interaction.followup.send(f"✅ **Joined {channel.name}.**") + + # Ensure the response is completed + if interaction.response.is_done(): + await interaction.followup.send(f"✅ **Joined {channel.name}.**") + else: + await interaction.response.send_message(f"✅ **Joined {channel.name}.**") return voice_clients[guild_id] @@ -61,13 +67,16 @@ async def play_audio(interaction: discord.Interaction, query: str): # Ensure Amber is connected to a voice channel if guild_id not in voice_clients or not voice_clients[guild_id].is_connected(): + await interaction.response.defer() # Defer the response early voice_client = await join_voice(interaction) if voice_client is None: # If join failed return else: voice_client = voice_clients[guild_id] - await interaction.response.defer() + # Defer response if not already done + if not interaction.response.is_done(): + await interaction.response.defer() # Search for the song on YouTube ydl_opts = { @@ -103,13 +112,30 @@ async def play_audio(interaction: discord.Interaction, query: str): async def play_next(interaction: discord.Interaction): guild_id = interaction.guild.id - if guild_id not in music_queues or not music_queues[guild_id]: - await interaction.followup.send("❌ **No songs in the queue.**") + if guild_id not in music_queues: + music_queues[guild_id] = [] + + # Handle Repeat One + if repeat_modes.get(guild_id) == "one" and current_tracks.get(guild_id): + song_url, title = current_tracks[guild_id] + music_queues[guild_id].insert(0, (song_url, title)) # Re-add the current song to the front of the queue + + # Handle Repeat All + elif repeat_modes.get(guild_id) == "all" and not music_queues[guild_id]: + # Move completed songs back to the queue + song_url, title = current_tracks.get(guild_id, (None, None)) + if song_url and title: + music_queues[guild_id].append((song_url, title)) + music_queues[guild_id].extend(current_tracks.values()) + + # Proceed to play the next song + if not music_queues[guild_id]: + await interaction.followup.send("❌ **No more songs in the queue.**") return voice_client = voice_clients[guild_id] song_url, title = music_queues[guild_id].pop(0) - current_tracks[guild_id] = title + current_tracks[guild_id] = (song_url, title) # Prepare FFmpeg options ffmpeg_options = { diff --git a/commands.py b/commands.py index 549b7c2..8ef03c6 100644 --- a/commands.py +++ b/commands.py @@ -1,6 +1,16 @@ import discord from discord import app_commands -from audio import play_audio, stop_audio, set_volume, join_voice, leave_voice, pause_audio, resume_audio, generate_recommendations +from audio import ( + play_audio, + stop_audio, + set_volume, + join_voice, + leave_voice, + pause_audio, + resume_audio, + repeat_modes, + generate_recommendations + ) async def setup_commands(client, guild_id=None): @@ -28,6 +38,18 @@ async def setup_commands(client, guild_id=None): async def resume(interaction: discord.Interaction): await resume_audio(interaction) + @client.tree.command(name="repeat", description="Set the repeat mode for playback.") + @app_commands.describe(mode="Repeat mode: 'one', 'all', or 'off'") + async def repeat(interaction: discord.Interaction, mode: str): + guild_id = interaction.guild.id + valid_modes = ["one", "all", "off"] + + if mode not in valid_modes: + await interaction.response.send_message(f"❌ **Invalid mode. Use one of: {', '.join(valid_modes)}.**") + return + + repeat_modes[guild_id] = mode + await interaction.response.send_message(f"🔄 **Repeat mode set to:** {mode.capitalize()}.") @client.tree.command(name="volume", description="Set playback volume.") async def volume(interaction: discord.Interaction, level: int):