88 lines
3.0 KiB
Python
88 lines
3.0 KiB
Python
from typing import Optional
|
||
from dataclasses import dataclass
|
||
|
||
|
||
@dataclass
|
||
class MediaContent:
|
||
url: str
|
||
headers: dict
|
||
chunk_size: int
|
||
|
||
|
||
class YtDlpInfo:
|
||
def __init__(self, url: str):
|
||
self.url = url
|
||
self.info = None
|
||
self._extract_info()
|
||
|
||
def _extract_info(self):
|
||
import yt_dlp
|
||
|
||
ydl_opts = {
|
||
"quiet": True,
|
||
"skip_download": True,
|
||
"noplaylist": True,
|
||
"js-runtimes": "deno",
|
||
}
|
||
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
||
self.info = ydl.extract_info(self.url, download=False)
|
||
|
||
@property
|
||
def title(self) -> str:
|
||
"""Возвращает title видео"""
|
||
return self.info.get("title", "unknown")
|
||
|
||
def get_video_url(self, resolution: Optional[str] = None) -> Optional[MediaContent]:
|
||
"""
|
||
Возвращает ссылку на видеопоток с указанным разрешением
|
||
resolution: например '1080p', '720p', '480p'
|
||
"""
|
||
formats = self.info.get("formats", [])
|
||
video_formats = [
|
||
f
|
||
for f in formats
|
||
if f.get("vcodec") != "none" # есть видео
|
||
and f.get("acodec") == "none" # без аудио
|
||
]
|
||
if resolution:
|
||
# ищем точное соответствие разрешению
|
||
for f in video_formats:
|
||
if f.get("format_note") == resolution:
|
||
return MediaContent(
|
||
f.get("url", ""),
|
||
f.get("http_headers", {}),
|
||
f.get("downloader_options", {}).get("http_chunk_size", 1024**2),
|
||
)
|
||
# если разрешение не указано или не найдено — берем лучший
|
||
if video_formats:
|
||
# сортируем по height
|
||
video_formats.sort(key=lambda x: x.get("height") or 0, reverse=True)
|
||
return MediaContent(
|
||
video_formats[0].get("url", ""),
|
||
video_formats[0].get("http_headers", {}),
|
||
video_formats[0]
|
||
.get("downloader_options", {})
|
||
.get("http_chunk_size", 1024**2),
|
||
)
|
||
return None
|
||
|
||
def get_audio_url(self) -> Optional[MediaContent]:
|
||
"""Возвращает ссылку на аудиопоток"""
|
||
formats = self.info.get("formats", [])
|
||
audio_formats = [
|
||
f
|
||
for f in formats
|
||
if f.get("vcodec") == "none" and f.get("acodec") != "none"
|
||
]
|
||
if audio_formats:
|
||
# берем наилучшее качество
|
||
audio_formats.sort(key=lambda x: x.get("abr") or 0, reverse=True)
|
||
return MediaContent(
|
||
audio_formats[0].get("url", ""),
|
||
audio_formats[0].get("http_headers", {}),
|
||
audio_formats[0]
|
||
.get("downloader_options", {})
|
||
.get("http_chunk_size", 1024**2),
|
||
)
|
||
return None
|