"""latestpornvideo: odzyskanie miniatur, ktore nie dzialaja (2026-10-15). Scraper od dzis sam poprawia nowe wpisy (`better_thumb`), tu poprawiamy istniejace: - brak miniatury, - `pixhost.to/show/...` (strona podgladu zamiast obrazka), - obrazek pixhost usuniety (przekierowanie na /image/removed.png), - z `--imgds`: miniatury imgds.net (dawne ticdn.net), ktore daja 404. W kazdym z tych przypadkow zapasem jest plakat odtwarzacza lulu z wpisu. python scripts/fix_latestpornvideo_thumbs.py # podglad 20 wierszy python scripts/fix_latestpornvideo_thumbs.py --apply --limit 20000 [--imgds] Dlugie, na prodzie przez `docker compose run -d --rm worker python3 /srv/scripts/...`. """ from __future__ import annotations import argparse import logging import time import httpx import sqlalchemy as sa from app.connectors.direct_scrapers.latestpornvideo import better_thumb from app.db import session_scope log = logging.getLogger(__name__) def _imgds_missing(url: str) -> bool: try: r = httpx.head(url, headers={"User-Agent": "Mozilla/5.0"}, timeout=10.0, follow_redirects=True) except Exception: return False return r.status_code == 404 def run(apply: bool, limit: int, imgds: bool, sleep: float) -> dict[str, int]: c = {"checked": 0, "changed": 0, "unchanged": 0, "lost": 0} cond = ( "thumbnail_url IS NULL OR thumbnail_url LIKE '%pixhost%'" + (" OR thumbnail_url LIKE 'https://imgds.net/snaps/%'" if imgds else "") ) with session_scope() as s: rows = s.execute( sa.text( "SELECT id, page_url, thumbnail_url FROM playback_sources " "WHERE origin='tube:latestpornvideocom' AND dead_at IS NULL " f"AND ({cond}) ORDER BY id LIMIT :lim" ), {"lim": limit}, ).all() for pb_id, page_url, thumb in rows: c["checked"] += 1 candidate = thumb if thumb and thumb.startswith("https://imgds.net/snaps/") and _imgds_missing(thumb): candidate = None new = better_thumb(candidate, page_url, timeout=30.0) if new == thumb: c["unchanged"] += 1 elif not new: c["lost"] += 1 else: c["changed"] += 1 if c["changed"] <= 5: print(f"{page_url}: {thumb} -> {new}") if apply: with session_scope() as s: s.execute( sa.text("UPDATE playback_sources SET thumbnail_url=:u WHERE id=:id"), {"u": new[:2048], "id": pb_id}, ) s.commit() if c["checked"] % 200 == 0: log.info("lpv thumbs %s", c) time.sleep(sleep) return c def main() -> int: logging.basicConfig(level=logging.INFO) p = argparse.ArgumentParser() p.add_argument("--apply", action="store_true") p.add_argument("--limit", type=int, default=20) p.add_argument("--imgds", action="store_true") p.add_argument("--sleep", type=float, default=0.2) args = p.parse_args() print(run(args.apply, args.limit, args.imgds, args.sleep)) return 0 if __name__ == "__main__": raise SystemExit(main())