"""Discord slash commands for MoltMic voice bot.""" from typing import Optional import discord from discord import app_commands from utils.logging import get_logger try: from discord.ext import voice_recv HAS_VOICE_RECV = True except ImportError: voice_recv = None HAS_VOICE_RECV = False logger = get_logger(__name__) class MoltMicCommands(app_commands.Group): """Slash commands for MoltMic voice bot.""" def __init__(self, bot): super().__init__(name="moltmic", description="MoltMic voice commands") self.bot = bot @app_commands.command(name="join", description="Join your voice channel and start listening") @app_commands.describe(channel="Voice channel to join (defaults to your current channel)") async def join(self, interaction: discord.Interaction, channel: Optional[discord.VoiceChannel] = None): await interaction.response.defer(thinking=True) try: target = channel or (interaction.user.voice and interaction.user.voice.channel) if not target: await interaction.followup.send("❌ You're not in a voice channel.", ephemeral=True) return # Already in this channel? if interaction.guild.voice_client and interaction.guild.voice_client.channel.id == target.id: await interaction.followup.send(f"Already in {target.mention}", ephemeral=True) return # Move or connect if interaction.guild.voice_client: await interaction.guild.voice_client.move_to(target) voice_client = interaction.guild.voice_client else: connect_cls = voice_recv.VoiceRecvClient if HAS_VOICE_RECV else discord.VoiceClient voice_client = await target.connect(cls=connect_cls, self_deaf=False, timeout=60.0) await self.bot.on_voice_join(interaction.guild, target, voice_client) await interaction.followup.send(f"🎙️ Joined {target.mention} and listening...") except discord.errors.ClientException as e: logger.error(f"Failed to join: {e}") await interaction.followup.send(f"❌ Failed to join: {e}", ephemeral=True) except Exception as e: logger.exception(f"Join error: {e}") await interaction.followup.send("❌ Unexpected error", ephemeral=True) @app_commands.command(name="leave", description="Leave the voice channel") async def leave(self, interaction: discord.Interaction): await interaction.response.defer(thinking=True) try: if not interaction.guild.voice_client: await interaction.followup.send("❌ Not in a voice channel.", ephemeral=True) return await self.bot.on_voice_leave(interaction.guild) await interaction.followup.send("👋 Left voice channel.") except Exception as e: logger.exception(f"Leave error: {e}") await interaction.followup.send("❌ Error leaving.", ephemeral=True) @app_commands.command(name="status", description="Show bot status") async def status(self, interaction: discord.Interaction): await interaction.response.defer(thinking=True) try: session = self.bot.session_manager.get_session(interaction.guild.id) if not session: await interaction.followup.send("❌ Not in a voice channel.", ephemeral=True) return embed = discord.Embed(title="🎙️ MoltMic Status", color=discord.Color.green()) embed.add_field(name="Channel", value=f"<#{session.channel_id}>", inline=True) embed.add_field(name="Duration", value=f"{session.duration:.0f}s", inline=True) embed.add_field(name="Users", value=str(session.get_user_count()), inline=True) await interaction.followup.send(embed=embed) except Exception as e: logger.exception(f"Status error: {e}") await interaction.followup.send("❌ Error.", ephemeral=True) async def setup_commands(bot): """Register slash commands.""" cmds = MoltMicCommands(bot) bot.tree.add_command(cmds) logger.info("Slash commands registered (moltmic: join, leave, status)") return cmds