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)