"""hentaiplay.net — bezpośredni mp4 z odtwarzacza video.js. Dodany 2026-08-04. Link do pliku siedzi wprost w HTML strony odcinka (player to video.js z `vjs.zencdn.net`), bez AJAX-a i bez Cloudflare — podobnie jak przy [[hentaigasm]], w odróżnieniu od [[hentaimama]] (POST za CF) i [[xanimeporn]] (pusty ``). **Trzeba odsiać miniaturki, nie tylko szukać `.mp4`.** Serwis nazywa zrzuty klatek od pliku wideo, więc w HTML leżą obok siebie: https://hentaiplanet.info/Ushiro-no-Shoumen-Kamui-san-Episode-4-RAW.mp4 ← wideo …/wp-content/uploads/Ushiro-…-RAW.mp4_snapshot_07.59.296-160x90.jpg ← miniaturka Naiwne `\\.mp4` łapie oba. Dlatego wymagamy, żeby URL KOŃCZYŁ się na `.mp4`, i dodatkowo odrzucamy `wp-content/uploads` (miniaturki serwisu). Zweryfikowane z VPS-a: 206 na Range, `ftypmp42` w pierwszym KB (faststart), 78 MB, działa BEZ Referera i bez tokenu. Serwer oddaje `content-type: application/octet-stream`, ale ścieżka kończy się `.mp4`, więc ExoPlayer i tak wybierze `Mp4Extractor` po rozszerzeniu. Stąd `mobile_direct_ok`. """ from __future__ import annotations import logging import re from app.extractors._fetch import fetch_tube_html from app.extractors._models import StreamSource log = logging.getLogger(__name__) _BASE = "https://hentaiplay.net" #: Tylko URL-e KOŃCZĄCE się na .mp4 — patrz pułapka z miniaturkami w docstringu. _MP4_RE = re.compile(r"https?://[A-Za-z0-9._~%+-]+(?:/[A-Za-z0-9._~%+-]+)*\.mp4(?=[\"'\s<>]|$)") 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 link in _MP4_RE.findall(html_text): if "wp-content/uploads" in link or 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("hentaiplay: brak linku mp4 na %s", page_url) return None return out