diff --git a/bot/modules/media_loader/ytdlp.py b/bot/modules/media_loader/ytdlp.py index 00c3430..a3be3df 100644 --- a/bot/modules/media_loader/ytdlp.py +++ b/bot/modules/media_loader/ytdlp.py @@ -299,14 +299,11 @@ async def download_media( 'merge_output_format': 'mp4', # FFmpeg options for merging to ensure compatibility # Copy streams when possible (no re-encoding), only encode if necessary - # Add proper metadata for mobile compatibility 'postprocessor_args': { 'ffmpeg': [ '-c:v', 'copy', '-c:a', 'aac', '-movflags', '+faststart', - '-aspect', 'auto', # Preserve aspect ratio - '-metadata:s:v:0', 'rotate=0', # Ensure no rotation metadata issues ] }, # Don't prefer free formats (they may be lower quality) @@ -317,18 +314,32 @@ async def download_media( 'ignoreerrors': False, } - # Check if Node.js is available for JS extraction (required for Instagram, TikTok, etc.) + # Check if Node.js is available for JS extraction (required for Instagram, TikTok, YouTube, etc.) import shutil nodejs_path = shutil.which('node') if nodejs_path: - logger.debug(f"Node.js found at: {nodejs_path}. JS extraction will be available.") + logger.info(f"Node.js found at: {nodejs_path}. JS extraction will be available.") # yt-dlp will automatically use Node.js if available - # Optionally, we can explicitly set it via extractor_args if needed + # For YouTube, we can explicitly set extractor args to use Node.js + # This helps avoid warnings about missing JS runtime + if 'youtube.com' in url or 'youtu.be' in url: + ydl_opts['extractor_args'] = { + 'youtube': { + 'player_client': ['android', 'web'], # Use clients that don't require JS + } + } else: logger.warning( - "Node.js not found. Some sites (Instagram, TikTok, etc.) may require JS extraction. " + "Node.js not found. Some sites (Instagram, TikTok, YouTube, etc.) may require JS extraction. " "Install Node.js for full functionality." ) + # For YouTube without Node.js, use extractor args to avoid warnings + if 'youtube.com' in url or 'youtu.be' in url: + ydl_opts['extractor_args'] = { + 'youtube': { + 'player_client': ['android', 'web'], # Use clients that don't require JS + } + } # Add cookies if specified (for Instagram and other sites) if cookies_file: @@ -390,7 +401,22 @@ async def download_media( raise KeyboardInterrupt("Download cancelled") # Download (progress hook will be called from this thread) - ydl.download([url]) + # Note: Some postprocessors may show errors (like FixupM3u8 with aspect ratio), + # but the video file is still downloaded correctly + try: + ydl.download([url]) + except Exception as postprocess_error: + # Check if it's just a postprocessing error (video is already downloaded) + error_msg = str(postprocess_error) + if "Postprocessing" in error_msg or "aspect ratio" in error_msg.lower(): + logger.warning( + f"Postprocessing error (non-critical): {error_msg}. " + f"Video file should still be available. Will check file existence." + ) + # Don't raise - video is likely already downloaded + else: + # Real error, re-raise + raise return info except KeyboardInterrupt: