Enhance YouTube video download functionality with improved error handling and format options. Update Docker configuration to use environment variable for port and simplify network settings.

This commit is contained in:
vrubel 2025-12-24 22:41:20 +03:00
parent 2d248b9ce0
commit 88d753b84a
4 changed files with 109 additions and 66 deletions

View file

@ -66,14 +66,17 @@ def download_youtube_video(url: str, max_retries: int = 3) -> Path:
is_shorts = '/shorts/' in url
# Базовые настройки для получения информации
# Для Shorts используем более надежные клиенты
player_clients = ['android', 'ios', 'web'] if is_shorts else ['android', 'web']
ydl_opts_info = {
'quiet': False,
'no_warnings': False,
'user_agent': user_agent,
'socket_timeout': 60, # Увеличиваем таймаут
'socket_timeout': 60,
'extractor_args': {
'youtube': {
'player_client': ['android', 'web'] if not is_shorts else ['android', 'ios', 'web'],
'player_client': player_clients,
'player_skip': ['webpage'],
},
},
@ -93,41 +96,97 @@ def download_youtube_video(url: str, max_retries: int = 3) -> Path:
else:
logger.info(f"YouTube: работаем без cookies (попытка {attempt + 1})")
with yt_dlp.YoutubeDL(ydl_opts_info) as ydl:
info = ydl.extract_info(url, download=False)
video_title = info.get('title', 'video')
logger.info(f"YouTube: получена информация о видео: {video_title}")
# Пробуем получить информацию о видео
info = None
try:
with yt_dlp.YoutubeDL(ydl_opts_info) as ydl:
info = ydl.extract_info(url, download=False)
except Exception as info_error:
# Если не получилось с cookies, пробуем без них
if cookies_valid and ('cookies' in str(info_error).lower() or 'bot' in str(info_error).lower()):
logger.warning("YouTube: не удалось получить информацию с cookies, пробуем без них")
ydl_opts_info.pop('cookiefile', None)
with yt_dlp.YoutubeDL(ydl_opts_info) as ydl:
info = ydl.extract_info(url, download=False)
cookies_valid = False # Отключаем cookies для скачивания тоже
else:
raise
# Настройки для скачивания
ydl_opts_download = {
'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best',
'outtmpl': _safe_filename(video_title),
'quiet': False,
'no_warnings': False,
'user_agent': user_agent,
'socket_timeout': 60, # Увеличиваем таймаут
'extractor_args': {
'youtube': {
'player_client': ['android', 'web'] if not is_shorts else ['android', 'ios', 'web'],
'player_skip': ['webpage'],
video_title = info.get('title', 'video') if info else 'video'
logger.info(f"YouTube: получена информация о видео: {video_title}")
# Настройки для скачивания с более гибким форматом
# Пробуем разные варианты форматов, если один не работает
format_options = [
'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best', # Предпочтительный
'best[ext=mp4]/best', # Простой fallback
'bestvideo+bestaudio/best', # Без ограничения по расширению
'best', # Самый простой вариант
]
download_success = False
for format_option in format_options:
ydl_opts_download = {
'format': format_option,
'outtmpl': _safe_filename(video_title),
'quiet': False,
'no_warnings': False,
'user_agent': user_agent,
'socket_timeout': 60,
'extractor_args': {
'youtube': {
'player_client': ['android', 'ios', 'web'] if is_shorts else ['android', 'web'],
'player_skip': ['webpage'],
},
},
},
'http_headers': {
'User-Agent': user_agent,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-us,en;q=0.5',
'Accept-Encoding': 'gzip, deflate',
'Connection': 'keep-alive',
},
}
'http_headers': {
'User-Agent': user_agent,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-us,en;q=0.5',
'Accept-Encoding': 'gzip, deflate',
'Connection': 'keep-alive',
},
}
# Если есть валидный файл с cookies, используем его для скачивания
use_cookies_this_attempt = cookies_valid
if use_cookies_this_attempt:
ydl_opts_download['cookiefile'] = str(cookies_file_path.absolute())
logger.info(f"YouTube: начинаем скачивание (попытка {attempt + 1}/{max_retries}, Shorts: {is_shorts}, формат: {format_option}, cookies: {use_cookies_this_attempt})")
try:
with yt_dlp.YoutubeDL(ydl_opts_download) as ydl:
ydl.download([url])
download_success = True
break
except Exception as download_error:
error_str = str(download_error)
# Если ошибка с cookies, пробуем без них
if use_cookies_this_attempt and ('cookies' in error_str.lower() or 'bot' in error_str.lower() or 'sign in' in error_str.lower()):
logger.warning(f"YouTube: ошибка с cookies для формата {format_option}, пробуем без cookies...")
ydl_opts_download.pop('cookiefile', None)
try:
with yt_dlp.YoutubeDL(ydl_opts_download) as ydl:
ydl.download([url])
download_success = True
cookies_valid = False # Отключаем cookies для следующих попыток
break
except Exception:
# Если и без cookies не получилось, пробуем следующий формат
logger.warning(f"YouTube: не удалось скачать без cookies, пробуем следующий формат...")
continue
# Если ошибка формата, пробуем следующий формат
elif 'format is not available' in error_str.lower() or 'requested format' in error_str.lower():
logger.warning(f"YouTube: формат {format_option} недоступен, пробуем следующий...")
continue
else:
# Другая ошибка - пробуем следующий формат
logger.warning(f"YouTube: ошибка при скачивании формата {format_option}: {error_str[:100]}, пробуем следующий...")
continue
# Если есть валидный файл с cookies, используем его для скачивания
if cookies_valid:
ydl_opts_download['cookiefile'] = str(cookies_file_path.absolute())
logger.info(f"YouTube: начинаем скачивание (попытка {attempt + 1}/{max_retries}, Shorts: {is_shorts})")
with yt_dlp.YoutubeDL(ydl_opts_download) as ydl:
ydl.download([url])
if not download_success:
raise Exception("Не удалось скачать видео ни с одним из доступных форматов")
# Находим скачанный файл
downloaded_files = list(DOWNLOADS_DIR.glob('*'))
@ -142,6 +201,15 @@ def download_youtube_video(url: str, max_retries: int = 3) -> Path:
error_str = str(e)
logger.warning(f"YouTube: попытка {attempt + 1}/{max_retries} не удалась: {error_str}")
# Если ошибка связана с форматом, пробуем другие настройки
if 'format is not available' in error_str.lower() or 'requested format' in error_str.lower():
logger.warning("YouTube: проблема с форматом, пробуем другие настройки на следующей попытке")
# На следующей попытке попробуем другие player_client
if attempt < max_retries - 1:
import time
time.sleep((attempt + 1) * 2)
continue
# Если ошибка связана с cookies и они были использованы, попробуем без cookies на следующей попытке
if 'cookies' in error_str.lower() or 'bot' in error_str.lower() or 'sign in' in error_str.lower():
if cookies_valid and attempt == 0: