hentaimama: nowy zapis id posta i 5 playerow w admin-ajax, adresy w JSON-ie; bierzemy mp4 z gdvid (3 jakosci, bez tokenu), POST najpierw bez proxy. Ogon "Watch Online Free in HD" w tytulach ucinany. xanimeporn: przekierowanie download.php rozwiazywane na serwerze, apka dostawala .php, otwierala WebView i pobierala plik zamiast grac. Blad resolve (extractor pusty, HTTP strony) trafia do playback_events. Filmy: tytul z okruszkow (motyw dooplay losuje "Watch"/"Now Playing:"), linki nitroflare/rapidgator nie sa juz brane za wideo, sam landing idzie do WebView, a przytrzymanie w apce nie zabija ostatniego linku filmu, jesli serwer widzi, ze zyje. Skrypty naprawcze: tytuly dooplay, tytuly i miniatury hentaimama, repair_dooplay_movies dla streampornvip. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
80 lines
3.3 KiB
Python
80 lines
3.3 KiB
Python
"""xanimeporn.com — mp4 z endpointu pobierania. Dodany 2026-08-04.
|
|
|
|
Player to Fluid Player z **pustym `<source src=''>`** — źródło wstrzykiwane jest w
|
|
runtime, a skrypt inicjalizujący obsługuje wyłącznie fullscreen i analitykę. W statycznym
|
|
HTML nie ma ani jednego linku do wideo, więc wygląda to na ślepy zaułek.
|
|
|
|
Wyjściem jest zakładka „Downloads", która niesie:
|
|
|
|
https://videos.xanimeporn.com/download.php?id=<postId>&quality=1080p
|
|
https://videos.xanimeporn.com/download.php?id=<postId>&quality=720p
|
|
|
|
`postId` siedzi w klasie `<body>` (`postid-69951`), więc nie trzeba parsować zakładki —
|
|
składamy URL sami dla obu jakości.
|
|
|
|
**Oddajemy docelowy plik, nie `download.php` (zmiana 2026-10-15).** Endpoint przekierowuje
|
|
na `download.xanimeporn.com/videos/<q>/...mp4?s=<sig>&e=<epoch>` z `Content-Disposition:
|
|
attachment`. Wczesniej oddawalismy `download.php`, zeby telefon sam bral swiezy podpis, ale
|
|
apka po `.php` w adresie uznawala link za strone playera i otwierala go w WebView, ktory
|
|
POBIERAL plik do Pobranych zamiast grac (zgloszenie 54b17aed; od dodania serwisu ani jedno
|
|
odtworzenie). Podpis zyje ok. 2 h i nie jest zwiazany z IP (adres z VPS-a gra z domowego),
|
|
a resolve dzieje sie przy kliknieciu, wiec rozwiazujemy przekierowanie tutaj. Gdy sie nie
|
|
uda, zostaje `download.php` jako zapas.
|
|
|
|
Zweryfikowane z VPS-a: 1080p 222 MB i 720p 84 MB, oba 206 na Range z `ftypisom`/`ftypmp42`
|
|
w pierwszym KB (faststart). Wymaga Referera i UA, oba dokłada `playback.py`. Bez
|
|
Cloudflare i bez proxy, w odróżnieniu od hentaimamy.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import re
|
|
|
|
import httpx
|
|
|
|
from app.extractors._fetch import fetch_tube_html
|
|
from app.extractors._models import StreamSource
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
_BASE = "https://xanimeporn.com"
|
|
_POST_ID_RE = re.compile(r"\bpostid-(\d+)\b")
|
|
#: Serwis publikuje dokładnie te dwie jakości; kolejność = preferencja.
|
|
_QUALITIES = ("1080p", "720p")
|
|
_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36"
|
|
|
|
|
|
def extract(page_url: str, *, timeout: float = 60.0) -> list[StreamSource] | None:
|
|
html_text = fetch_tube_html(page_url, timeout=timeout)
|
|
m = _POST_ID_RE.search(html_text)
|
|
if not m:
|
|
log.info("xanimeporn: brak postid w klasie body na %s", page_url)
|
|
return None
|
|
post_id = m.group(1)
|
|
|
|
out: list[StreamSource] = []
|
|
for q in _QUALITIES:
|
|
link = f"https://videos.xanimeporn.com/download.php?id={post_id}&quality={q}"
|
|
try:
|
|
res = httpx.get(
|
|
link,
|
|
headers={"User-Agent": _UA, "Referer": _BASE + "/"},
|
|
follow_redirects=False,
|
|
timeout=15.0,
|
|
)
|
|
location = res.headers.get("location") or ""
|
|
if res.status_code in (301, 302, 303, 307, 308) and location.startswith("http"):
|
|
link = location
|
|
except Exception as e:
|
|
log.info("xanimeporn: przekierowanie %s %s nie wyszlo: %s", post_id, q, e)
|
|
out.append(
|
|
StreamSource(
|
|
link=link,
|
|
type="mp4",
|
|
quality=q,
|
|
referer=_BASE + "/",
|
|
# Zweryfikowane 206 + faststart, podpis nie jest zwiazany z IP.
|
|
raw={"mobile_direct_ok": True},
|
|
)
|
|
)
|
|
return out
|