"""sxyprn.com — direct stream extractor. Page → `data-vnfo` JSON → URL transform algorytmem boo/ssut51/preda → .vid mp4. Sxyprn URL'e w `data-vnfo` mają format `/cdn/c8/////.vid` który wymaga rebuildu zanim CDN zaserwuje video bytes (bez tego endpoint zwraca tylko pojedynczy timestamp 10B jako placeholder/probe response). Algorytm z `main2.js`: tmp[1] += "8/" + base64url("-sxyprn.com-") tmp[5] -= ssut51(tmp[6]) + ssut51(tmp[7]) # preda gdzie ssut51 sumuje cyfry w stringu. Po tym joinujemy → finalny URL serwujący mp4. Każdy fetch strony zwraca FRESH signed URL (różne tokeny i timestamp). """ from __future__ import annotations import base64 import json import logging import re from app.extractors._fetch import fetch_tube_html from app.extractors._models import StreamSource log = logging.getLogger(__name__) _VNFO_RE = re.compile(r"data-vnfo='([^']+)'") def _ssut51(s: str) -> int: """Sumuje wszystkie cyfry w stringu.""" return sum(int(c) for c in s if c.isdigit()) def _boo(ss: int, es: int) -> str: """base64url-safe `-sxyprn.com-` z `=`→`.`.""" raw = f"{ss}-sxyprn.com-{es}".encode() return ( base64.b64encode(raw) .decode() .replace("+", "-") .replace("/", "_") .replace("=", ".") ) def extract(page_url: str, *, timeout: float = 60.0) -> list[StreamSource] | None: html = fetch_tube_html(page_url, timeout=timeout) m = _VNFO_RE.search(html) if not m: log.warning("sxyprn: no data-vnfo in %s", page_url) return None try: vnfo = json.loads(m.group(1)) except json.JSONDecodeError: log.warning("sxyprn: bad vnfo JSON in %s", page_url) return None if not isinstance(vnfo, dict) or not vnfo: return None sources: list[StreamSource] = [] for _pid, src in vnfo.items(): if not isinstance(src, str) or not src.startswith("/cdn/"): continue tmp = src.split("/") if len(tmp) < 8: log.warning("sxyprn: short path (%d segs) %s", len(tmp), src) continue try: s6 = _ssut51(tmp[6]) s7 = _ssut51(tmp[7]) tmp[1] += "8" + "/" + _boo(s6, s7) tmp[5] = str(int(tmp[5]) - s6 - s7) except (ValueError, IndexError) as e: log.warning("sxyprn: transform failed for %s: %s", src, e) continue final_path = "/".join(tmp) full = "https://sxyprn.com" + final_path sources.append(StreamSource(link=full, type="mp4")) if not sources: return None return sources