fix: correct quality selection -- specific format_id first, exclude av01, validate video stream

This commit is contained in:
vrubelroman 2026-05-03 01:36:04 +03:00
parent 326eabaa99
commit 053f6c8afc
3 changed files with 139 additions and 33 deletions

33
bot.py
View file

@ -19,6 +19,13 @@ from typing import Optional
# Все таймауты убраны - видео может качаться и отправляться очень долго
HTTP_TIMEOUT = httpx.Timeout(connect=None, read=None, write=None, pool=None)
# Таймаут для запроса форматов (не такой критичный, но не должен висеть вечно)
FORMATS_TIMEOUT = httpx.Timeout(connect=15, read=30, write=15, pool=15)
# Клиентский кэш форматов: {normalized_url: (timestamp, formats)}
_formats_cache: dict[str, tuple[float, list[dict]]] = {}
_FORMATS_CACHE_TTL = 30 * 60 # 30 минут
# Настройка логирования
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
@ -963,11 +970,31 @@ async def download_tiktok_video(url: str, chat_id: int, max_retries: int = 3) ->
# ============================================================================
def _normalize_youtube_url_for_cache(url: str) -> str:
"""Нормализует URL для кэша: оставляет только video ID"""
import re
m = re.search(r'(youtu\.be/|youtube\.com/watch\?v=)([a-zA-Z0-9_-]{11})', url)
if m:
return f"https://www.youtube.com/watch?v={m.group(2)}"
return url
async def get_formats_from_service(url: str) -> list[dict] | None:
"""Получает список доступных форматов для YouTube URL через сервис youtube-downloader"""
logger.info(f"Получение форматов для YouTube: {url}")
cache_key = _normalize_youtube_url_for_cache(url)
now = time.time()
if cache_key in _formats_cache:
cached_time, cached_formats = _formats_cache[cache_key]
if now - cached_time < _FORMATS_CACHE_TTL:
logger.info(f"Форматы взяты из кэша ({len(cached_formats)} шт., возраст {now - cached_time:.0f}с)")
return cached_formats
del _formats_cache[cache_key]
try:
async with httpx.AsyncClient(timeout=HTTP_TIMEOUT) as client:
async with httpx.AsyncClient(timeout=FORMATS_TIMEOUT) as client:
response = await client.post(
f"{YOUTUBE_DOWNLOADER_URL}/formats",
json={"url": url},
@ -975,7 +1002,9 @@ async def get_formats_from_service(url: str) -> list[dict] | None:
)
if response.status_code == 200:
data = response.json()
return data.get('formats', [])
formats = data.get('formats', [])
_formats_cache[cache_key] = (time.time(), formats)
return formats
logger.warning(f"Не удалось получить форматы: {response.status_code}")
return None
except Exception as e: