Mixdrop (bug #3/#10 czarny ekran): wymagane UA+Accept headers (bez nich shell bez P.A.C.K.E.R.). Detect dead-video page -> raise HosterDead zamiast None (mobile dostaje skip-to-next sygnal). Dispatch regex obejmuje nowy canonical domain `miixdrop` (double-i). Yespornvip (bug #1): nowy KVS engine extractor. Origin `tube:yespornvip` istnial w playback_sources ale brak handlera w _REGISTRY -> try_extract None. Flashvars `video_url: 'function/0/<get_file_url>'`, function/0 to passthrough. 480p mp4 z mobile_direct_ok=True. Freshporno (bug #9 revert): wrocony na _vps_blocked_fallback (WebView path). Krotko-zywy switch na native extract z force_proxy=True cofniety bo app idzie publicznie - VPS bandwidth/anonimowosc priorytet nad UX flicker. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
77 lines
2.6 KiB
Python
77 lines
2.6 KiB
Python
"""yesporn.vip — KVS engine direct stream extractor.
|
|
|
|
User bug-report 2026-05-27: "Yespornvip dalej nie działa". Origin `tube:yespornvip`
|
|
istniał w playback_sources ale brak wpisu w `_REGISTRY` → `try_extract()` zwracał
|
|
None → mobile player no-source.
|
|
|
|
Detail page sceny linkuje do `/embed/<id>` w iframe. Embed page renderuje KVS
|
|
player z `flashvars`:
|
|
- `video_url: 'function/0/https://yesporn.vip/get_file/<srv>/<token>/<bucket>/<id>/<id>.mp4/?embed=true'`
|
|
- `event_reporting2: 'https://yesporn.vip/get_file/.../<id>.mp4/'` (analytics ping
|
|
URL, ale jest valid get_file)
|
|
- `video_url_text: '480p'` — quality label dla video_url
|
|
|
|
`function/0/` to KVS player JS dekoder prefix — dla type 0 to passthrough,
|
|
URL po prefixie jest bezpośrednio użyteczny.
|
|
|
|
Single-quality (480p) z embed bo wyższe (`video_alt_url`) to redirect URLs
|
|
(`video_alt_url_redirect: '1'`), nie direct streamy. CDN time-bound signed,
|
|
mobile gra direct.
|
|
"""
|
|
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://yesporn.vip"
|
|
|
|
# `video_url: 'function/0/https://.../get_file/...mp4/?embed=true'` lub bez prefixu
|
|
_VIDEO_URL_RE = re.compile(
|
|
r"video_url\s*:\s*'(?:function/0/)?(https?://[^']+/get_file/[^']+\.mp4/?[^']*)'",
|
|
re.IGNORECASE,
|
|
)
|
|
_QUALITY_RE = re.compile(r"video_url_text\s*:\s*'([^']*)'", re.IGNORECASE)
|
|
|
|
|
|
def extract(page_url: str, *, timeout: float = 60.0) -> list[StreamSource] | None:
|
|
if "/embed/" not in page_url:
|
|
# Detail page → derive embed URL via /video/<id>/<slug>/ → /embed/<id>.
|
|
m = re.search(r"/video/(\d+)/", page_url)
|
|
if m:
|
|
embed_url = f"{_BASE}/embed/{m.group(1)}"
|
|
else:
|
|
log.info("yespornvip: cannot derive embed from %s", page_url)
|
|
return None
|
|
else:
|
|
embed_url = page_url
|
|
|
|
html = fetch_tube_html(embed_url, timeout=timeout)
|
|
|
|
m = _VIDEO_URL_RE.search(html)
|
|
if not m:
|
|
log.info("yespornvip: no video_url in flashvars on %s", embed_url)
|
|
return None
|
|
|
|
url = m.group(1)
|
|
# `?embed=true` parametr — get_file z embed=true może zwracać HTML wrapper
|
|
# zamiast 302 do CDN. Zostawiamy bo player tak go używa, ale jeśli 302 nie
|
|
# wskoczy poprawnie to fallback usunie param.
|
|
quality = None
|
|
q_match = _QUALITY_RE.search(html)
|
|
if q_match:
|
|
quality = q_match.group(1).strip() or None
|
|
|
|
return [
|
|
StreamSource(
|
|
link=url,
|
|
type="mp4",
|
|
quality=quality,
|
|
referer=_BASE + "/",
|
|
raw={"mobile_direct_ok": True},
|
|
)
|
|
]
|