From 0b495c3544f0625c4af4c58c92641ad0f03c2b09 Mon Sep 17 00:00:00 2001 From: orbitalo Date: Fri, 27 Mar 2026 12:27:58 +0000 Subject: [PATCH] feat: Web-UI zeigt KI-Filmbeschreibungen, Darsteller und Regisseur MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Die filmCard-Funktion rendert jetzt die angereicherten Daten: - 3-6 Sätze Beschreibung - Hauptdarsteller + Regisseur - Land, Jahr, Genre als Metadaten-Zeile --- homelab-ai-bot/savetv_web.py | 68 ++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/homelab-ai-bot/savetv_web.py b/homelab-ai-bot/savetv_web.py index 25b7f4bd..b51bbc43 100644 --- a/homelab-ai-bot/savetv_web.py +++ b/homelab-ai-bot/savetv_web.py @@ -197,15 +197,26 @@ HTML = r""" flex-wrap: wrap; align-items: center; } - .film-info { - color: var(--muted); - font-size: 14px; - margin-top: 6px; - font-style: italic; + .film-details { + color: #9898b8; + font-size: 13.5px; + margin-top: 8px; + line-height: 1.5; opacity: 0; transition: opacity .4s; } - .film-info.loaded { opacity: 1; } + .film-details.loaded { opacity: 1; } + .film-desc { + color: #a8a8c4; + font-size: 13.5px; + line-height: 1.55; + margin-top: 6px; + } + .film-crew { + color: #8888a8; + font-size: 12.5px; + margin-top: 5px; + } .days-badge { font-size: 14px; font-weight: 600; @@ -427,6 +438,12 @@ let infoLoading = false; let dlProgress = {}; let polling = false; +function esc(s) { + var d = document.createElement('div'); + d.textContent = s; + return d.innerHTML; +} + async function loadFilmInfo(films) { if (infoLoading) return; var missing = films.filter(function(f) { return !filmInfoCache[f.tid]; }); @@ -443,20 +460,32 @@ async function loadFilmInfo(films) { missing.forEach(function(f) { var d = data[f.title]; if (!d) return; - var parts = []; - if (d.year) parts.push(d.year); - if (d.countries && d.countries.length) parts.push(d.countries.join('/')); - if (d.genres && d.genres.length) parts.push(d.genres.join(', ')); - if (parts.length) { - filmInfoCache[f.tid] = parts.join(' \u00b7 '); - var el = document.getElementById('info-' + f.tid); - if (el) { el.textContent = filmInfoCache[f.tid]; el.classList.add('loaded'); } + filmInfoCache[f.tid] = d; + var el = document.getElementById('details-' + f.tid); + if (el) { + el.innerHTML = buildDetails(d); + el.classList.add('loaded'); } }); } catch(e) {} infoLoading = false; } +function buildDetails(d) { + if (!d) return ''; + var parts = []; + if (d.year) parts.push(esc(d.year)); + if (d.countries && d.countries.length) parts.push(esc(d.countries.join('/'))); + if (d.genres && d.genres.length) parts.push(esc(d.genres.join(', '))); + var metaLine = parts.length ? '
' + parts.join(' \u00b7 ') + '
' : ''; + var descLine = d.description ? '
' + esc(d.description) + '
' : ''; + var crewParts = []; + if (d.actors && d.actors.length) crewParts.push('Mit ' + esc(d.actors.join(', '))); + if (d.director) crewParts.push('Regie: ' + esc(d.director)); + var crewLine = crewParts.length ? '
' + crewParts.join(' \u00b7 ') + '
' : ''; + return metaLine + descLine + crewLine; +} + async function loadFilms() { var resp = await fetch('/api/films'); var data = await resp.json(); @@ -542,18 +571,19 @@ function filmCard(f) { extraLine = '
Gespeichert
'; } - var infoText = filmInfoCache[f.tid] || ''; - var infoClass = infoText ? 'film-info loaded' : 'film-info'; + var cached = filmInfoCache[f.tid]; + var detailsHtml = cached ? buildDetails(cached) : ''; + var detailsClass = detailsHtml ? 'film-details loaded' : 'film-details'; return '
' + statusEl - + '
' + f.title + '
' + + '
' + esc(f.title) + '
' + '
' - + '' + f.station + '' + + '' + esc(f.station) + '' + '' + (f.cinema ? 'Kino' : 'TV') + '' + '' + daysLabel + '' + '
' - + '
' + infoText + '
' + + '
' + detailsHtml + '
' + extraLine + '
'; }