aboutsummaryrefslogtreecommitdiffstats
path: root/cogs/music/play_utils.py
diff options
context:
space:
mode:
authorsalmonik <raisersoft@proton.me>2026-01-13 16:37:53 +0100
committersalmonik <raisersoft@proton.me>2026-01-13 16:37:53 +0100
commit260c3acf932719f621bd47aea59a3593cbfb629c (patch)
tree668eded18764ef5597289731cb8650ffbaf327dc /cogs/music/play_utils.py
parentbump libs (diff)
downloadsenator-sperma-260c3acf932719f621bd47aea59a3593cbfb629c.tar.gz
senator-sperma-260c3acf932719f621bd47aea59a3593cbfb629c.zip
add support for internet streams for playing
Diffstat (limited to '')
-rw-r--r--cogs/music/play_utils.py95
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)