diff --git a/audio.py b/audio.py index be4a9b7..2de8546 100644 --- a/audio.py +++ b/audio.py @@ -65,19 +65,18 @@ async def join_voice(interaction: discord.Interaction): async def play_audio(interaction: discord.Interaction, query: str): guild_id = interaction.guild.id + # Defer the response if not already done + if not interaction.response.is_done(): + await interaction.response.defer() + # 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] - # Defer response if not already done - if not interaction.response.is_done(): - await interaction.response.defer() - # Search for the song on YouTube ydl_opts = { 'format': 'bestaudio/best', @@ -87,7 +86,7 @@ async def play_audio(interaction: discord.Interaction, query: str): try: info = ydl.extract_info(f"ytsearch:{query}", download=False)['entries'][0] except Exception as e: - await interaction.followup.send(f"Failed to find or play the requested audio. Error: {str(e)}") + await interaction.followup.send(f"❌ **Error:** Could not find or play the requested audio. {str(e)}") return song_url = info['url'] @@ -108,6 +107,15 @@ async def play_audio(interaction: discord.Interaction, query: str): if not voice_client.is_playing(): await play_next(interaction) + # Send "Now Playing" embed with controls + embed = discord.Embed( + title="🎡 Now Playing", + description=f"**{title}** by {artist}", + color=discord.Color.blue() + ) + view = PlaybackControls(interaction, guild_id) + await interaction.followup.send(embed=embed, view=view) + async def play_next(interaction: discord.Interaction): guild_id = interaction.guild.id @@ -232,6 +240,101 @@ async def leave_voice(interaction: discord.Interaction): await interaction.response.send_message("❌ **I am not connected to any voice channel.**") +# ---------- Discord UI ---------- + + +class PlaybackControls(discord.ui.View): + def __init__(self, interaction, guild_id): + super().__init__(timeout=None) # Persistent buttons + self.interaction = interaction + self.guild_id = guild_id + + @discord.ui.button(label="⏸️ Pause", style=discord.ButtonStyle.primary) + async def pause_button(self, interaction: discord.Interaction, button: discord.ui.Button): + if self.guild_id in voice_clients and voice_clients[self.guild_id].is_playing(): + voice_clients[self.guild_id].pause() + button.label = "▢️ Resume" + await interaction.response.edit_message(content="⏸️ **Paused playback.**", view=self) + elif self.guild_id in voice_clients and voice_clients[self.guild_id].is_paused(): + voice_clients[self.guild_id].resume() + button.label = "⏸️ Pause" + await interaction.response.edit_message(content="▢️ **Resumed playback.**", view=self) + + @discord.ui.button(label="⏭️ Skip", style=discord.ButtonStyle.secondary) + async def skip_button(self, interaction: discord.Interaction, button: discord.ui.Button): + if self.guild_id in voice_clients and voice_clients[self.guild_id].is_playing(): + voice_clients[self.guild_id].stop() # Stop triggers `play_next` + await interaction.response.send_message("⏭️ **Skipped to the next song.**", ephemeral=True) + else: + await interaction.response.send_message("❌ **No song is currently playing to skip.**", ephemeral=True) + + @discord.ui.button(label="πŸ›‘ Stop", style=discord.ButtonStyle.danger) + async def stop_button(self, interaction: discord.Interaction, button: discord.ui.Button): + if self.guild_id in voice_clients and voice_clients[self.guild_id].is_playing(): + voice_clients[self.guild_id].stop() + music_queues[self.guild_id] = [] # Clear the queue + await interaction.response.send_message("πŸ›‘ **Stopped playback and cleared the queue.**", ephemeral=True) + else: + await interaction.response.send_message("❌ **No song is currently playing to stop.**", ephemeral=True) + + @discord.ui.button(label="πŸ”„ Repeat: Off", style=discord.ButtonStyle.success) + async def repeat_button(self, interaction: discord.Interaction, button: discord.ui.Button): + current_mode = repeat_modes.get(self.guild_id, "off") + new_mode = "one" if current_mode == "off" else "all" if current_mode == "one" else "off" + repeat_modes[self.guild_id] = new_mode + button.label = f"πŸ”„ Repeat: {new_mode.capitalize()}" + await interaction.response.edit_message(content=f"πŸ”„ **Repeat mode set to:** {new_mode.capitalize()}", view=self) + + @discord.ui.button(label="πŸ”ˆ Volume Down", style=discord.ButtonStyle.secondary) + async def volume_down(self, interaction: discord.Interaction, button: discord.ui.Button): + current_volume = volumes.get(self.guild_id, default_volume) + new_volume = max(0.0, current_volume - 0.1) # Decrease volume by 10% + volumes[self.guild_id] = new_volume + + # Apply volume to the current source + if self.guild_id in voice_clients and voice_clients[self.guild_id].is_playing(): + source = voice_clients[self.guild_id].source + if isinstance(source, discord.PCMVolumeTransformer): + source.volume = new_volume + + await interaction.response.send_message(f"πŸ”ˆ **Volume decreased to {int(new_volume * 100)}%.**", ephemeral=True) + + @discord.ui.button(label="πŸ”Š Volume Up", style=discord.ButtonStyle.primary) + async def volume_up(self, interaction: discord.Interaction, button: discord.ui.Button): + current_volume = volumes.get(self.guild_id, default_volume) + new_volume = min(1.0, current_volume + 0.1) # Increase volume by 10% + volumes[self.guild_id] = new_volume + + # Apply volume to the current source + if self.guild_id in voice_clients and voice_clients[self.guild_id].is_playing(): + source = voice_clients[self.guild_id].source + if isinstance(source, discord.PCMVolumeTransformer): + source.volume = new_volume + + await interaction.response.send_message(f"πŸ”Š **Volume increased to {int(new_volume * 100)}%.**", ephemeral=True) + + @discord.ui.button(label="πŸ”‡ Mute/Unmute", style=discord.ButtonStyle.danger) + async def mute_toggle(self, interaction: discord.Interaction, button: discord.ui.Button): + current_volume = volumes.get(self.guild_id, default_volume) + + # Toggle mute + if current_volume > 0: + volumes[self.guild_id] = 0.0 + button.label = "πŸ”Š Unmute" + else: + volumes[self.guild_id] = default_volume + button.label = "πŸ”‡ Mute" + + # Apply volume to the current source + if self.guild_id in voice_clients and voice_clients[self.guild_id].is_playing(): + source = voice_clients[self.guild_id].source + if isinstance(source, discord.PCMVolumeTransformer): + source.volume = volumes[self.guild_id] + + status = "muted" if volumes[self.guild_id] == 0.0 else "unmuted" + await interaction.response.edit_message(content=f"πŸ”‡ **Volume {status}.**", view=self) + + # ---------- Recommendations ---------- def fetch_related_songs(song_title, artist): """