From 53b63ee8fea35ab8b3af5bea8bbbf8b21e18d60f Mon Sep 17 00:00:00 2001 From: Homelab Cursor Date: Sat, 28 Mar 2026 12:59:27 +0100 Subject: [PATCH] savetv: Hetzner-Speicherindikator im Archiv, Datumssortierung Downloads --- homelab-ai-bot/savetv_web.py | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/homelab-ai-bot/savetv_web.py b/homelab-ai-bot/savetv_web.py index 8b18351b..90def214 100644 --- a/homelab-ai-bot/savetv_web.py +++ b/homelab-ai-bot/savetv_web.py @@ -486,15 +486,24 @@ function buildDetails(d) { return metaLine + descLine + crewLine; } +var storedSet = new Set(); + +function normTitle(s) { + return s.replace(/[^\w\s]/g, ' ').replace(/\s+/g, ' ').trim().toLowerCase(); +} + async function loadFilms() { var resp = await fetch('/api/films'); var data = await resp.json(); allFilms = data.films; downloads = data.downloads || {}; + (data.stored_titles || []).forEach(function(t) { storedSet.add(t); }); document.getElementById('loading').style.display = 'none'; document.getElementById('content').style.display = 'block'; + var storedCount = 0; + allFilms.forEach(function(f) { if (storedSet.has(normTitle(f.title))) storedCount++; }); document.getElementById('header-stats').textContent = - data.total + ' Aufnahmen \u00b7 ' + data.kino + ' Kino \u00b7 ' + data.urgent + ' dringend'; + data.total + ' Aufnahmen \u00b7 ' + data.kino + ' Kino \u00b7 ' + data.urgent + ' dringend \u00b7 ' + storedCount + ' gespeichert'; renderFilms(); var hasRunning = Object.values(downloads).some(function(v) { return v === 'running'; }); if (hasRunning) startPolling(); @@ -546,13 +555,18 @@ function filmCard(f) { var daysClass = f.days_left <= 3 ? 'days-urgent' : 'days-ok'; var daysLabel = f.days_left === 0 ? 'heute' : f.days_left === 1 ? '1 Tag' : f.days_left + ' Tage'; + var isStored = storedSet.has(normTitle(f.title)); + var cardClass = 'film-card'; if (sel) cardClass += ' selected'; - if (dlState === 'done') cardClass += ' downloaded'; + if (dlState === 'done' || isStored) cardClass += ' downloaded'; if (dlState === 'running') cardClass += ' downloading'; var statusEl = '
' + (sel ? '\u2713' : '') + '
'; var extraLine = ''; + if (isStored && dlState !== 'running') { + statusEl = '
\ud83d\udcbe
'; + } if (dlState === 'running') { var prog = dlProgress[String(f.tid)]; statusEl = '
\u2b07
'; @@ -733,12 +747,23 @@ def api_films(): films = sorted(seen_titles.values(), key=lambda x: x.get("start_date", ""), reverse=True) dl_log = _load_download_log() + import re as _re + def _norm_title(s): + return _re.sub(r'\s+', ' ', _re.sub(r'[^\w\s]', ' ', s)).strip().lower() + + stored_norms = set() + for fp in DOWNLOAD_DIR.iterdir(): + if fp.suffix == ".mp4" and fp.stat().st_size > 1_000_000: + raw = fp.stem.rsplit(" (", 1)[0] + stored_norms.add(_norm_title(raw)) + return jsonify({ "films": films, "total": len(entries), "kino": sum(1 for f in films if f["cinema"]), "urgent": sum(1 for f in films if f["days_left"] <= 7), "downloads": dl_log, + "stored_titles": list(stored_norms), })