# This file is part of Senator Sperma # Licensed under the GPL-3.0 License # Copyright (C) 2026 Salmonik @ salmonik@tuta.io # https://codeberg.org/salmonik/senator-sperma import discord from discord.ext import commands import logging import asyncio logger = logging.getLogger(__name__) class Voice(commands.Cog): def __init__(self, bot): self.bot = bot async def _validate_user_voice_state(self, ctx): """Validate that user is in a voice channel.""" if not ctx.author.voice or not ctx.author.voice.channel: await ctx.send("You need to be in a voice channel first!") return False return True async def _create_voice_client(self, ctx): """Create a new voice client connection.""" try: voice_client = await ctx.author.voice.channel.connect(timeout=30.0, reconnect=True) logger.info(f"Connected to voice channel: {ctx.author.voice.channel}") return voice_client except asyncio.TimeoutError: await ctx.send("Connection to voice channel timed out.") return None except discord.ClientException as e: logger.error(f"Failed to connect to voice channel: {e}") await ctx.send("Failed to connect to voice channel. Please try again.", ephemeral=True) return None async def _move_voice_client(self, voice_client, ctx): """Move existing voice client to user's channel.""" try: await voice_client.move_to(ctx.author.voice.channel) logger.info(f"Moved to voice channel: {ctx.author.voice.channel}") return voice_client except asyncio.TimeoutError: await ctx.send("Connection to voice channel timed out.") return None except discord.ClientException as e: logger.error(f"Failed to move to voice channel: {e}") await ctx.send("Failed to move to your voice channel. Please try again.", ephemeral=True) return None async def _verify_connection(self, voice_client): """Verify and repair voice client connection if needed.""" if not voice_client.is_connected(): try: await voice_client.connect(reconnect=True, timeout=10.0) return voice_client except Exception as e: logger.error(f"Failed to reconnect to voice: {e}") return None return voice_client async def ensure_voice_client(self, ctx): """Ensure we have a valid voice client connection.""" if not await self._validate_user_voice_state(ctx): return None voice_client = discord.utils.get(self.bot.voice_clients, guild=ctx.guild) # If no voice client exists, create one if not voice_client or not voice_client.is_connected(): return await self._create_voice_client(ctx) # If we're in a different channel, move to the user's channel if voice_client.channel != ctx.author.voice.channel: return await self._move_voice_client(voice_client, ctx) # Verify the connection is healthy return await self._verify_connection(voice_client) async def connect(self, ctx): """Connect to the user's voice channel with improved connection handling.""" voice_client = await self.ensure_voice_client(ctx) if not voice_client: return None return voice_client def setup(bot): bot.add_cog(Voice(bot))