"""hentaigasm.com — bezpośredni mp4 z konfiguracji JWPlayera. Dodany 2026-08-04. Najprostszy z całego wertykału hentai. Konfiguracja playera siedzi WPROST w HTML strony odcinka, bez AJAX-a i bez Cloudflare: jwplayer("player_01").setup({ file: "https://hgasm1.com/Nuki Nuki Zupposism 2 Subbed.mp4", image: "https://hgasm1.com/thumbnail/Nuki Nuki Zupposism 2 Subbed.jpg", ... }) Dla porównania: [[hentaimama]] trzyma to za POST-em na `admin-ajax` schowanym za Cloudflare, a [[xanimeporn]] ma Fluid Player z pustym `` i realny link dopiero w zakładce „Downloads". **Ścieżka zawiera SPACJE** i trzeba je zakodować — bez tego request się wywala. Kodujemy tylko część po hoście, żeby nie ruszyć schematu ani kropek w domenie. Zweryfikowane z VPS-a: 206 na Range, `ftypisom` w pierwszym KB (faststart), 198 MB, działa BEZ Referera i bez tokenu, więc URL nie wygasa. Stąd `mobile_direct_ok`. """ from __future__ import annotations import logging import re from urllib.parse import quote, urlsplit, urlunsplit from app.extractors._fetch import fetch_tube_html from app.extractors._models import StreamSource log = logging.getLogger(__name__) _BASE = "https://hentaigasm.com" _JW_FILE_RE = re.compile(r"file:\s*[\"'](https?://[^\"']+\.mp4)[\"']") def _encode(url: str) -> str: """Zakoduj spacje w ścieżce, zostawiając schemat i host nietknięte.""" parts = urlsplit(url) return urlunsplit( (parts.scheme, parts.netloc, quote(parts.path), parts.query, parts.fragment) ) def extract(page_url: str, *, timeout: float = 60.0) -> list[StreamSource] | None: html_text = fetch_tube_html(page_url, timeout=timeout) seen: set[str] = set() out: list[StreamSource] = [] for raw in _JW_FILE_RE.findall(html_text): link = _encode(raw.strip()) if link in seen: continue seen.add(link) out.append( StreamSource( link=link, type="mp4", quality=None, # serwis publikuje jedną rendycję, bez etykiety referer=_BASE + "/", # Zweryfikowane: 206 bez Referera, bez tokenu, faststart. raw={"mobile_direct_ok": True}, ) ) if not out: log.info("hentaigasm: brak file: w konfiguracji JWPlayera na %s", page_url) return None return out