diff options
Diffstat (limited to 'cogs/music')
| -rw-r--r-- | cogs/music/audio_playback.py | 55 | ||||
| -rw-r--r-- | cogs/music/play_commands.py | 4 |
2 files changed, 41 insertions, 18 deletions
diff --git a/cogs/music/audio_playback.py b/cogs/music/audio_playback.py index 1267fa7..28c6118 100644 --- a/cogs/music/audio_playback.py +++ b/cogs/music/audio_playback.py | |||
| @@ -60,17 +60,18 @@ class AudioPlaybackManager: | |||
| 60 | """Connect or move to voice channel. Returns voice client.""" | 60 | """Connect or move to voice channel. Returns voice client.""" |
| 61 | try: | 61 | try: |
| 62 | # Check if vc is valid and actually connected | 62 | # Check if vc is valid and actually connected |
| 63 | is_connected = vc is not None and vc.is_connected() | 63 | if vc is not None and vc.is_connected(): |
| 64 | # Connect to voice channel if not connected | 64 | # Already connected - check if need to move |
| 65 | if not is_connected: | 65 | if vc.channel != target_channel: |
| 66 | logger.info(f"Connecting to voice channel: {target_channel.name}") | 66 | logger.info(f"Moving to voice channel: {target_channel.name}") |
| 67 | vc = await target_channel.connect() | 67 | await vc.move_to(target_channel) |
| 68 | logger.info(f"Connected to voice channel: {target_channel.name}") | 68 | logger.info(f"Moved to voice channel: {target_channel.name}") |
| 69 | # Move to user's channel if in a different one | 69 | return vc |
| 70 | elif vc.channel != target_channel: | 70 | |
| 71 | logger.info(f"Moving to voice channel: {target_channel.name}") | 71 | # Not connected - connect now |
| 72 | await vc.move_to(target_channel) | 72 | logger.info(f"Connecting to voice channel: {target_channel.name}") |
| 73 | logger.info(f"Moved to voice channel: {target_channel.name}") | 73 | vc = await target_channel.connect() |
| 74 | logger.info(f"Connected to voice channel: {target_channel.name}") | ||
| 74 | return vc | 75 | return vc |
| 75 | except Exception as e: | 76 | except Exception as e: |
| 76 | logger.error(f"Error connecting to voice channel: {str(e)}") | 77 | logger.error(f"Error connecting to voice channel: {str(e)}") |
| @@ -138,15 +139,35 @@ class AudioPlaybackManager: | |||
| 138 | @staticmethod | 139 | @staticmethod |
| 139 | async def execute_playback(ctx, source, display_name, is_url): | 140 | async def execute_playback(ctx, source, display_name, is_url): |
| 140 | """Execute the actual audio playback.""" | 141 | """Execute the actual audio playback.""" |
| 141 | vc = ctx.voice_client | ||
| 142 | target_channel = await AudioPlaybackManager.validate_voice_channel(ctx) | 142 | target_channel = await AudioPlaybackManager.validate_voice_channel(ctx) |
| 143 | if not target_channel: | 143 | if not target_channel: |
| 144 | return False | 144 | return False |
| 145 | 145 | ||
| 146 | # Get existing voice client from bot or connect | ||
| 147 | guild = ctx.guild | ||
| 148 | vc = discord.utils.get(ctx.bot.voice_clients, guild=guild) | ||
| 149 | |||
| 146 | try: | 150 | try: |
| 147 | vc = await AudioPlaybackManager.connect_to_voice_channel( | 151 | # Handle various connection states |
| 148 | ctx, vc, target_channel | 152 | if vc is None: |
| 149 | ) | 153 | logger.info("No existing voice client, connecting...") |
| 154 | try: | ||
| 155 | vc = await target_channel.connect() | ||
| 156 | except discord.ClientException: | ||
| 157 | vc = discord.utils.get(ctx.bot.voice_clients, guild=guild) | ||
| 158 | elif not vc.is_connected(): | ||
| 159 | logger.info("Voice client exists but disconnected, reconnecting...") | ||
| 160 | try: | ||
| 161 | await vc.disconnect() | ||
| 162 | except Exception: | ||
| 163 | pass | ||
| 164 | try: | ||
| 165 | vc = await target_channel.connect() | ||
| 166 | except discord.ClientException: | ||
| 167 | vc = discord.utils.get(ctx.bot.voice_clients, guild=guild) | ||
| 168 | elif vc.channel != target_channel: | ||
| 169 | logger.info(f"Moving to voice channel: {target_channel.name}") | ||
| 170 | await vc.move_to(target_channel) | ||
| 150 | 171 | ||
| 151 | # Stop any currently playing audio | 172 | # Stop any currently playing audio |
| 152 | if vc.is_playing() or vc.is_paused(): # type: ignore[union-attr] | 173 | if vc.is_playing() or vc.is_paused(): # type: ignore[union-attr] |
| @@ -171,7 +192,7 @@ class AudioPlaybackManager: | |||
| 171 | # Play the audio | 192 | # Play the audio |
| 172 | vc.play(audio_source, after=after_playing) | 193 | vc.play(audio_source, after=after_playing) |
| 173 | logger.info(f"Playing: {final_display_name}") | 194 | logger.info(f"Playing: {final_display_name}") |
| 174 | await ctx.respond(f"grom: {final_display_name}") | 195 | await ctx.followup.send(f"grom: {final_display_name}") |
| 175 | 196 | ||
| 176 | # Wait for FFmpeg to attempt connection - errors usually happen within 5 seconds | 197 | # Wait for FFmpeg to attempt connection - errors usually happen within 5 seconds |
| 177 | await asyncio.sleep(5) | 198 | await asyncio.sleep(5) |
| @@ -195,7 +216,7 @@ class AudioPlaybackManager: | |||
| 195 | 216 | ||
| 196 | except Exception as e: | 217 | except Exception as e: |
| 197 | logger.error(f"Error in play: {str(e)}", exc_info=True) | 218 | logger.error(f"Error in play: {str(e)}", exc_info=True) |
| 198 | await ctx.respond(f"eror: {str(e)}", ephemeral=True) | 219 | await ctx.followup.send(f"eror: {str(e)}", ephemeral=True) |
| 199 | return False | 220 | return False |
| 200 | 221 | ||
| 201 | @staticmethod | 222 | @staticmethod |
diff --git a/cogs/music/play_commands.py b/cogs/music/play_commands.py index fd5113a..a82fa9d 100644 --- a/cogs/music/play_commands.py +++ b/cogs/music/play_commands.py | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | import logging | 6 | import logging |
| 7 | import os | 7 | import os |
| 8 | import urllib.parse | 8 | import urllib.parse |
| 9 | import asyncio | ||
| 9 | from os import PathLike | 10 | from os import PathLike |
| 10 | from typing import Awaitable, Callable, List, Tuple | 11 | from typing import Awaitable, Callable, List, Tuple |
| 11 | 12 | ||
| @@ -139,9 +140,10 @@ class PlayCommands(commands.Cog): | |||
| 139 | local_path = os.path.join(self.temp_dir, filename) | 140 | local_path = os.path.join(self.temp_dir, filename) |
| 140 | os.makedirs(self.temp_dir, exist_ok=True) | 141 | os.makedirs(self.temp_dir, exist_ok=True) |
| 141 | 142 | ||
| 143 | loop = asyncio.get_event_loop() | ||
| 142 | with open(local_path, "wb") as f: | 144 | with open(local_path, "wb") as f: |
| 143 | async for chunk in response.content.iter_chunked(8192): | 145 | async for chunk in response.content.iter_chunked(8192): |
| 144 | f.write(chunk) | 146 | await loop.run_in_executor(None, f.write, chunk) |
| 145 | 147 | ||
| 146 | compressed_path = await media_processing.AudioCompressor.compress( | 148 | compressed_path = await media_processing.AudioCompressor.compress( |
| 147 | ctx, local_path | 149 | ctx, local_path |
