CZWARTY niezalezny host: pliki na hentaiplanet.info, podczas gdy hentaimama ma gdvid.info, xanimeporn download.xanimeporn.com, a hentaigasm hgasm<N>.com. Cztery strony, cztery osobne pule plikow - zadna nie re-hostuje pozostalych, mimo ze katalogi odcinkow mocno sie pokrywaja. Metadane z RSS-a, tak jak przy hentaigasm i z tego samego powodu: /genre/ w HTML strony to 2084 linki, najwieksza chmura z sidebara w calym wertykale (hentaigasm mial 38, hentaimama 118). Feed daje date, tytul i realne kategorie. Odsiewamy przy tym pozycje czysto techniczne (Hentai Anime, New Hentai, English Subbed) oraz rocznik, bo to nie sa tagi tresci. /page/2/ nie zwraca odcinkow, /feed/?paged=N stronicuje chronologicznie. Playback: mp4 wprost w HTML (video.js), bez AJAX-a i bez Cloudflare. Pulapka: serwis nazywa miniaturki od pliku wideo (…-RAW.mp4_snapshot_07.59.jpg), wiec naiwne szukanie .mp4 lapie zarowno wideo, jak i obrazek. Wymagamy URL-a KONCZACEGO sie na .mp4 i odrzucamy wp-content/uploads. Druga pulapka, zlapana dopiero testem: og:image na tej stronie NIE ISTNIEJE, miniaturka jest tylko w JSON-LD i z escapowanymi ukosnikami. Pierwsza wersja dawala 12/12 odcinkow bez miniaturki. Zweryfikowane z VPS: 206 na Range, ftypmp42, 78 MB, dziala BEZ Referera i bez tokenu. Serwer oddaje content-type application/octet-stream, ale sciezka konczy sie .mp4, wiec ExoPlayer wybierze Mp4Extractor po rozszerzeniu. Pilot: seen 48, new 48, errors 0. Komplet dat i miniaturek. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
57 lines
2.3 KiB
Python
57 lines
2.3 KiB
Python
"""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 `<source>`).
|
|
|
|
**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
|