Save.TV: Archiv-Bewertung Tool + _get_archive POST-Fix
This commit is contained in:
parent
51abcb06eb
commit
7ac401c3a5
1 changed files with 206 additions and 9 deletions
|
|
@ -68,6 +68,17 @@ TOOLS = [
|
||||||
"parameters": {"type": "object", "properties": {}, "required": []},
|
"parameters": {"type": "object", "properties": {}, "required": []},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "get_savetv_archive_filme",
|
||||||
|
"description": "Save.TV Archiv-Filme bewerten: Alle fertigen Aufnahmen holen, "
|
||||||
|
"nach Qualitaet bewerten, deduplizieren. Zeigt Top-Filme, dringende "
|
||||||
|
"(bald ablaufend) und weitere. Nutze bei 'gute Filme im Archiv', "
|
||||||
|
"'welche Filme habe ich', 'was ist sehenswert', 'Archiv bewerten'.",
|
||||||
|
"parameters": {"type": "object", "properties": {}, "required": []},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": {
|
"function": {
|
||||||
|
|
@ -87,9 +98,10 @@ TOOLS = [
|
||||||
|
|
||||||
SYSTEM_PROMPT_EXTRA = """TV / Save.TV Tools:
|
SYSTEM_PROMPT_EXTRA = """TV / Save.TV Tools:
|
||||||
- get_savetv_tipps: Zeigt sehenswerte Spielfilme der naechsten Tage/Wochen
|
- get_savetv_tipps: Zeigt sehenswerte Spielfilme der naechsten Tage/Wochen
|
||||||
|
- get_savetv_archive_filme: Bewertet alle fertigen Aufnahmen im Archiv nach Qualitaet
|
||||||
- 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 einen Film aufnehmen will, nutze savetv_record mit der TelecastId.
|
Wenn der User nach Archiv-Filmen/Bewertung fragt, nutze get_savetv_archive_filme.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -159,17 +171,21 @@ def _save_seen(seen):
|
||||||
|
|
||||||
|
|
||||||
def _get_archive(state=0, count=20):
|
def _get_archive(state=0, count=20):
|
||||||
"""Archiv abrufen. state: 0=geplant, 1=fertig."""
|
"""Archiv abrufen (POST, wie Web-UI). state: 0=geplant, 1=fertig."""
|
||||||
s = _get_session()
|
s = _get_session()
|
||||||
if not s:
|
if not s:
|
||||||
return {"error": "Login fehlgeschlagen"}
|
return {"error": "Login fehlgeschlagen"}
|
||||||
try:
|
try:
|
||||||
r = s.get(
|
end = datetime.now().strftime("%Y-%m-%d")
|
||||||
|
start = (datetime.now() - timedelta(days=60)).strftime("%Y-%m-%d")
|
||||||
|
r = s.post(
|
||||||
SAVETV_URL + "/STV/M/obj/archive/JSON/VideoArchiveApi.cfm",
|
SAVETV_URL + "/STV/M/obj/archive/JSON/VideoArchiveApi.cfm",
|
||||||
params={
|
data={
|
||||||
"bAggregateEntries": "false",
|
"bAggregateEntries": "false",
|
||||||
"iEntriesPerPage": str(count),
|
"iEntriesPerPage": str(count),
|
||||||
"iRecordingState": str(state),
|
"iRecordingState": str(state),
|
||||||
|
"dStartdate": start,
|
||||||
|
"dEnddate": end,
|
||||||
},
|
},
|
||||||
headers={"X-Requested-With": "XMLHttpRequest"},
|
headers={"X-Requested-With": "XMLHttpRequest"},
|
||||||
timeout=15,
|
timeout=15,
|
||||||
|
|
@ -179,6 +195,40 @@ def _get_archive(state=0, count=20):
|
||||||
return {"error": str(e)}
|
return {"error": str(e)}
|
||||||
|
|
||||||
|
|
||||||
|
def _get_full_archive():
|
||||||
|
"""Alle fertigen Aufnahmen paginiert holen."""
|
||||||
|
s = _get_session()
|
||||||
|
if not s:
|
||||||
|
return []
|
||||||
|
end = datetime.now().strftime("%Y-%m-%d")
|
||||||
|
start = (datetime.now() - timedelta(days=60)).strftime("%Y-%m-%d")
|
||||||
|
all_entries = []
|
||||||
|
for page in range(1, 20):
|
||||||
|
try:
|
||||||
|
r = s.post(
|
||||||
|
SAVETV_URL + "/STV/M/obj/archive/JSON/VideoArchiveApi.cfm",
|
||||||
|
data={
|
||||||
|
"bAggregateEntries": "false",
|
||||||
|
"iEntriesPerPage": "100",
|
||||||
|
"iCurrentPage": str(page),
|
||||||
|
"iRecordingState": "1",
|
||||||
|
"dStartdate": start,
|
||||||
|
"dEnddate": end,
|
||||||
|
},
|
||||||
|
headers={"X-Requested-With": "XMLHttpRequest"},
|
||||||
|
timeout=15,
|
||||||
|
)
|
||||||
|
data = r.json()
|
||||||
|
entries = data.get("ARRVIDEOARCHIVEENTRIES", [])
|
||||||
|
if not entries:
|
||||||
|
break
|
||||||
|
all_entries.extend(entries)
|
||||||
|
except Exception as e:
|
||||||
|
log.error("Archive page %d: %s", page, e)
|
||||||
|
break
|
||||||
|
return all_entries
|
||||||
|
|
||||||
|
|
||||||
def _scrape_epg():
|
def _scrape_epg():
|
||||||
"""Holt Filme aus Save.TV Programmseiten (JSON im HTML).
|
"""Holt Filme aus Save.TV Programmseiten (JSON im HTML).
|
||||||
|
|
||||||
|
|
@ -342,9 +392,154 @@ def _format_film(f, with_tid=True):
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
DOKU_KEYWORDS = {
|
||||||
|
"schlangen", "giftig", "gefährlich", "tiere", "tierwelt",
|
||||||
|
"wildtiere", "safari", "ozean", "meer", "ozeane",
|
||||||
|
"doku", "dokumentation", "reportage", "magazin",
|
||||||
|
"botschafter der meere", "dynastie", "leoparden",
|
||||||
|
"schildkröten", "wale", "australien", "afrika",
|
||||||
|
"gehirn unter strom",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _score_archive_film(title, station, highlight, subtitle="", thema=""):
|
||||||
|
"""Bewertet einen Archiv-Film heuristisch (0-100)."""
|
||||||
|
t = title.lower()
|
||||||
|
s = station.lower()
|
||||||
|
|
||||||
|
if "programmänderung" in t:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
for kw in DOKU_KEYWORDS:
|
||||||
|
if kw in t:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
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):
|
||||||
|
"""Alle fertigen Archiv-Filme holen, bewerten, deduplizieren, sortiert ausgeben."""
|
||||||
|
entries = _get_full_archive()
|
||||||
|
if not entries:
|
||||||
|
return "Keine Archiv-Eintraege gefunden."
|
||||||
|
|
||||||
|
films = []
|
||||||
|
seen_titles = {}
|
||||||
|
series_count = 0
|
||||||
|
|
||||||
|
for e in entries:
|
||||||
|
tc = e.get("STRTELECASTENTRY", {})
|
||||||
|
episode = tc.get("SFOLGE", "")
|
||||||
|
if episode:
|
||||||
|
series_count += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
title = tc.get("STITLE", "?")
|
||||||
|
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))
|
||||||
|
tid = int(tc.get("ITELECASTID", 0))
|
||||||
|
|
||||||
|
score = _score_archive_film(title, station, highlight, subtitle, thema)
|
||||||
|
if score < 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
key = title.lower().strip()
|
||||||
|
if key in seen_titles:
|
||||||
|
if days_left > seen_titles[key]["days_left"]:
|
||||||
|
seen_titles[key]["days_left"] = days_left
|
||||||
|
seen_titles[key]["date"] = date
|
||||||
|
seen_titles[key]["tid"] = tid
|
||||||
|
continue
|
||||||
|
|
||||||
|
seen_titles[key] = {
|
||||||
|
"title": title, "station": station, "date": date,
|
||||||
|
"days_left": days_left, "score": score, "tid": tid,
|
||||||
|
"highlight": highlight,
|
||||||
|
}
|
||||||
|
|
||||||
|
films = sorted(seen_titles.values(), key=lambda x: (-x["score"], x["days_left"]))
|
||||||
|
|
||||||
|
total_archive = len(entries)
|
||||||
|
urgent = sorted(
|
||||||
|
[f for f in films if f["days_left"] <= 7],
|
||||||
|
key=lambda x: (x["days_left"], -x["score"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
lines = [
|
||||||
|
f"Save.TV Archiv-Bewertung: {len(films)} Filme "
|
||||||
|
f"(von {total_archive} Aufnahmen, {series_count} Serien-Episoden gefiltert)\n"
|
||||||
|
]
|
||||||
|
|
||||||
|
if urgent:
|
||||||
|
lines.append(f"DRINGEND — {len(urgent)} Filme laufen in <=7 Tagen ab:")
|
||||||
|
for f in urgent:
|
||||||
|
hl = " *" if f["highlight"] else ""
|
||||||
|
lines.append(
|
||||||
|
f" [{f['days_left']}d] {f['title'][:45]} | {f['station']} | "
|
||||||
|
f"Score {f['score']}{hl} | TID {f['tid']}"
|
||||||
|
)
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
|
top = [f for f in films if f["score"] >= 60 and f["days_left"] > 7]
|
||||||
|
if top:
|
||||||
|
lines.append(f"TOP-FILME ({len(top)}):")
|
||||||
|
for f in top[:30]:
|
||||||
|
hl = " *" if f["highlight"] else ""
|
||||||
|
lines.append(
|
||||||
|
f" {f['title'][:45]:45s} | {f['station']:12s} | "
|
||||||
|
f"{f['date']} | {f['days_left']:2d}d | Score {f['score']}{hl}"
|
||||||
|
)
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
|
rest = [f for f in films if f["score"] < 60 and f["days_left"] > 7]
|
||||||
|
if rest:
|
||||||
|
lines.append(f"WEITERE ({len(rest)}):")
|
||||||
|
for f in rest[:20]:
|
||||||
|
lines.append(
|
||||||
|
f" {f['title'][:45]:45s} | {f['station']:12s} | "
|
||||||
|
f"{f['date']} | {f['days_left']:2d}d"
|
||||||
|
)
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
def handle_get_savetv_status(**kw):
|
def handle_get_savetv_status(**kw):
|
||||||
archive = _get_archive(state=1, count=5)
|
archive = _get_archive(state=1, count=20)
|
||||||
planned = _get_archive(state=0, count=10)
|
planned = _get_archive(state=0, count=20)
|
||||||
|
|
||||||
if "error" in archive:
|
if "error" in archive:
|
||||||
return "Save.TV Fehler: " + archive["error"]
|
return "Save.TV Fehler: " + archive["error"]
|
||||||
|
|
@ -352,12 +547,13 @@ def handle_get_savetv_status(**kw):
|
||||||
lines = ["Save.TV Status\n"]
|
lines = ["Save.TV Status\n"]
|
||||||
|
|
||||||
total = int(archive.get("ITOTALENTRIESINARCHIVE", 0))
|
total = int(archive.get("ITOTALENTRIESINARCHIVE", 0))
|
||||||
lines.append("Archiv: " + str(total) + " Aufnahmen gesamt")
|
fertig_total = int(archive.get("ITOTALENTRIES", 0))
|
||||||
|
lines.append(f"Archiv: {total} Aufnahmen gesamt, {fertig_total} fertig")
|
||||||
|
|
||||||
fertig = archive.get("ARRVIDEOARCHIVEENTRIES", [])
|
fertig = archive.get("ARRVIDEOARCHIVEENTRIES", [])
|
||||||
if fertig:
|
if fertig:
|
||||||
lines.append("\nLetzte fertige Aufnahmen:")
|
lines.append("\nLetzte fertige Aufnahmen:")
|
||||||
for e in fertig[:5]:
|
for e in fertig[:10]:
|
||||||
tc = e.get("STRTELECASTENTRY", {})
|
tc = e.get("STRTELECASTENTRY", {})
|
||||||
lines.append(
|
lines.append(
|
||||||
" " + tc.get("STITLE", "?")[:40] + " | "
|
" " + tc.get("STITLE", "?")[:40] + " | "
|
||||||
|
|
@ -368,7 +564,7 @@ def handle_get_savetv_status(**kw):
|
||||||
geplant = planned.get("ARRVIDEOARCHIVEENTRIES", [])
|
geplant = planned.get("ARRVIDEOARCHIVEENTRIES", [])
|
||||||
plan_total = int(planned.get("ITOTALENTRIES", 0))
|
plan_total = int(planned.get("ITOTALENTRIES", 0))
|
||||||
if geplant:
|
if geplant:
|
||||||
lines.append("\nGeplante Aufnahmen (" + str(plan_total) + "):")
|
lines.append(f"\nGeplante Aufnahmen ({plan_total}):")
|
||||||
for e in geplant[:10]:
|
for e in geplant[:10]:
|
||||||
tc = e.get("STRTELECASTENTRY", {})
|
tc = e.get("STRTELECASTENTRY", {})
|
||||||
lines.append(
|
lines.append(
|
||||||
|
|
@ -455,5 +651,6 @@ def handle_savetv_record(telecast_id=0, **kw):
|
||||||
HANDLERS = {
|
HANDLERS = {
|
||||||
"get_savetv_status": handle_get_savetv_status,
|
"get_savetv_status": handle_get_savetv_status,
|
||||||
"get_savetv_tipps": handle_get_savetv_tipps,
|
"get_savetv_tipps": handle_get_savetv_tipps,
|
||||||
|
"get_savetv_archive_filme": handle_get_savetv_archive_filme,
|
||||||
"savetv_record": handle_savetv_record,
|
"savetv_record": handle_savetv_record,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue