fix(kvs): cap get_file timeout + early-break on dead scenes

Bug 6ec1960e: yespornvip "resolving forever". yesporn.vip moved to a
cdn4/remote_control.php CDN (still portable cross-IP — verified 206 from a
residential IP, so backend resolve stays correct). But when a video is removed
from the CDN the page still exists and each get_file 302-follow STALLS to the
full timeout. With the resolve timeout (60s) applied per quality variant, a dead
scene hung 3x60 = 180s and returned nothing -> the mobile resolve spinner never
ended.

Fix: a dedicated low get_file timeout (10s, separate from the page-fetch
timeout) and an early-break once 2 variants fail with no result so far (the
scene is dead on the CDN — no point waiting for the third). Dead scene now
resolves to None in ~20s instead of 180s; a live scene is unaffected (~0.8s,
3 sources). Applies to all KVS tubes (yespornvip + pornditt).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
jtrzupek 2026-06-02 21:33:05 +02:00
parent 08f901712c
commit d4c4b79e92

View file

@ -40,6 +40,13 @@ _LICENSE_RE = re.compile(r"license_code\s*:\s*[\"'](\$[^\"']+)[\"']", re.IGNOREC
_HASH_LENGTH = 32
# get_file 302-follow timeout. Zdrowy CDN odpowiada <1s; gdy wideo zostało usunięte
# z CDN (strona istnieje, ale get_file stalluje) request wisi do timeoutu. Trzymamy
# go NISKO i osobno od page-fetch timeoutu — bug 6ec1960e 2026-06-02: yesporn.vip
# przeszedł na cdn4/remote_control.php i dla martwych scen wszystkie 3 jakości
# wisiały po 60s = 180s → mobile "resolving w nieskończoność".
_GETFILE_TIMEOUT = 10.0
def _license_token(license_code: str) -> list[int]:
license_code = license_code.replace("$", "")
@ -134,16 +141,25 @@ def resolve_kvs(page_url: str, *, base_url: str, timeout: float = 60.0) -> list[
for m in _TEXT_RE.finditer(html):
quality_by_var[m.group(1).lower()] = m.group(2).strip()
# get_file timeout NISKI (osobny od page-fetch) + early-break: gdy 2 pierwsze
# jakości nie rozwiążą się (przy 0 dotychczasowych wyników) scena jest martwa na
# CDN — nie ma sensu czekać na trzecią (oszczędza kolejne _GETFILE_TIMEOUT).
gf_timeout = min(timeout, _GETFILE_TIMEOUT)
seen_dec: set[str] = set()
result: list[StreamSource] = []
fails = 0
for m in _URL_RE.finditer(html):
var_name = m.group(1).lower()
decoded = real_url(m.group(2), license_code)
if decoded in seen_dec:
continue
seen_dec.add(decoded)
final = _resolve_get_file(session, base_url, decoded, timeout)
final = _resolve_get_file(session, base_url, decoded, gf_timeout)
if not final:
fails += 1
if fails >= 2 and not result:
log.info("kvs: %d get_file fails, 0 results — martwa scena? %s", fails, page_url)
break
continue
result.append(
StreamSource(