import logging import time from functools import lru_cache from fastapi import APIRouter, HTTPException from app.models.youtube import YouTubeExtractRequest, YouTubeStreamResponse, StreamFormat logger = logging.getLogger(__name__) router = APIRouter(tags=["youtube"]) @lru_cache def _get_youtube_service(): from app.core.config import get_settings from app.services.youtube_service import YouTubeService s = get_settings() return YouTubeService(timeout=s.yt_dlp_timeout, cache_ttl=s.yt_dlp_cache_ttl) @router.post("/youtube/extract", response_model=YouTubeStreamResponse) async def extract_youtube_stream(req: YouTubeExtractRequest): from app.core.config import get_settings settings = get_settings() if not settings.youtube_proxy_enabled: raise HTTPException(status_code=503, detail="YouTube proxy is disabled") service = _get_youtube_service() started = time.monotonic() logger.info("youtube-extract-started url=%s", req.url) try: data = await service.extract_streams(req.url) except Exception as e: logger.error("youtube-extract-failed url=%s error=%s", req.url, e) raise HTTPException(status_code=500, detail=str(e)) if data.get("error"): logger.warning( "youtube-extract-error url=%s error=%s duration=%.1fs", req.url, data["error"], time.monotonic() - started, ) return YouTubeStreamResponse( video_id=data.get("video_id", ""), title=data.get("title", ""), error=data["error"], ) formats = [ StreamFormat( format_id=f.get("format_id", ""), url=f.get("url", ""), resolution=f.get("resolution"), is_audio_only=f.get("acodec", "none") != "none" and f.get("vcodec", "none") == "none", is_video_only=f.get("vcodec", "none") != "none" and f.get("acodec", "none") == "none", codec=f.get("vcodec") or f.get("acodec"), ) for f in data.get("formats", []) ] logger.info( "youtube-extract-completed url=%s video_id=%s is_live=%s fmt_count=%d duration=%.1fs", req.url, data["video_id"], data["is_live"], len(formats), time.monotonic() - started, ) return YouTubeStreamResponse( video_id=data["video_id"], title=data["title"], is_live=data["is_live"], is_upcoming=data["is_upcoming"], video_proxy_url=data.get("video_proxy_url"), audio_proxy_url=data.get("audio_proxy_url"), thumbnail_url=data.get("thumbnail_url"), formats=formats, )