diff options
| author | salmonik <raisersoft@proton.me> | 2026-01-13 16:37:53 +0100 |
|---|---|---|
| committer | salmonik <raisersoft@proton.me> | 2026-01-13 16:37:53 +0100 |
| commit | 260c3acf932719f621bd47aea59a3593cbfb629c (patch) | |
| tree | 668eded18764ef5597289731cb8650ffbaf327dc /cogs/music/play_utils.py | |
| parent | bump libs (diff) | |
| download | senator-sperma-260c3acf932719f621bd47aea59a3593cbfb629c.tar.gz senator-sperma-260c3acf932719f621bd47aea59a3593cbfb629c.zip | |
add support for internet streams for playing
Diffstat (limited to 'cogs/music/play_utils.py')
| -rw-r--r-- | cogs/music/play_utils.py | 95 |
1 files changed, 59 insertions, 36 deletions
diff --git a/cogs/music/play_utils.py b/cogs/music/play_utils.py index 8de7543..0614157 100644 --- a/cogs/music/play_utils.py +++ b/cogs/music/play_utils.py | |||
| @@ -226,34 +226,49 @@ class PlayUtils: | |||
| 226 | return None | 226 | return None |
| 227 | 227 | ||
| 228 | @staticmethod | 228 | @staticmethod |
| 229 | async def play(ctx, filepath, delete_after_play=False): | 229 | async def play(ctx, source, delete_after_play=False): |
| 230 | """Play audio from a local file or URL. | ||
| 231 | |||
| 232 | Args: | ||
| 233 | ctx: Discord context | ||
| 234 | source: Either a local file path or a URL to stream from | ||
| 235 | delete_after_play: If True, delete the file after playing (only for local files) | ||
| 236 | """ | ||
| 230 | # Check if user is in a voice channel | 237 | # Check if user is in a voice channel |
| 231 | if not ctx.author.voice or not ctx.author.voice.channel: | 238 | if not ctx.author.voice or not ctx.author.voice.channel: |
| 232 | await ctx.respond("Musisz być na kanale głosowym, żebym mógł dołączyć!", ephemeral=True) | 239 | await ctx.respond("Musisz być na kanale głosowym, żebym mógł dołączyć!", ephemeral=True) |
| 233 | if delete_after_play and os.path.exists(filepath): | 240 | if delete_after_play and os.path.exists(source): |
| 234 | try: | 241 | try: |
| 235 | os.remove(filepath) | 242 | os.remove(source) |
| 236 | logger.info(f"Cleaned up temporary file: {filepath}") | 243 | logger.info(f"Cleaned up temporary file: {source}") |
| 237 | except Exception as e: | 244 | except Exception as e: |
| 238 | logger.error(f"Error cleaning up file {filepath}: {str(e)}") | 245 | logger.error(f"Error cleaning up file {source}: {str(e)}") |
| 239 | return | 246 | return |
| 240 | 247 | ||
| 241 | logger.info(f"Attempting to play: {filepath}") | 248 | is_url = source.startswith(('http://', 'https://')) |
| 242 | |||
| 243 | # Get absolute path and verify file exists | ||
| 244 | if not os.path.isabs(filepath): | ||
| 245 | filepath = os.path.abspath(filepath) | ||
| 246 | logger.debug(f"Converted to absolute path: {filepath}") | ||
| 247 | 249 | ||
| 248 | if not os.path.exists(filepath): | 250 | if not is_url: |
| 249 | error_msg = f"File not found: {filepath}" | 251 | # Handle local file |
| 250 | logger.error(error_msg) | 252 | logger.info(f"Attempting to play local file: {source}") |
| 251 | await ctx.respond("Nie znaleziono pliku do odtworzenia", ephemeral=True) | ||
| 252 | return | ||
| 253 | 253 | ||
| 254 | filename = os.path.basename(filepath) | 254 | # Get absolute path and verify file exists |
| 255 | logger.info(f"Playing file: {filename} (from: {filepath})") | 255 | if not os.path.isabs(source): |
| 256 | 256 | source = os.path.abspath(source) | |
| 257 | logger.debug(f"Converted to absolute path: {source}") | ||
| 258 | |||
| 259 | if not os.path.exists(source): | ||
| 260 | error_msg = f"File not found: {source}" | ||
| 261 | logger.error(error_msg) | ||
| 262 | await ctx.respond("Nie znaleziono pliku do odtworzenia", ephemeral=True) | ||
| 263 | return | ||
| 264 | |||
| 265 | filename = os.path.basename(source) | ||
| 266 | display_name = os.path.splitext(filename)[0] | ||
| 267 | else: | ||
| 268 | # Handle URL | ||
| 269 | logger.info(f"Attempting to play stream from URL: {source}") | ||
| 270 | display_name = source # Use URL as display name for streams | ||
| 271 | |||
| 257 | # Get or create voice client | 272 | # Get or create voice client |
| 258 | vc = ctx.voice_client | 273 | vc = ctx.voice_client |
| 259 | target_channel = ctx.author.voice.channel | 274 | target_channel = ctx.author.voice.channel |
| @@ -275,23 +290,31 @@ class PlayUtils: | |||
| 275 | vc.stop() | 290 | vc.stop() |
| 276 | 291 | ||
| 277 | # Play the audio | 292 | # Play the audio |
| 278 | source = discord.FFmpegPCMAudio(source=filepath) | 293 | if is_url: |
| 279 | vc.play(source) | 294 | # For URLs, use FFmpeg with the direct URL |
| 280 | 295 | ffmpeg_options = { | |
| 281 | try: | 296 | 'options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', |
| 282 | metadata = mutagen.File(filepath) | 297 | 'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5' |
| 283 | title = metadata.get('title', None) | 298 | } |
| 284 | logger.debug(f"Read metadata - title: {title}") | 299 | source = discord.FFmpegPCMAudio(source, **ffmpeg_options) |
| 285 | except Exception as e: | 300 | else: |
| 286 | logger.warning(f"Could not read metadata from {filepath}: {str(e)}") | 301 | # For local files, use default options |
| 287 | title = None | 302 | source = discord.FFmpegPCMAudio(source=source) |
| 288 | 303 | ||
| 289 | if title is None: | 304 | # Try to get metadata for local files |
| 290 | title = os.path.splitext(os.path.basename(filepath))[0] | 305 | try: |
| 291 | logger.debug(f"Using filename as title: {title}") | 306 | metadata = mutagen.File(source) |
| 307 | if metadata: | ||
| 308 | title = metadata.get('title', [None])[0] if hasattr(metadata, 'get') else None | ||
| 309 | if title: | ||
| 310 | display_name = title | ||
| 311 | logger.debug(f"Read metadata - title: {title}") | ||
| 312 | except Exception as e: | ||
| 313 | logger.warning(f"Could not read metadata from {source}: {str(e)}") | ||
| 292 | 314 | ||
| 293 | logger.info(f"Playing file: {title}") | 315 | vc.play(source) |
| 294 | await ctx.respond(f"grom: {title}") | 316 | logger.info(f"Playing: {display_name}") |
| 317 | await ctx.respond(f"grom: {display_name}") | ||
| 295 | 318 | ||
| 296 | except Exception as e: | 319 | except Exception as e: |
| 297 | logger.error(f"Error in play: {str(e)}", exc_info=True) | 320 | logger.error(f"Error in play: {str(e)}", exc_info=True) |
