fix(porn00): backend KVS resolve (portable CDN, no proxy) — corrects #20
Same proper re-investigation as freshporno (DevTools + Bright Data residential cross-IP + curl_cffi browser TLS). porn00's final CDN fe.porn00.org/...?token=&expires= is PORTABLE cross-IP (token resolved from one residential IP replays 206 from a different Bright Data residential IP) and only rejects non-browser TLS (plain curl 403, curl_cffi chrome 206). In #20 I tested the final URL with a standalone plain curl, got 403, wrongly concluded "IP-bound" and left it on WebView (and before that it used force_proxy, which violated the no-proxy stance). porn00 flashvars are plain get_file (already decoded, no function/0 prefix), so extend _kvs._URL_RE to match both forms — real_url passes plain URLs through unchanged, _resolve_get_file follows the 302 in-session. porn00.py becomes a thin _kvs wrapper. Verified no regression for the function/0 tubes (yespornvip/pornditt/ freshporno still resolve 3x mp4). Result: porn00 native multi-quality, mobile_direct, zero proxy/WebView. fpoxxx and pornxp were re-tested the same way and ARE genuinely IP-bound (403 from a different residential IP — their token binds to the resolver IP), so they correctly stay on the WebView fallback. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6e3ad870a7
commit
c05bafb4c7
3 changed files with 31 additions and 50 deletions
|
|
@ -32,6 +32,7 @@ from app.extractors.tubes import (
|
|||
hqporner,
|
||||
latestpornvideo,
|
||||
paradisehill,
|
||||
porn00,
|
||||
pornditt,
|
||||
pornhat,
|
||||
porntrex,
|
||||
|
|
@ -116,15 +117,14 @@ _REGISTRY: dict[str, Callable[[str], list[StreamSource] | None]] = {
|
|||
# Teraz backend-resolve jak yespornvip/pornditt (_kvs używa curl_cffi chrome).
|
||||
# Native, multi-quality, zero proxy/WebView. (zweryfikowane na emulatorze przed deploy)
|
||||
"freshpornoorg": freshporno.extract,
|
||||
# porn00 — KVS engine. 2026-06-01 cross-IP re-test (task #20): get_file 302 →
|
||||
# `fe.porn00.org/videos/.../<id>.mp4?token=&expires=` zwraca 403 z residential
|
||||
# IP → token IP-bound do resolvera (VPS), NIE portable jak yespornvip/pornditt.
|
||||
# Backend-resolve nie daje mobile-playable URL bez proxy, a video-proxy odpada
|
||||
# (public app, feedback Jana). Per polityka "IP-bound CDN → WebView": switch z
|
||||
# porn00.extract (force_proxy=True, łamało no-proxy) na _vps_blocked_fallback.
|
||||
# Ad-risk z bug-reportów 5037b3e3/e8e3198b złagodzony przez ad-filter (31d9076:
|
||||
# AD_HOSTS + coverOverlay + INJECTED_JS skip ad-CDN).
|
||||
"porn00org": _vps_blocked_fallback.extract,
|
||||
# porn00 — KVS (plain get_file + license). 2026-06-04 DevTools + cross-IP re-test
|
||||
# NAPRAWIA błąd z #20: finalny fe.porn00.org/...?token=&expires= jest PORTABLE
|
||||
# (token time-bound nie IP-bound — Bright Data residential proxy z innego IP → 206)
|
||||
# ale wymaga browser-TLS (curl_cffi chrome → 206; plain curl → 403). W #20
|
||||
# testowałem finalny URL plain-curl-em → 403 → błędnie „IP-bound" → WebView.
|
||||
# Teraz backend-resolve przez _kvs (curl_cffi chrome), native multi-quality,
|
||||
# ZERO proxy (wcześniej force_proxy łamał no-proxy). Same mechanizm co freshporno.
|
||||
"porn00org": porn00.extract,
|
||||
# pornxp — `<source> //sr.porn-xp.com/<token>/.../720.mp4` (redirect → xpxp.eu).
|
||||
# 2026-06-01 (task #20): 403 cross-IP → token w path IP-bound. WebView only.
|
||||
"pornxpph": _vps_blocked_fallback.extract,
|
||||
|
|
|
|||
|
|
@ -28,8 +28,15 @@ from app.extractors._models import StreamSource
|
|||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# Łapie OBA formaty flashvars:
|
||||
# - `function/0/https://.../get_file/<HASH>/...` (yespornvip/pornditt/freshporno —
|
||||
# zakodowany, dekodowany przez real_url)
|
||||
# - `https://.../get_file/...` (porn00 — już zdekodowany plain get_file; real_url
|
||||
# przepuszcza go bez zmian)
|
||||
# W obu przypadkach finał to get_file → 302 → CDN (follow in-session).
|
||||
_URL_RE = re.compile(
|
||||
r"(video(?:_alt)?_url\d*)\s*:\s*[\"'](function/0/[^\"']+)[\"']",
|
||||
r"(video(?:_alt)?_url\d*)\s*:\s*[\"']"
|
||||
r"(function/0/[^\"']+|https?://[^\"']*?/get_file/[^\"']*)[\"']",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
_TEXT_RE = re.compile(
|
||||
|
|
|
|||
|
|
@ -1,50 +1,24 @@
|
|||
"""porn00.org — KVS engine extractor.
|
||||
"""porn00.org — KVS (kt_player) direct stream extractor. Patrz app/extractors/tubes/_kvs.py.
|
||||
|
||||
Detail page wbudowuje stream URLs w JS flashvars block:
|
||||
- `video_url: 'https://.../get_file/.../<id>.mp4/?v-acctoken=...'` (default, 360p)
|
||||
- `video_alt_url: 'https://.../get_file/.../<id>_720p.mp4/?v-acctoken=...'` (alt, 720p)
|
||||
flashvars `video_url`/`video_alt_url` to PLAIN get_file (już zdekodowany, bez function/0):
|
||||
`https://www.porn00.org/get_file/3/<hash>/.../<id>.mp4` + `license_code`. _kvs._URL_RE
|
||||
łapie też ten format; real_url przepuszcza plain bez dekodowania; follow 302 →
|
||||
`fe.porn00.org/videos/.../<id>.mp4?token=&expires=` (206 video/mp4).
|
||||
|
||||
CDN token (`v-acctoken=...`) jest IP-bound do VPS, mobile direct fetch → 403.
|
||||
playback.py wraps URL przez stream_proxy z `Referer: <page_url>` — działa.
|
||||
|
||||
Get_file → 302 → direct mp4 (jak freshporno). Type='mp4'.
|
||||
2026-06-04 (DevTools + cross-IP re-test, naprawia błąd z #20): finalny CDN jest
|
||||
**portable cross-IP** (token time-bound nie IP-bound — zweryfikowane przez Bright Data
|
||||
residential proxy: get_file z jednego IP, fetch finalnego z innego IP → 206). W #20
|
||||
testowałem finalny URL plain-curl-em → 403 → błędnie „IP-bound" → WebView. Wymaga
|
||||
browser-TLS (curl_cffi chrome → 206; plain curl → 403). _kvs używa curl_cffi chrome,
|
||||
mobile (ExoPlayer) gra direct. Native, multi-quality, ZERO proxy (wcześniej force_proxy).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
from app.extractors._fetch import fetch_tube_html
|
||||
from app.extractors._models import StreamSource
|
||||
from app.extractors.tubes import _kvs
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
_VIDEO_URL_RE = re.compile(
|
||||
r"""video_url:\s*['"]([^'"]+\.mp4[^'"]*)['"]""", re.IGNORECASE,
|
||||
)
|
||||
_VIDEO_ALT_URL_RE = re.compile(
|
||||
r"""video_alt_url:\s*['"]([^'"]+\.mp4[^'"]*)['"]""", re.IGNORECASE,
|
||||
)
|
||||
_BASE = "https://www.porn00.org"
|
||||
|
||||
|
||||
def extract(page_url: str, *, timeout: float = 60.0) -> list[StreamSource] | None:
|
||||
html = fetch_tube_html(page_url, timeout=timeout)
|
||||
result: list[StreamSource] = []
|
||||
|
||||
# Preferujemy alt (720p) przed default (360p).
|
||||
# CDN token `v-acctoken` jest IP-bound do VPS. Mobile direct fetch ZAWSZE → 403,
|
||||
# więc oznacz force_proxy żeby player od razu używał proxified URL bez prób direct.
|
||||
# Bez tego: każdy playback = "mrugnięcie" (direct fail → fallback na proxy).
|
||||
proxy_flag = {"force_proxy": True}
|
||||
if (m := _VIDEO_ALT_URL_RE.search(html)):
|
||||
result.append(StreamSource(link=m.group(1), type="mp4", quality="720p", raw=proxy_flag))
|
||||
if (m := _VIDEO_URL_RE.search(html)):
|
||||
url = m.group(1)
|
||||
if not result or result[0].link != url:
|
||||
result.append(StreamSource(link=url, type="mp4", quality="360p", raw=proxy_flag))
|
||||
|
||||
if not result:
|
||||
log.info("porn00: no video_url flashvars on %s", page_url)
|
||||
return None
|
||||
|
||||
return result
|
||||
return _kvs.resolve_kvs(page_url, base_url=_BASE, timeout=timeout)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue