"""Extracteur Uqload (uqload.to/.co/.com/.io/.vc) — page embed → mp4/m3u8. La page embed contient un jwplayer configuré dans du JS packé (p,a,c,k,e,d) : `sources:[{file:"https://.../master.m3u8?..."}]`. On dépacke puis on extrait par regex. """ import logging import re from app.scrapers.base import HosterExtractor, ScrapeError, VideoLink, register_hoster from app.scrapers.hosters._packer import unpack_packed_js from app.scrapers.http import fetch logger = logging.getLogger(__name__) _PATTERNS = ( re.compile(r'sources\s*:\s*\[\s*\{[^}]*?(?:file|src)\s*:\s*["\'](?P[^"\']+)["\']'), re.compile(r'(?:file|src)\s*:\s*["\'](?Phttps?://[^"\']+?\.(?:m3u8|mp4)[^"\']*)["\']'), re.compile(r'["\'](?Phttps?://[^"\']*?\.(?:m3u8|mp4)(?:\?[^"\']*)?)["\']'), ) @register_hoster class UqloadExtractor(HosterExtractor): name = "uqload" domains = ("uqload.to", "uqload.co", "uqload.com", "uqload.io", "uqload.vc") async def extract(self, embed_url: str) -> VideoLink: html = await fetch(embed_url) candidates: list[str] = [] for content in (html, unpack_packed_js(html) or ""): for pattern in _PATTERNS: for match in pattern.finditer(content): candidates.append(match.group("url")) video = [u for u in candidates if re.search(r"\.(mp4|m3u8)(\?|$)", u)] url = next((u for u in video if ".mp4" in u), None) or (video[0] if video else None) if not url: raise ScrapeError(f"uqload : URL vidéo introuvable dans {embed_url}") return VideoLink( url=url, hoster=self.name, headers={"Referer": embed_url}, is_hls=".m3u8" in url, )