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:
parent
2d248b9ce0
commit
88d753b84a
4 changed files with 109 additions and 66 deletions
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue