fix(playback): mark deleted sxyprn posts dead + rank native sources first
Two bug-report fixes (2026-06-07): - sxyprn returns HTTP 200 "Post Not Found" for deleted posts (soft-404), so the extractor returned None → resolve treated it as transient and never marked the source dead, leaving a dead link offered forever. Now raise HosterDead on the marker so resolve marks it dead. - Scene playback sources were ordered alphabetically by origin, so a WebView- fallback hoster (fpoxxx, IP-bound + ad-heavy) ranked above a working native source (freshporno) on the same scene. Add is_vps_blocked_fallback() and sort native-resolve origins ahead of WebView-fallback ones. Verified on prod: sxyprn dead URL → HosterDead; scene sources reorder freshpornoorg before fpoxxx. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
4d14f3946b
commit
8c0edbdf7b
3 changed files with 30 additions and 1 deletions
|
|
@ -653,6 +653,20 @@ def _build_scene_out(session: Session, scene: Scene) -> SceneOut:
|
||||||
out.animated_thumbnail_url = _wrap_image_proxy(out.animated_thumbnail_url, p.page_url)
|
out.animated_thumbnail_url = _wrap_image_proxy(out.animated_thumbnail_url, p.page_url)
|
||||||
playback_out.append(out)
|
playback_out.append(out)
|
||||||
|
|
||||||
|
# Rank natywne-resolve źródła PRZED WebView-fallback (IP-bound/ad-heavy: fpoxxx,
|
||||||
|
# pornxpph, pornhub...). Query był alfabetyczny po origin, więc np. fpoxxx-WebView
|
||||||
|
# pokazywał się przed działającym freshporno (bug-report 2026-06-07). Stabilny sort:
|
||||||
|
# natywne (0) → fallback (1), tie-break po origin.
|
||||||
|
from app.extractors import is_vps_blocked_fallback
|
||||||
|
|
||||||
|
def _resolve_rank(origin: str | None) -> int:
|
||||||
|
if not origin:
|
||||||
|
return 1
|
||||||
|
sitetag = origin.split(":", 1)[1] if ":" in origin else origin
|
||||||
|
return 1 if is_vps_blocked_fallback(sitetag) else 0
|
||||||
|
|
||||||
|
playback_out.sort(key=lambda o: (_resolve_rank(o.origin), o.origin or ""))
|
||||||
|
|
||||||
progress = session.get(ScenePlayProgress, scene.id)
|
progress = session.get(ScenePlayProgress, scene.id)
|
||||||
is_fav = session.get(FavoriteScene, scene.id) is not None
|
is_fav = session.get(FavoriteScene, scene.id) is not None
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -193,6 +193,15 @@ def supported_sitetags() -> tuple[str, ...]:
|
||||||
return tuple(_REGISTRY.keys())
|
return tuple(_REGISTRY.keys())
|
||||||
|
|
||||||
|
|
||||||
|
def is_vps_blocked_fallback(sitetag: str) -> bool:
|
||||||
|
"""True gdy sitetag resolvuje się TYLKO przez WebView fallback (IP-bound CDN /
|
||||||
|
ad-heavy / CAPTCHA — np. fpoxxx, pornxpph, pornhubcom). Takie źródła dają gorszy
|
||||||
|
UX (reklamy, czarny ekran) niż natywny KVS/direct resolve, więc UI powinien je
|
||||||
|
rankować NIŻEJ gdy scena ma też natywne źródło (bug-report 2026-06-07: scena
|
||||||
|
pokazywała fpoxxx-WebView przed działającym freshporno bo sort był alfabetyczny)."""
|
||||||
|
return _REGISTRY.get(sitetag) is _vps_blocked_fallback.extract
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"try_extract",
|
"try_extract",
|
||||||
"supported_sitetags",
|
"supported_sitetags",
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import logging
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from app.extractors._fetch import fetch_tube_html
|
from app.extractors._fetch import fetch_tube_html
|
||||||
from app.extractors._models import StreamSource
|
from app.extractors._models import HosterDead, StreamSource
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -48,6 +48,12 @@ def _boo(ss: int, es: int) -> str:
|
||||||
|
|
||||||
def extract(page_url: str, *, timeout: float = 60.0) -> list[StreamSource] | None:
|
def extract(page_url: str, *, timeout: float = 60.0) -> list[StreamSource] | None:
|
||||||
html = fetch_tube_html(page_url, timeout=timeout)
|
html = fetch_tube_html(page_url, timeout=timeout)
|
||||||
|
# sxyprn soft-404: usunięty post zwraca HTTP 200 ze stroną "Post Not Found"
|
||||||
|
# (nie 404), więc bez tego extractor zwracał None → resolve traktował jako
|
||||||
|
# transient i NIGDY nie oznaczał źródła dead → user wciąż dostawał martwy link
|
||||||
|
# (bug-report 2026-06-07, scena 75aa3316). Raise HosterDead → resolve mark-dead.
|
||||||
|
if "Post Not Found" in html:
|
||||||
|
raise HosterDead(f"sxyprn {page_url}: post deleted (Post Not Found)")
|
||||||
m = _VNFO_RE.search(html)
|
m = _VNFO_RE.search(html)
|
||||||
if not m:
|
if not m:
|
||||||
log.warning("sxyprn: no data-vnfo in %s", page_url)
|
log.warning("sxyprn: no data-vnfo in %s", page_url)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue