diff --git a/app/api/scenes.py b/app/api/scenes.py index c6215f6..a364c7c 100644 --- a/app/api/scenes.py +++ b/app/api/scenes.py @@ -647,6 +647,16 @@ def _build_scenes_out_batch( ).scalars().all() for p in pb_rows: out = PlaybackSourceOut.model_validate(p) + # sxyprn/trafficdeposit stored thumb rotuje (404 po ~tygodniach). SceneDetail + # bierze PIERWSZE źródło z thumbem (origin ASC → sxyprncom często pierwsze), więc + # bez tego pokazywał martwy obraz mimo że LISTA używała żywej wersji (report: + # "na liście jest miniaturka, w scenie nie"). Podmieniamy na żywy resolver; + # inne martwe rotting-thumby zerujemy → mobile bierze kolejne źródło / placeholder. + sxy = _sxyprn_thumb_url(p.page_url) + if sxy: + out.thumbnail_url = sxy + elif out.thumbnail_url and _is_rotting_thumb(out.thumbnail_url): + out.thumbnail_url = None if out.thumbnail_url and _needs_proxy(out.thumbnail_url): out.thumbnail_url = _wrap_image_proxy(out.thumbnail_url, p.page_url) if out.animated_thumbnail_url and _needs_proxy(out.animated_thumbnail_url): diff --git a/app/connectors/direct_scrapers/watchporn.py b/app/connectors/direct_scrapers/watchporn.py index b95b6e9..078ff69 100644 --- a/app/connectors/direct_scrapers/watchporn.py +++ b/app/connectors/direct_scrapers/watchporn.py @@ -34,6 +34,18 @@ _TAG_RE = re.compile(r'href="https://watchporn\.to/tags/([a-z0-9\-]+)/"[^>]*>([^ _CAT_RE = re.compile(r'href="https://watchporn\.to/categories/([a-z0-9\-]+)/"[^>]*>([^<]+)', re.IGNORECASE) _DUR_RE = re.compile(r'"duration"\s*:\s*"([^"]+)"') _UPLOAD_RE = re.compile(r'"uploadDate"\s*:\s*"([^"]+)"') +_VIDEO_ID_RE = re.compile(r"/video/(\d+)/") + + +def _derive_thumb(scene_url: str) -> str | None: + """KVS trzyma poster pod stałym wzorem `contents/videos_screenshots// + /preview.jpg` (zweryfikowane). Fallback gdy detail page nie ma og:image, żeby + kafelek na liście miał miniaturkę OD RAZU (bez czekania na auto-enrich w SceneDetail).""" + m = _VIDEO_ID_RE.search(scene_url) + if not m: + return None + vid = int(m.group(1)) + return f"{_BASE}/contents/videos_screenshots/{vid // 1000 * 1000}/{vid}/preview.jpg" class WatchPornScraper(BaseBrowseScraper): @@ -82,6 +94,10 @@ class WatchPornScraper(BaseBrowseScraper): seen_t.add(slug) tags.append(RawTag(external_id=f"{self.sitetag}:tag:{slug}", name=name, slug=slug)) + thumbnail_url = ( + meta_content(detail_html, property="og:image") or _derive_thumb(scene_url) + ) + studio: RawStudio | None = None cm = _CAT_RE.search(detail_html) if cm: @@ -102,7 +118,10 @@ class WatchPornScraper(BaseBrowseScraper): tags=tags, playback_sources=[ RawPlaybackSource( - origin=f"tube:{self.sitetag}", page_url=scene_url, duration_sec=duration_sec + origin=f"tube:{self.sitetag}", + page_url=scene_url, + duration_sec=duration_sec, + thumbnail_url=thumbnail_url, ) ], )