From 196f36372e12a7ad00381c33f4f05045bf9f8adb Mon Sep 17 00:00:00 2001 From: root Date: Sat, 25 Apr 2026 19:28:24 +0200 Subject: [PATCH] feat(savetv): Der Clou als geschuetzten Wunschfilm aufnehmen --- homelab-ai-bot/SAVETV_ENRICHER.md | 5 ++ homelab-ai-bot/tools/savetv.py | 55 ++++++++++++++++++- homelab-ai-bot/tools/savetv_country_filter.py | 1 + 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/homelab-ai-bot/SAVETV_ENRICHER.md b/homelab-ai-bot/SAVETV_ENRICHER.md index 682383d23..bdae2dade 100644 --- a/homelab-ai-bot/SAVETV_ENRICHER.md +++ b/homelab-ai-bot/SAVETV_ENRICHER.md @@ -37,6 +37,11 @@ Automatische KI-Anreicherung von Save.TV-Filmarchiv mit Beschreibungen, Darstell - **Erlaubt automatisch:** internationale Kinofilme aus USA/UK/Kanada/Australien/Japan/Südkorea/Hongkong mit passendem Genre oder klar erkennbarem Kino-Titel. - **Konsequenz:** Unbekannte RBB/MDR/hr/WDR/BR/SWR/ZDF/ARD/arte/ONE-Titel werden nicht mehr automatisch aufgenommen oder heruntergeladen, bis sie angereichert sind oder eindeutig als Kinofilm erkannt werden. +### 5. Wunschfilm: Der Clou +- **Wunschtitel:** `Der Clou` / `The Sting` (1973) +- **Automatik:** Wird im Save.TV-Scan immer automatisch aufgenommen, wenn der Titel eindeutig `Der Clou` oder `The Sting` ist. +- **Schutz gegen Fehlgriff:** Der einzelne Titel `Sting` wird nur akzeptiert, wenn Beschreibung/Untertitel auf Paul Newman, Robert Redford, Johnny Hooker, Gondorff, Lonnegan oder das 1930er-Setting verweisen. Dadurch wird `Sting` (2024, Spinnen-Horror) nicht erneut als `Der Clou` behandelt. + ## Erfahrungen / Gotchas - `qwen2.5:14b` ist zuverlässiger für JSON-Output als `qwen3:30b-a3b` diff --git a/homelab-ai-bot/tools/savetv.py b/homelab-ai-bot/tools/savetv.py index 51adffc71..72a6c3fa6 100644 --- a/homelab-ai-bot/tools/savetv.py +++ b/homelab-ai-bot/tools/savetv.py @@ -43,6 +43,28 @@ DOWNLOAD_FORMAT_SD = 5 AUTO_RECORD_SCORE = 80 SUGGEST_SCORE = 60 +WISHLIST_MOVIES = [ + { + "name": "Der Clou", + "title_patterns": [ + r"\bder\s+clou\b", + r"\bthe\s+sting\b", + ], + # "Sting" alleine ist mehrdeutig; nur mit inhaltlichem Treffer aufnehmen. + "ambiguous_title_patterns": [ + r"\bsting\b", + ], + "required_context_patterns": [ + r"\bpaul\s+newman\b", + r"\brobert\s+redford\b", + r"\bjohnny\s+hooker\b", + r"\bgondorff\b", + r"\blonnegan\b", + r"\b1930\b", + ], + }, +] + SPAM_SUBCATEGORIES = { "teleshop", "shopping", "dauerwerbesendung", "volksmusik", "casting", "reality", "quiz/spiel", "comic", "zeichentrick", @@ -353,6 +375,11 @@ def _filter_films(telecasts, only_new=False): if is_highlight: score += 10 + wishlist_match = _wishlist_match(tc) + if wishlist_match: + score = max(score, 100) + tc["_wishlist_match"] = wishlist_match + tc["_score"] = score tc["_start_dt"] = start_dt films.append(tc) @@ -372,6 +399,23 @@ def _mark_seen(films): _save_seen(seen) +def _wishlist_match(tc): + """Gibt den Wunschtitel zurueck, wenn eine Sendung sicher passt.""" + haystack = " ".join( + str(tc.get(k) or "") + for k in ("STITLE", "STHEMA", "SFULLSUBTITLE", "SDESCRIPTION") + ).lower() + title = str(tc.get("STITLE") or "").lower() + for movie in WISHLIST_MOVIES: + for pattern in movie["title_patterns"]: + if re.search(pattern, title, re.IGNORECASE): + return movie["name"] + if any(re.search(p, title, re.IGNORECASE) for p in movie["ambiguous_title_patterns"]): + if any(re.search(p, haystack, re.IGNORECASE) for p in movie["required_context_patterns"]): + return movie["name"] + return None + + def _record_telecast(telecast_id): """Aufnahme anlegen.""" s = _get_session() @@ -734,12 +778,13 @@ def get_new_films(): suggestions = [] for f in films: + wishlist_match = f.get("_wishlist_match") allow_auto, quality_reason = savetv_country_filter.classify_auto_quality( f.get("STITLE", ""), f.get("STVSTATIONNAME", ""), filminfo_cache, ) - if not allow_auto: + if not allow_auto and not wishlist_match: log.info("Auto-Aufnahme übersprungen: %s (%s)", f.get("STITLE"), quality_reason) continue @@ -756,8 +801,12 @@ def get_new_films(): result = _record_telecast(tid) f["_record_result"] = result auto_recorded.append(f) - log.info("Auto-Aufnahme: %s (Score %d) -> %s", - f.get("STITLE"), score, result) + if wishlist_match: + log.info("Wunschfilm-Aufnahme (%s): %s -> %s", + wishlist_match, f.get("STITLE"), result) + else: + log.info("Auto-Aufnahme: %s (Score %d) -> %s", + f.get("STITLE"), score, result) else: suggestions.append(f) diff --git a/homelab-ai-bot/tools/savetv_country_filter.py b/homelab-ai-bot/tools/savetv_country_filter.py index 53b550b1b..73105ab2f 100644 --- a/homelab-ai-bot/tools/savetv_country_filter.py +++ b/homelab-ai-bot/tools/savetv_country_filter.py @@ -83,6 +83,7 @@ _KNOWN_CINEMA_TITLE = { "blacklight", "blade runner", "bodyguard", "bohemian rhapsody", "bourne", "braveheart", "carlito", "casino", "chinatown", "colombiana", "contraband", "crank", "deadpool", "der staatsfeind", + "der clou", "the sting", "die bourne identität", "die bourne identitaet", "das vermächtnis", "das vermaechtnis", "g20", "green zone", "hitman", "manchurian", "network", "stirb langsam", "the nice guys", "tom clancy",