Save.TV: Kino-Highlights Erkennung statt Score-basiert, 62 echte Kinofilme identifiziert

This commit is contained in:
root 2026-03-17 15:14:28 +07:00
parent 2fae7af346
commit 63d2a64533

View file

@ -102,11 +102,10 @@ SYSTEM_PROMPT_EXTRA = """TV / Save.TV Tools:
- savetv_record: Nimmt einen Film per TelecastId auf - savetv_record: Nimmt einen Film per TelecastId auf
- get_savetv_status: Zeigt Archiv und geplante Aufnahmen - get_savetv_status: Zeigt Archiv und geplante Aufnahmen
Wenn der User nach Archiv-Filmen/Bewertung fragt, nutze get_savetv_archive_filme. Wenn der User nach Archiv-Filmen/Bewertung fragt, nutze get_savetv_archive_filme.
WICHTIG bei Archiv-Bewertung: Die Scores sind nur grobe Heuristiken (Sender, Highlight-Flag). WICHTIG bei Archiv-Bewertung: Das Tool liefert KINO-HIGHLIGHTS (echte Kinofilme, Klassiker,
Nutze DEIN eigenes Filmwissen um die wirklich guten Filme zu identifizieren! Schau die preisgekroente Filme) getrennt von deutschem Fernsehprogramm. Praesentiere dem User die
KOMPLETTE Liste durch auch Filme mit Score 50-55 koennen Meisterwerke sein (z.B. bekannte KINO-HIGHLIGHTS zuerst und erklaere kurz warum jeder Film sehenswert ist (Regisseur, Preise,
internationale Filme, Oscar-Gewinner, Klassiker). Sortiere nach DEINER Einschaetzung der Stars). Hebe DRINGEND ablaufende Kino-Highlights besonders hervor die muss er schnell sichern.
Filmqualitaet, nicht blind nach Score. Hebe besonders hervor: bald ablaufende gute Filme.
""" """
@ -406,61 +405,78 @@ DOKU_KEYWORDS = {
"gehirn unter strom", "gehirn unter strom",
} }
KNOWN_CINEMA = {
"gravity", "blood diamond", "dunkirk",
"die fabelhafte welt der amelie", "children of men",
"die üblichen verdächtigen", "mord im orient express",
"aviator", "12 monkeys", "bullet train", "salt",
"anatomie eines falls", "i, tonya", "die wannseekonferenz",
"die vögel", "gosford park",
"albert nobbs", "der mit dem wolf tanzt", "zeugin der anklage",
"crazy heart", "talk to me", "das massaker von katyn",
"fallende blätter", "das lehrerzimmer", "die aussprache",
"old henry", "unternehmen petticoat",
"die reise zum mittelpunkt der erde",
"tagebuch einer kammerzofe",
"deutschstunde", "disco boy",
"die kinder der seidenstraße",
"führer und verführer", "nur fliegen ist schöner",
"der mit dem wolf tanzt", "nightwatch",
"der dritte", "blind willow",
"the revenant", "lion", "undisputed",
"no turning back", "parker", "stirb langsam",
"shooter", "valerian", "the suicide squad",
"mile 22", "open range", "hot summer nights",
"local hero", "z for zachariah", "the good neighbor",
"the informer", "la coda del diavolo",
"ladykillers", "hi-lo country", "yalda",
"bad director", "powder girl",
}
def _score_archive_film(title, station, highlight, subtitle="", thema=""): ENGLISH_WORDS = {
"""Bewertet einen Archiv-Film heuristisch (0-100).""" "the", "of", "and", "in", "for", "from", "with", "on", "at",
"to", "is", "has", "men", "man", "last", "night", "day", "club",
"girl", "boy", "road", "way", "no", "dead", "kill", "out",
"black", "good", "old", "new", "one", "two", "fallen",
"international", "redemption", "revenge", "spirit",
}
def _is_known_cinema(title):
"""Prueft ob ein Film als bekannter Kinofilm erkannt wird."""
t = title.lower().strip()
for known in KNOWN_CINEMA:
if t.startswith(known) or t == known:
return True
words = set(re.findall(r'[a-z]+', t))
english_count = len(words & ENGLISH_WORDS)
if re.match(r'^[A-Za-z0-9:,\'\-\.\! ]+$', title) and english_count >= 2:
return True
return False
def _is_excluded(title):
"""Filtert Programmänderungen und Dokus."""
t = title.lower() t = title.lower()
s = station.lower()
if "programmänderung" in t: if "programmänderung" in t:
return -1 return True
for kw in DOKU_KEYWORDS: for kw in DOKU_KEYWORDS:
if kw in t: if kw in t:
return -1 return True
return False
score = 50
premium_stations = {"arte", "zdf", "das erste", "mdr", "swr", "ndr", "wdr", "br"}
action_stations = {"prosieben", "sat.1", "kabel 1", "vox", "rtl", "tele 5", "zdf_neo"}
if s in premium_stations:
score += 5
elif s in action_stations:
score += 3
if highlight:
score += 15
desc = (thema or subtitle or "").lower()
if len(desc) > 30:
score += 5
quality_hints = [
"oscar", "golden globe", "cannes", "berlinale", "venedig",
"preisgekrönt", "meisterwerk", "bestseller", "basiert auf",
]
for hint in quality_hints:
if hint in desc or hint in t:
score += 10
break
if any(c.isascii() and c.isalpha() for c in title) and not all(c.isascii() for c in title if c.isalpha()):
pass
elif re.search(r'[A-Z][a-z]+ [A-Z][a-z]+', title) and not re.search(r'[äöüÄÖÜß]', title):
score += 8
return score
def handle_get_savetv_archive_filme(**kw): def handle_get_savetv_archive_filme(**kw):
"""Alle fertigen Archiv-Filme holen, bewerten, deduplizieren, sortiert ausgeben.""" """Alle fertigen Archiv-Filme holen, in Kino vs. TV trennen, sortiert ausgeben."""
entries = _get_full_archive() entries = _get_full_archive()
if not entries: if not entries:
return "Keine Archiv-Eintraege gefunden." return "Keine Archiv-Eintraege gefunden."
films = []
seen_titles = {} seen_titles = {}
series_count = 0 series_count = 0
excluded_count = 0
for e in entries: for e in entries:
tc = e.get("STRTELECASTENTRY", {}) tc = e.get("STRTELECASTENTRY", {})
@ -470,63 +486,74 @@ def handle_get_savetv_archive_filme(**kw):
continue continue
title = tc.get("STITLE", "?") title = tc.get("STITLE", "?")
if _is_excluded(title):
excluded_count += 1
continue
station = tc.get("STVSTATIONNAME", "?") station = tc.get("STVSTATIONNAME", "?")
highlight = tc.get("BISHIGHLIGHT", False)
subtitle = tc.get("SSUBTITLE", "")
thema = tc.get("STHEMA", "")
date = tc.get("DSTARTDATE", "?")[:10]
days_left = int(tc.get("IDAYSLEFTBEFOREDELETE", 0)) days_left = int(tc.get("IDAYSLEFTBEFOREDELETE", 0))
tid = int(tc.get("ITELECASTID", 0)) tid = int(tc.get("ITELECASTID", 0))
is_cinema = _is_known_cinema(title)
score = _score_archive_film(title, station, highlight, subtitle, thema)
if score < 0:
continue
key = title.lower().strip() key = title.lower().strip()
if key in seen_titles: if key in seen_titles:
if days_left > seen_titles[key]["days_left"]: if days_left > seen_titles[key]["days_left"]:
seen_titles[key]["days_left"] = days_left seen_titles[key].update(days_left=days_left, tid=tid)
seen_titles[key]["date"] = date
seen_titles[key]["tid"] = tid
continue continue
seen_titles[key] = { seen_titles[key] = {
"title": title, "station": station, "date": date, "title": title, "station": station,
"days_left": days_left, "score": score, "tid": tid, "days_left": days_left, "tid": tid,
"highlight": highlight, "cinema": is_cinema,
} }
films = sorted(seen_titles.values(), key=lambda x: (-x["score"], x["days_left"])) all_films = list(seen_titles.values())
cinema = sorted(
total_archive = len(entries) [f for f in all_films if f["cinema"]],
urgent = sorted( key=lambda x: x["days_left"],
[f for f in films if f["days_left"] <= 7], )
key=lambda x: (x["days_left"], -x["score"]), tv_films = sorted(
[f for f in all_films if not f["cinema"]],
key=lambda x: x["days_left"],
) )
lines = [ lines = [
f"Save.TV Archiv-Bewertung: {len(films)} Filme " f"Save.TV Archiv: {len(all_films)} Filme "
f"(von {total_archive} Aufnahmen, {series_count} Serien-Episoden gefiltert)\n" f"({series_count} Serien, {excluded_count} Dokus/Spam gefiltert)\n"
] ]
if urgent: cinema_urgent = [f for f in cinema if f["days_left"] <= 7]
lines.append(f"DRINGEND — {len(urgent)} Filme laufen in <=7 Tagen ab:") cinema_safe = [f for f in cinema if f["days_left"] > 7]
for f in urgent:
if cinema_urgent:
lines.append( lines.append(
f" [{f['days_left']}d] {f['title'][:50]} | {f['station']} | TID {f['tid']}" f"KINO-HIGHLIGHTS DRINGEND — laufen bald ab, JETZT sichern:"
)
for f in cinema_urgent:
lines.append(
f" [{f['days_left']}d] {f['title']} ({f['station']})"
) )
lines.append("") lines.append("")
safe = [f for f in films if f["days_left"] > 7] if cinema_safe:
if safe: lines.append(f"KINO-HIGHLIGHTS ({len(cinema_safe)} Filme):")
for f in cinema_safe:
lines.append( lines.append(
f"ALLE FILME IM ARCHIV ({len(safe)}) — nutze dein Filmwissen " f" {f['title']} ({f['station']}, {f['days_left']}d)"
f"um die besten zu identifizieren:"
) )
for f in safe: lines.append("")
if tv_films:
tv_urgent = [f for f in tv_films if f["days_left"] <= 7]
tv_safe = [f for f in tv_films if f["days_left"] > 7]
lines.append( lines.append(
f" {f['title'][:50]} | {f['station']} | {f['days_left']}d" f"DEUTSCHE TV-FILME ({len(tv_films)}, "
f"davon {len(tv_urgent)} bald ablaufend):"
) )
for f in tv_urgent:
lines.append(f" [{f['days_left']}d] {f['title']} ({f['station']})")
if tv_safe:
lines.append(f" ... und {len(tv_safe)} weitere mit >7 Tagen")
return "\n".join(lines) return "\n".join(lines)