"""Czysci tytuly filmow z naglowka nowego motywu dooplay (10.2026) i scala duplikaty. Motyw mangoporn/streamporn.li wstawia do h1 "Watch TYTUL 2026 by STUDIO Porn Movie Online Free" albo "Now Playing: TYTUL". Parser od 2026-10-15 bierze tytul z okruszkow, ten skrypt poprawia to, co weszlo wczesniej: - "Now Playing: X" -> "X" (zawsze naglowek, nigdy prawdziwy tytul), - "Watch X RRRR by S Porn Movie Online Free" -> "X" (tylko z tym ogonem; "Watch Me Eat My Creampie 5" to prawdziwy tytul i zostaje), - "Play X" zostaje, bo bywa tytulem ("Play Time!"). Jesli po poprawce istnieje juz inny film o tym samym title_normalized i zgodnym roku (rowny albo jeden pusty), poprawiany film jest do niego dolaczany (merge_movies, starszy zostaje). Wiecej niz jedno trafienie = tylko poprawka tytulu, bez scalania. python scripts/fix_dooplay_junk_titles.py # podglad python scripts/fix_dooplay_junk_titles.py --apply """ from __future__ import annotations import argparse import logging import re import sqlalchemy as sa from app.db import session_scope from app.models.movie import Movie from app.normalize.text import normalize from app.resolve.movie_merge import merge_movies log = logging.getLogger(__name__) _NOW_PLAYING_RE = re.compile(r"^Now\s+Playing:\s*(?P.+?)\s*$", re.IGNORECASE | re.DOTALL) _WATCH_TAIL_RE = re.compile( r"^Watch\s+(?P<title>.+?)(?:\s+(?:19|20)\d{2}\s+by\s+.+?)?\s+Porn\s+Movie\s+Online\s+Free\s*$", re.IGNORECASE | re.DOTALL, ) def clean_title(title: str) -> str | None: for rx in (_NOW_PLAYING_RE, _WATCH_TAIL_RE): m = rx.match(title) if m and m.group("title").strip(): return m.group("title").strip() return None def run(apply: bool) -> dict[str, int]: counters = {"candidates": 0, "retitled": 0, "merged": 0, "ambiguous": 0} with session_scope() as session: rows = session.execute( sa.select(Movie.id, Movie.title, Movie.release_year).where( sa.or_( Movie.title.op("~*")(r"^now playing:"), Movie.title.op("~*")(r"^watch .+ porn movie online free\s*$"), ) ) ).all() for movie_id, title, year in rows: new_title = clean_title(title) if not new_title: continue counters["candidates"] += 1 norm = normalize(new_title) twins = session.execute( sa.select(Movie.id, Movie.release_year, Movie.created_at) .where(Movie.title_normalized == norm, Movie.id != movie_id) .order_by(Movie.created_at) ).all() twins = [t for t in twins if t.release_year is None or year is None or t.release_year == year] print(f"{title[:70]!r} -> {new_title[:60]!r} twins={len(twins)}") if not apply: continue movie = session.get(Movie, movie_id) movie.title = new_title[:512] movie.title_normalized = norm[:512] counters["retitled"] += 1 if len(twins) == 1: merge_movies(session, keep_id=twins[0].id, drop_id=movie_id, resolved_by="fix_dooplay_junk_titles") counters["merged"] += 1 elif len(twins) > 1: counters["ambiguous"] += 1 session.commit() return counters def main() -> int: logging.basicConfig(level=logging.INFO) p = argparse.ArgumentParser() p.add_argument("--apply", action="store_true") args = p.parse_args() print(run(args.apply)) return 0 if __name__ == "__main__": raise SystemExit(main())