From adbdce1c75806f75b39f0bfeea98f44c711fcd99 Mon Sep 17 00:00:00 2001 From: jtrzupek Date: Wed, 10 Jun 2026 10:11:10 +0200 Subject: [PATCH] fix(api): de-prioritize rotting sxyprn/trafficdeposit thumbnails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sxyprn thumbnails are time-signed on trafficdeposit CDN and ROT — the signed asset 404s after ~weeks and can't be re-signed/refreshed server-side (bug 2026-06-10, ~15k sxyprn-only scenes showed broken thumbs). In the light-list slim-thumbnail pick, prefer a thumbnail from any non-trafficdeposit source; fall back to sxyprn only when it's the scene's sole thumbnail (recent ones still load; dead ones now render a clean placeholder client-side instead of a broken image). Co-Authored-By: Claude Opus 4.8 --- app/api/scenes.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/app/api/scenes.py b/app/api/scenes.py index 640a3b5..d48102d 100644 --- a/app/api/scenes.py +++ b/app/api/scenes.py @@ -442,6 +442,13 @@ def get_scene( return _build_scene_out(session, scene, device_id=device_id) +def _is_rotting_thumb(url: str) -> bool: + """sxyprn/trafficdeposit miniaturki są czasowo podpisane i rotują (asset 404 po + ~tygodniach, nie odświeżalne server-side; bug 2026-06-10). De-prioritize je w wyborze + slim-thumbnaila — używamy tylko gdy scena nie ma żadnej innej miniaturki.""" + return "trafficdeposit.com" in url + + def _needs_proxy(url: str) -> bool: """Wszystkie thumbnaile z playback_sources są proxowane przez backend. Większość CDN-ów porn-tube'ów wymaga Refera (hqporner, mypornerleak/58img, @@ -557,14 +564,25 @@ def _build_scenes_out_batch( ) .order_by(PlaybackSource.origin.asc()) ).all() - # Pierwsza miniaturka + pierwszy animated per scena (1 slim wpis). + # Pierwsza miniaturka + pierwszy animated per scena (1 slim wpis). De-prioritize + # sxyprn/trafficdeposit thumbnaile — są podpisane czasowo i ROTUJĄ (asset 404 po + # ~tygodniach, nie da się re-signować; bug 2026-06-10). Wolimy miniaturkę z innego + # źródła gdy istnieje; sxyprn bierzemy tylko gdy nic innego nie ma (świeże jeszcze + # działają, martwe → mobile pokazuje placeholder zamiast broken-image). thumb_by_scene: dict = {} + thumb_fallback: dict = {} anim_by_scene: dict = {} for sid, thumb, anim, page_url in pb_light: - if sid not in thumb_by_scene and thumb: - thumb_by_scene[sid] = (thumb, page_url) + if thumb: + if _is_rotting_thumb(thumb): + thumb_fallback.setdefault(sid, (thumb, page_url)) + elif sid not in thumb_by_scene: + thumb_by_scene[sid] = (thumb, page_url) if sid not in anim_by_scene and anim: anim_by_scene[sid] = (anim, page_url) + # Uzupełnij scenami które mają TYLKO rotting thumbnail (sxyprn-only). + for sid, val in thumb_fallback.items(): + thumb_by_scene.setdefault(sid, val) for sid in scene_ids: t = thumb_by_scene.get(sid) a = anim_by_scene.get(sid)