feat(scenes): force-refresh thumbnail via enrich-thumbnail ?force

enrich-thumbnail was fill-only (skipped scenes that already had a thumbnail), so a
broken or stale preview (rotting sxyprn/trafficdeposit) could not be refreshed. Add a
force flag that re-fetches the source page and overwrites the existing thumbnail.
Backs the new "Refresh thumbnail" button (report d3376a71).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
jtrzupek 2026-06-13 19:04:10 +02:00
parent 32919d6a6c
commit e512665d26

View file

@ -1205,6 +1205,7 @@ class EnrichThumbOut(BaseModel):
def enrich_thumbnail_from_tube( def enrich_thumbnail_from_tube(
scene_id: uuid.UUID, scene_id: uuid.UUID,
session: Annotated[Session, Depends(get_session)], session: Annotated[Session, Depends(get_session)],
force: bool = False,
) -> EnrichThumbOut: ) -> EnrichThumbOut:
"""Pobiera detail page z dowolnego tube playback_source bez thumbnail_url """Pobiera detail page z dowolnego tube playback_source bez thumbnail_url
i wyciąga miniaturkę (og:image / twitter:image / LD-JSON thumbnailUrl / i wyciąga miniaturkę (og:image / twitter:image / LD-JSON thumbnailUrl /
@ -1213,7 +1214,10 @@ def enrich_thumbnail_from_tube(
Update'uje WSZYSTKIE PlaybackSource'y dla tej sceny które nie mają thumb, Update'uje WSZYSTKIE PlaybackSource'y dla tej sceny które nie mają thumb,
żeby kolejne otwarcia listy widziały miniaturę niezależnie od source pick. żeby kolejne otwarcia listy widziały miniaturę niezależnie od source pick.
Mobile auto-wywoła to przy otwarciu SceneDetail bez thumb (jak duration). Mobile auto-wywoła to przy otwarciu SceneDetail bez thumb (jak duration).
"""
`force=true` (przycisk "Refresh thumbnail" na SceneDetail, zgłoszenie d3376a71):
NADPISUJE istniejącą miniaturę świeżą ze strony tube'a — dla zepsutych/stałych
(rotting sxyprn/trafficdeposit, błędna grafika)."""
from app.extractors._fetch import browser_get from app.extractors._fetch import browser_get
from app.extractors._models import TubePageError from app.extractors._models import TubePageError
from app.extractors.thumb_extract import extract_thumbnail_url from app.extractors.thumb_extract import extract_thumbnail_url
@ -1232,8 +1236,8 @@ def enrich_thumbnail_from_tube(
).scalars().all() ).scalars().all()
sources_with_thumb = [s for s in sources if s.thumbnail_url] sources_with_thumb = [s for s in sources if s.thumbnail_url]
if sources_with_thumb: if sources_with_thumb and not force:
# już mamy — idempotent return. # już mamy — idempotent return (force=true pomija, żeby odświeżyć).
return EnrichThumbOut( return EnrichThumbOut(
scene_id=scene_id, scene_id=scene_id,
thumbnail_url=sources_with_thumb[0].thumbnail_url, thumbnail_url=sources_with_thumb[0].thumbnail_url,
@ -1250,10 +1254,10 @@ def enrich_thumbnail_from_tube(
continue continue
thumb = extract_thumbnail_url(r.text) thumb = extract_thumbnail_url(r.text)
if thumb: if thumb:
# Zapisz na wszystkich źródłach bez thumb (oszczędza duplikat fetch) # Zapisz na wszystkich źródłach bez thumb (force → też nadpisz istniejące).
updated = 0 updated = 0
for s in sources: for s in sources:
if not s.thumbnail_url: if force or not s.thumbnail_url:
s.thumbnail_url = thumb s.thumbnail_url = thumb
updated += 1 updated += 1
session.commit() session.commit()