"""Hentaimama: ogon w tytulach i brakujace miniatury (2026-10-15). 1. Tytuly: od ~31.08.2026 og:title mial ogon "TYTUL - Watch Online Free in HD - Hentaimama" i tak weszlo ok. 100 scen. Scraper juz go ucina, tu poprawiamy istniejace (title i title_normalized). 2. Miniatury: ok. 2100 zrodel z pierwszego przebiegu (12.08) nie ma thumbnail_url, a te sceny nie maja innego zrodla z obrazkiem. Strony maja og:image, pobieramy je po kolei. python scripts/fix_hentaimama_titles_thumbs.py # podglad python scripts/fix_hentaimama_titles_thumbs.py --apply [--limit N] [--sleep 0.5] Dlugie, wiec na prodzie przez `docker compose run -d --rm worker python3 scripts/...` (z pliku, nie przez stdin). """ from __future__ import annotations import argparse import html as html_mod import logging import time import sqlalchemy as sa from app.connectors.direct_scrapers.hentaimama import _OG_IMAGE_RE, _TITLE_TAIL_RE from app.db import session_scope from app.extractors._fetch import fetch_tube_html from app.normalize.text import normalize log = logging.getLogger(__name__) def fix_titles(apply: bool) -> int: n = 0 with session_scope() as session: rows = session.execute( sa.text("SELECT id, title FROM scenes WHERE title ~* 'hentaimama\\s*$'") ).all() for scene_id, title in rows: new = _TITLE_TAIL_RE.sub("", title).strip() if not new or new == title: continue n += 1 if n <= 5: print(f"{title!r} -> {new!r}") if apply: session.execute( sa.text("UPDATE scenes SET title=:t, title_normalized=:n WHERE id=:id"), {"t": new[:512], "n": normalize(new)[:512], "id": scene_id}, ) if apply: session.commit() return n def fix_thumbs(apply: bool, limit: int, sleep: float) -> dict[str, int]: c = {"checked": 0, "filled": 0, "no_image": 0, "fetch_fail": 0} with session_scope() as session: rows = session.execute( sa.text( "SELECT id, page_url FROM playback_sources WHERE origin='tube:hentaimama' " "AND thumbnail_url IS NULL AND dead_at IS NULL ORDER BY id LIMIT :lim" ), {"lim": limit}, ).all() for pb_id, page_url in rows: c["checked"] += 1 try: page = fetch_tube_html(page_url, timeout=30.0) except Exception as e: c["fetch_fail"] += 1 log.info("fetch %s: %s", page_url, e) time.sleep(sleep) continue m = _OG_IMAGE_RE.search(page) if not m: c["no_image"] += 1 else: img = html_mod.unescape(m.group(1)).strip() if apply: with session_scope() as session: session.execute( sa.text("UPDATE playback_sources SET thumbnail_url=:u WHERE id=:id"), {"u": img[:2048], "id": pb_id}, ) session.commit() c["filled"] += 1 if c["filled"] <= 3: print(page_url, "->", img) if c["checked"] % 100 == 0: log.info("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=5) p.add_argument("--sleep", type=float, default=0.5) p.add_argument("--skip-titles", action="store_true") args = p.parse_args() if not args.skip_titles: print("titles:", fix_titles(args.apply)) print("thumbs:", fix_thumbs(args.apply, args.limit, args.sleep)) return 0 if __name__ == "__main__": raise SystemExit(main())