From 5dac739e17471f8099e5f22a43492b56c7dbe152 Mon Sep 17 00:00:00 2001 From: vrubel Date: Wed, 28 Jan 2026 18:20:25 +0300 Subject: [PATCH] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=812?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/youtube_downloader.py | 129 ++++++++++++++++++++++---------------- 1 file changed, 75 insertions(+), 54 deletions(-) diff --git a/app/youtube_downloader.py b/app/youtube_downloader.py index 5a694d5..988bbc7 100644 --- a/app/youtube_downloader.py +++ b/app/youtube_downloader.py @@ -187,66 +187,87 @@ async def download_and_convert( temp_template = output_path.parent / f"temp_{output_path.name}.%(ext)s" try: - cmd = [ - 'yt-dlp', - '-x', # Извлечь аудио - '-f', 'bestaudio[ext=m4a]/bestaudio[ext=webm]/bestaudio/best', - '--hls-prefer-ffmpeg', - '--audio-format', 'mp3', - '--audio-quality', '0', # Лучшее качество - '-o', str(temp_template), - '--no-warnings', - '--progress', - '--newline', - '--no-playlist', - url + formats_to_try = [ + 'bestaudio[ext=m4a]/bestaudio[ext=webm]/bestaudio/best', + 'bestaudio/best', ] - if config: - if config.ytdlp_user_agent: - cmd.extend(['--user-agent', config.ytdlp_user_agent]) - if config.ytdlp_cookies_file: - cmd.extend(['--cookies', config.ytdlp_cookies_file]) - if config.ytdlp_player_client: - cmd.extend(['--extractor-args', f'youtube:player_client={config.ytdlp_player_client}']) - if config.ytdlp_force_ipv4: - cmd.append('--force-ipv4') - - logger.info(f"Downloading {url}") - - process = await asyncio.create_subprocess_exec( - *cmd, - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE - ) - stderr_tail = deque(maxlen=12) - stdout_tail = deque(maxlen=12) + async def _run_yt_dlp(format_selector: str): + cmd = [ + 'yt-dlp', + '-x', # Извлечь аудио + '-f', format_selector, + '--hls-prefer-ffmpeg', + '--audio-format', 'mp3', + '--audio-quality', '0', # Лучшее качество + '-o', str(temp_template), + '--no-warnings', + '--progress', + '--newline', + '--no-playlist', + url + ] + if config: + if config.ytdlp_user_agent: + cmd.extend(['--user-agent', config.ytdlp_user_agent]) + if config.ytdlp_cookies_file: + cmd.extend(['--cookies', config.ytdlp_cookies_file]) + if config.ytdlp_player_client: + cmd.extend(['--extractor-args', f'youtube:player_client={config.ytdlp_player_client}']) + if config.ytdlp_force_ipv4: + cmd.append('--force-ipv4') - async def _log_stream(stream, level: str, tail: deque[str]): - while True: - line = await stream.readline() - if not line: - break - text = line.decode('utf-8', errors='ignore').strip() - if text: - tail.append(text) - if level == "info": - logger.info(f"yt-dlp: {text}") - else: - logger.warning(f"yt-dlp: {text}") + logger.info(f"Downloading {url} with format: {format_selector}") - stderr_task = asyncio.create_task(_log_stream(process.stderr, "warn", stderr_tail)) - stdout_task = asyncio.create_task(_log_stream(process.stdout, "info", stdout_tail)) + process = await asyncio.create_subprocess_exec( + *cmd, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE + ) - await process.wait() - await stderr_task - await stdout_task - - if process.returncode != 0: + stderr_tail = deque(maxlen=12) + stdout_tail = deque(maxlen=12) + + async def _log_stream(stream, level: str, tail: deque[str]): + while True: + line = await stream.readline() + if not line: + break + text = line.decode('utf-8', errors='ignore').strip() + if text: + tail.append(text) + if level == "info": + logger.info(f"yt-dlp: {text}") + else: + logger.warning(f"yt-dlp: {text}") + + stderr_task = asyncio.create_task(_log_stream(process.stderr, "warn", stderr_tail)) + stdout_task = asyncio.create_task(_log_stream(process.stdout, "info", stdout_tail)) + + await process.wait() + await stderr_task + await stdout_task + return process.returncode, list(stderr_tail) + list(stdout_tail) + + last_tail: list[str] = [] + for fmt in formats_to_try: + returncode, tail_lines = await _run_yt_dlp(fmt) + last_tail = tail_lines + if returncode == 0: + break + tail_text = "\n".join(tail_lines[-12:]) if tail_lines else "" + if "Requested format is not available" in tail_text: + logger.warning("yt-dlp format unavailable, retrying with fallback") + continue logger.error("yt-dlp failed") - tail_lines = list(stderr_tail) + list(stdout_tail) - if tail_lines: - tail_text = "\n".join(tail_lines[-12:]) + if tail_text: + raise Exception(f"Ошибка скачивания: yt-dlp завершился с ошибкой\n{tail_text}") + raise Exception("Ошибка скачивания: yt-dlp завершился с ошибкой") + + if returncode != 0: + logger.error("yt-dlp failed") + if last_tail: + tail_text = "\n".join(last_tail[-12:]) raise Exception(f"Ошибка скачивания: yt-dlp завершился с ошибкой\n{tail_text}") raise Exception("Ошибка скачивания: yt-dlp завершился с ошибкой")