diff --git a/app/api/scenes.py b/app/api/scenes.py index ec46e5b..5bfb892 100644 --- a/app/api/scenes.py +++ b/app/api/scenes.py @@ -712,6 +712,49 @@ def _is_rotting_thumb(url: str) -> bool: return "fastpic.org" in url +def _is_flaky_thumb(url: str) -> bool: + """Host, który działa BYWA, ale zbyt często pada, żeby wygrywać wybór miniaturki. + + W odróżnieniu od `_is_rotting_thumb` NIE zerujemy takiej miniatury w SceneDetail: + to nie jest martwy URL, tylko niepewny. Zerowanie powtórzyłoby wpadkę z fullpornerem + z sierpnia 2026, gdzie sceny mające tylko to źródło traciły obrazek całkowicie. + + Problem był w kolejności wyboru: miniaturkę wygrywał pierwszy origin alfabetycznie, + a `tube:fullmoviesxxx` sortuje się PRZED `tube:fullporner`, więc chwiejny host + przykrywał zdrowy. 51 799 z 52 758 takich scen (98%) ma alternatywę, więc degradacja + niemal zawsze ma czym zastąpić. + + Pomiar 2026-08-13, po 20-25 losowych URL-ach na host: + + img.fullmovies.xxx 12/20 ok (5× ReadTimeout, 3× 502) 54 019 źródeł + img.hdporn.gg 16/20 ok (3× 502, 1× ReadTimeout) 54 267 źródeł + imgs.xiaoshenke.net 20/20 ok (fullporner) 68 406 źródeł + freshporno.org 20/20 ok + + `img.hdporn.gg` dopisany po sprawdzeniu efektu pierwszej wersji: degradacja samego + fullmovies przesunęła wybór na hdporn (44 z 60 scen), czyli przeniosłaby problem + zamiast go rozwiązać. Po dopisaniu obu wygrywają hosty ze 100% skutecznością. + """ + return "img.fullmovies.xxx" in url or "img.hdporn.gg" in url + + +#: Im niżej, tym gorzej. Używane TYLKO wewnątrz tieru fallback, czyli gdy scena nie ma +#: żadnej zdrowej miniatury i trzeba wybrać mniejsze zło. Bez tego decydowała kolejność +#: alfabetyczna originu, przez co scena mająca fullmovies + hdporn dostawała fullmovies, +#: czyli host o 40% awaryjności zamiast tego o 20%. +_FLAKY_RANK = ( + ("img.hdporn.gg", 1), # 16/20 ok + ("img.fullmovies.xxx", 2), # 12/20 ok +) + + +def _flaky_rank(url: str) -> int: + for host, rank in _FLAKY_RANK: + if host in url: + return rank + return 0 # nie-chwiejny (martwy rotting-thumb) — bez preferencji + + 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, @@ -847,8 +890,15 @@ def _build_scenes_out_batch( # Też tier fallback: statyczna miniatura z innego źródła jest tańsza. thumb_fallback.setdefault(sid, (yp, page_url)) elif thumb: - if _is_rotting_thumb(thumb): - thumb_fallback.setdefault(sid, (thumb, page_url)) + if _is_rotting_thumb(thumb) or _is_flaky_thumb(thumb): + # Martwe ORAZ chwiejne lądują w tierze fallback: użyte tylko wtedy, + # gdy scena nie ma stabilniejszej miniatury z innego źródła. W obrębie + # samego fallbacku wybieramy mniejsze zło wg `_FLAKY_RANK`, bo inaczej + # decydowałaby kolejność alfabetyczna originu i scena z fullmovies + + # hdporn dostawała gorszy z dwóch (pomiar: 38 z 60 takich scen). + prev = thumb_fallback.get(sid) + if prev is None or _flaky_rank(thumb) < _flaky_rank(prev[0]): + thumb_fallback[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: