Bisher lieferte Flask Medien mit no-cache aus; der Player musste jede Datei
bei jeder Anzeige neu anfragen. Versionierte URLs duerfen jetzt ein Jahr
ohne Rueckfrage aus dem Cache kommen, unversionierte bleiben unveraendert.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Der Filter in delete_file verglich nur item["url"], traf damit aber nur
URL-Eintraege. Bei Dateien wurde die Datei vom Datentraeger geloescht,
der Eintrag {"name": ...} blieb als Karteileiche in der config.json
stehen - in der Priority-Playlist wie in jeder Screen-Playlist.
Vergleich laeuft jetzt ueber playlist_item_name(), das alle drei
Eintragsformen abdeckt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Priority-Playlist gilt fuer alle Screens eines Standorts, liegt aber
in einem eigenen Menuepunkt und wurde beim Bearbeiten der normalen
Playlisten leicht uebersehen. Sie erscheint jetzt oberhalb jeder
Screen-Playlist als abgesetzte, ausgegraute Liste mit Prio-Badge.
Reine Anzeige: keine Checkbox, keine Buttons, kein Drag. Die Zeilen
liegen bewusst in einer eigenen ul ausserhalb von #playlist-<screen>,
damit savePlaylist() sie nicht mit einsammelt. Sichtbar nur, wenn die
Priority-Playlist des Standorts aktiviert ist.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Admin-Ansicht hat der Checkbox das Ergebnis von is_item_active()
uebergeben. Ausserhalb des Zeitfensters erschien ein zeitgesteuerter
Eintrag dadurch als deaktiviert, und beim naechsten Speichern der
Reihenfolge schrieb der Client diesen Anzeigezustand als enabled=false
zurueck - der Eintrag war danach dauerhaft stillgelegt.
Die Checkbox spiegelt jetzt das gespeicherte enabled-Flag. Der
Live-Zustand steckt in einem neuen Feld active und faerbt nur noch das
Zeit-Badge (grau, wenn das Fenster gerade zu ist). Der Player filtert
entsprechend ueber beide Felder.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Dropdown fuer die Merk-Dauer aktiviert jetzt die Checkbox mit; bisher
wurde die Auswahl ohne gesetzten Haken verworfen und trotzdem nach
jedem Login ein Code verlangt.
- Abgelaufene oder defekte Trusted-Device-Eintraege fuehrten beim Login
zu einem NameError (users_data war nicht geladen); Bereinigung neu
geschrieben.
- Cookie erhaelt das Secure-Flag, wenn die Verbindung HTTPS ist.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Wer von Stuttgart aus das Admin-Dashboard oeffnete, sah im Header
ploetzlich Karlsruhe - und landete beim Zurueckgehen ueber die
Standortauswahl dort. Grund: Dashboard, Hilfe, User-Verwaltung und die
MFA-Seiten setzten current_site fest auf get_site_list(cfg)[0], also den
global ersten Standort. Der Context-Processor tat dasselbe, fuer
angemeldete User sogar unabhaengig davon, ob sie auf diesen Standort
ueberhaupt zugreifen duerfen.
- remember_site() legt den zuletzt besuchten Standort in der Session ab;
aufgerufen aus admin(), admin_priority() und add_customer().
- current_site_for() liefert diesen Standort, sonst den ersten
*zugaenglichen*. Verwendet vom Context-Processor und den genannten
Seiten.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Enthaelt die Migration der Priority-Playlist: der globale Schluessel
"priority" ist entfallen, jeder Standort hat seinen eigenen Block.
Ausserdem aus dem laufenden Betrieb: der Standort "test" mit den Screens
"vorstand" und "casino", die Schalter "Willkommensseite hier anzeigen"
sowie Playlist-Eintraege. Der Phantom-Screen "test/logos" - entstanden,
weil der Ordner fuer hochgeladene Logos als Screen interpretiert wurde -
ist entfernt.
Keine neuen Zugangsdaten im Diff.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Priority-Playlist lag unter config["priority"] und wirkte damit auf
*alle* Standorte. In der Praxis lief so ein Stuttgart-spezifischer
Eintrag (wbxroompresence...find=Stuttgart) auch auf den Karlsruher
Screens.
Sie liegt jetzt unter sites.<site>.priority, die Medien unter
media/<site>/priority/:
- get_priority_config(cfg, site) liefert die Konfiguration des
Standorts. Ist dort nichts hinterlegt, wird ein globaler Altbestand
einmalig uebernommen - per deepcopy, damit spaetere Aenderungen nicht
zwischen Standorten durchschlagen.
- load_priority_files(site), priority_dir(site) sowie Player, Hash,
Upload, Loeschen, URL-Anlegen, Umsortieren und Einzeleintrag-
Bearbeitung arbeiten durchgaengig standortbezogen.
- Route /media/priority/<datei> -> /media/<site>/priority/<datei>,
Templates entsprechend.
- Der Ordnername "priority" ist wie "logos" in der Screen-Erkennung
ausgenommen. media/<site>/priority/ waere sonst als Screen in der
Konfiguration gelandet; "priority" ist in den Routen ohnehin als
Kennzeichen belegt, ein Screen dieses Namens war nie moeglich.
Migration der vorhandenen Konfiguration: der globale Block wurde in alle
drei Standorte uebernommen und der globale Schluessel entfernt. Der
leere globale Ordner media/priority/ ist entfallen.
README, AGENTS.md und Hilfeseite nachgezogen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Abgleich der Doku gegen den Code ergab:
- /admin/help und /customer fehlten in der Routen-Tabelle
- Der Verzeichnisbaum zeigte nur die Screen-Ordner, nicht die Dateien
auf Standort-Ebene (background.*, logo_<slot>.png, welcome.html) -
gerade die sind aber bewusst Dateien und keine Ordner, weil jeder
Unterordner als Screen interpretiert wird
- Der Docker-Abschnitt erwaehnte weder das noetige --build noch die
Log-Einstellungen (PYTHONUNBUFFERED, access-logfile), die fuer jede
Fehlersuche die Grundlage sind
AGENTS.md bekommt dazu einen Abschnitt "Betrieb / Diagnose".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
"Das System sucht automatisch nach den Kundenlogos und erstellt eine
angepasste Willkommensseite." stand bisher ganz unten bei den Angaben
zu Zielscreens und Markdown. Der Satz beschreibt aber, was mit den
eingegebenen Kundennamen passiert, und steht jetzt direkt darunter -
gefolgt vom Hinweis zum Logo-Upload und der bestehenden Trennlinie vor
"Anzeigen bis". Aus zwei Absaetzen wurde ein Satz.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Je Kundenspalte eine <hr class="mt-4 mb-3"> zwischen dem
Ansprechpartner-Feld und "Logo hochladen" - gleiche Gestaltung wie die
uebrigen Abschnittstrenner der Seite.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ein Neuladen der Willkommensseite - etwa beim Wechsel des Standorts -
leert alle <input type="file">. Die zuvor gewaehlte Datei ist damit weg,
ohne dass es auffaellt, und das Absenden erzeugt eine Willkommensseite
ohne das hochgeladene Logo.
Unter jedem Datei-Feld steht jetzt "Keine Datei gewählt" bzw. nach der
Auswahl Name und Groesse der Datei. Damit ist vor dem Absenden
erkennbar, ob wirklich etwas angehaengt ist.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ohne --access-logfile protokolliert gunicorn keine Requests. Im Log war
dadurch nicht erkennbar, ob eine Anfrage den Container ueberhaupt
erreicht - beim Nachstellen eines Upload-Problems fehlte damit die
grundlegendste Information.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ohne die Variable puffert Python stdout blockweise, sobald es kein
Terminal ist. Saemtliche print()-Ausgaben der App - darunter die
Diagnosezeilen zum Logo-Upload - erschienen dadurch nicht in
"docker compose logs", sondern blieben im Puffer haengen. In der
gesamten Log-Historie des Containers stand kein einziger APP.PY-Eintrag.
Tracebacks waren sichtbar, weil Flask sie ueber stderr ausgibt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Protokolliert je Kundenfeld, ob eine Datei angekommen ist. Ein
fehlendes enctype im Formular - etwa wenn der Browser eine aeltere
Fassung der Seite aus dem Cache liefert - sieht serverseitig sonst
genauso aus wie "kein Logo hochgeladen", und der Unterschied war aus
dem Log nicht erkennbar.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ein helles Logo auf hellem Grund liegt innerhalb der Farbtoleranz des
Flood Fill. Der Fuellvorgang lief vom Rand in das Logo hinein und
loeschte es mit - das Ergebnis war ein vollstaendig transparentes PNG,
auf der Willkommensseite also gar kein Logo. Ohne jede Rueckmeldung:
die bisherige Pruefung schlug nur an, wenn *nichts* entfernt wurde, nicht
wenn alles entfernt wurde.
remove_logo_background() legt jetzt vor dem Eingriff eine Kopie an und
misst danach ueber das Alpha-Histogramm, wie viel sichtbar geblieben
ist. Unter 2% gilt der Versuch als misslungen: das unveraenderte Bild
wird zurueckgegeben und die Oberflaeche nennt den Grund samt Auswegen
(transparentes PNG hochladen oder "Hintergrund behalten" ankreuzen).
Getestet mit Logos von dunkelrot bis reinweiss auf weissem Grund sowie
einem dunklen Logo auf schwarzem Grund.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Hochgeladene Logos landeten unter media/<site>/logos/. admin() behandelt
aber jeden Unterordner von media/<site>/ als Screen und schreibt ihn per
get_screen_config() dauerhaft in die Konfiguration. Der Logo-Ordner
erschien dadurch als Screen in der Oberflaeche, bekam beim Generieren
eine eigene welcome.html und liess sich wie ein Screen bespielen - und
die darin liegenden Logos wie Screen-Medien loeschen. Genau so ist eines
der hochgeladenen Logos verschwunden.
Logos liegen jetzt als media/<site>/logo_<slot>.png direkt im
Standort-Verzeichnis, so wie das Hintergrundbild als
media/<site>/background.* - aus demselben Grund. Die URL bleibt
/media/<site>/logos/<datei>, die Route liest aus dem
Standort-Verzeichnis; bestehende welcome.html funktionieren damit
unveraendert weiter.
Zusaetzlich wird der Ordnername "logos" bei der Screen-Erkennung
uebersprungen, damit Altbestaende nicht erneut als Screen auftauchen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ein hochgeladenes Logo erschien auf der Willkommensseite deutlich
kleiner als ein automatisch gefundenes. Ursache ist nicht die CSS -
beide nutzen dieselbe Klasse - sondern der Bildinhalt: nach dem
Freistellen ist der Rand zwar durchsichtig, zaehlt aber weiter zur
Bildflaeche. .customer-logo skaliert mit object-fit: contain auf 120px
Hoehe, ein Logo mit breitem Rand erscheint dadurch nur einen Bruchteil
davon gross (gemessen: 30px statt 120px). Brandfetch-Logos sind bereits
eng beschnitten und fuellen den Kasten aus.
trim_transparent_border() schneidet die durchsichtigen Raender nach dem
Freistellen weg. Greift auch bei bereits transparenten PNGs; bei
abgewaehltem Freistellen passiert nichts, da es dort keinen
transparenten Rand gibt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Willkommensseite ist je Standort identisch. Bisher musste man nach
dem Einschalten des Schalters "Willkommensseite hier anzeigen" erneut
generieren, damit sie auf dem Screen ankam - ein Handgriff ohne anderes
Ergebnis, und ohne Rueckmeldung, dass er noetig ist.
- sync_welcome_for_screen() kopiert beim Einschalten eine vorhandene
welcome.html in den Screen und setzt sie vorne in die Playlist; beim
Ausschalten werden Eintrag und Datei entfernt. Aufgerufen aus
update_screen(), nur wenn sich der Schalter wirklich aendert.
- save_welcome_page() legt zusaetzlich eine Standort-Kopie unter
media/<site>/welcome.html an, die nie geloescht wird. Ohne sie waere
nach dem Abschalten aller Screens keine Quelle mehr vorhanden und der
Schalter wuerde wieder stillschweigend nichts tun.
Nebenbei behoben: beim Generieren wurde welcome.html aus abgewaehlten
Screens nur aus der Playlist entfernt, die Datei blieb liegen. Bei
leerer Playlist spielt player() noch nicht verzeichnete Dateien aus dem
Ordner ab - die Begruessung waere dort also weiter zu sehen gewesen.
README, AGENTS.md und Hilfeseite nachgezogen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Mit read_only: true und ohne volumes lag /app vollstaendig auf einem
schreibgeschuetzten Dateisystem. Die App konnte weder history.json noch
config.json oder users.json schreiben und auch keine Medien ablegen -
Login endete mit OSError, Einstellungen und Willkommensseiten wurden
nicht gespeichert. Das README dokumentierte die Mounts bereits, die
Datei selbst hatte sie nie.
Zusaetzlich TZ=Europe/Berlin: is_item_active() wertet die Serverzeit
aus, ohne TZ laeuft der Container in UTC und alle Zeitfenster der
Playlist-Zeitsteuerung waeren um ein bis zwei Stunden verschoben.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Datei enthielt OPENAI_API_KEY und BRANDFETCH_API_KEY im Klartext und
war versioniert. Sie wurde lokal entfernt; der Loeschvorgang wird hier
nachgezogen und env.sh in .gitignore aufgenommen, damit sie nicht erneut
hineinrutscht.
Hinweis: Die Schluessel stehen weiterhin in der Repo-Historie und sollten
rotiert werden.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Findet die automatische Suche kein Logo, kann pro Kunde eine Bilddatei
hochgeladen werden. Ein Upload hat Vorrang vor der Suche.
Freistellen:
- remove_logo_background() entfernt den Hintergrund per Flood Fill von
den Bildraendern her. Bewusst kein globaler Farbvergleich - sonst
verschwindet auch Weiss innerhalb des Logos (etwa Text in einer
Flaeche). Weiche Kante gegen Treppeneffekte.
- Umgesetzt mit Pillow, das ueber qrcode[pil] ohnehin vorhanden ist.
Bewusst kein ML-Modell wie rembg: der Container laeuft mit read-only
Root-FS, ein Modell-Cache zur Laufzeit waere dort nicht moeglich.
- Bereits transparente Bilder bleiben unangetastet. Ist der Bildrand
nicht einfarbig, wird nicht freigestellt und die Oberflaeche weist
darauf hin, statt ein beschaedigtes Logo zu liefern.
- Checkbox "Hintergrund behalten" schaltet das Freistellen pro Kunde ab.
- Gespeichert wird immer als PNG (JPEG kann keine Transparenz), grosse
Bilder werden auf 800px verkleinert.
Ablage unter media/<site>/logos/logo_<slot>.png, neue Route
/media/<site>/logos/<datei>. Die URL traegt einen Zeitstempel, damit
Player kein altes Logo aus dem Cache zeigen.
Nebenbei behoben: welcome_data speicherte nur die erfolgreichen Kunden
statt der Felder 1-3. Fiel Kunde 1 aus, rutschte Kunde 2 beim naechsten
Aufruf in Feld 1 und Logo wie Ansprechpartner verschoben sich mit. Jetzt
feldweise - dadurch bleibt auch ein hochgeladenes Logo beim erneuten
Generieren erhalten, solange der Kundenname im selben Feld steht.
Die drei Kundenbloecke im Formular sind zu einer Schleife
zusammengefasst, damit die Upload-Felder nicht dreifach gepflegt werden
muessen.
README, AGENTS.md und Hilfeseite nachgezogen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
templates/customer.html:
- <div class="page"> wurde nie geschlossen. Ergaenzt, analog zu
help.html.
- Der {% include "_footer.html" %} war zusaetzlich in ein eigenes
<footer class="app-footer"> gewickelt, obwohl das Include dieses
Element bereits vollstaendig mitbringt - es standen also zwei
ineinander verschachtelte footer im Markup. Wrapper entfernt.
- Leeren <script>-Block entfernt.
Drei Stellen behaupteten noch, die Willkommensseite ginge in die
Lobby-Playlist:
- README.md: Abschnitt "Willkommensseite", dazu Zielscreens und
"Anzeigen bis" beschrieben
- generate_welcome_page.py: Modul-Docstring
- templates/customer.html: Kommentarblock ueber dem Formular
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- .gitignore: .env aufgenommen, damit lokale Zugangsdaten (OpenAI,
Brandfetch) nicht versehentlich versioniert werden
- config.json: Screen 'videosysteme' an Standort Karlsruhe, dazu eine
Zeitsteuerung am Priority-Eintrag (Mo 08:00-09:00)
- history.json: zugehoerige Verlaufseintraege
Reine Laufzeit- und Konfigurationsdaten, keine Codeaenderung.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Willkommensseite ging bisher fest in die Lobby-Playlist. Welche
Screens Begruessungsschirme sind, ist aber eine Eigenschaft der
Installation und nicht des einzelnen Kundenbesuchs - deshalb ein Flag
pro Screen statt einer Auswahl bei jedem Vorgang.
- Neue Screen-Einstellung "welcome_enabled" (Checkbox im Tab
Einstellungen). Die generierte welcome.html wird in jeden markierten
Screen des Standorts geschrieben und dort an Position 0 gesetzt.
- welcome_target_screens() faellt nur auf "lobby" zurueck, wenn kein
Screen des Standorts den Schluessel besitzt. Bestehende Standorte
verhalten sich damit ohne Konfigurationsaufwand unveraendert.
- add_customer_to_playlists() (frueher add_customer_to_lobby_playlist)
raeumt welcome.html aus allen Screens des Standorts und fuegt sie nur
in den Zielscreens wieder ein. Ein abgewaehlter Screen bleibt so nicht
mit einer alten Begruessung stehen.
- Eingefuegt wird ein Dict statt eines Strings, damit der Eintrag
enabled und schedule tragen kann.
- Optionales "Anzeigen bis" im Formular: setzt eine Zeitsteuerung, die
Seite verschwindet danach auf allen Screens von selbst.
- Das Formular zeigt die aktuellen Zielscreens an und meldet
verstaendlich, wenn keiner markiert ist.
- screens.setdefault("lobby", {}) entfernt - das legte an Standorten
ohne Lobby stillschweigend einen Screen an. Es werden nur noch
vorhandene Screens bespielt.
Die Seite referenziert alle Bilder absolut (/static/..., /media/...),
ist also ortsunabhaengig; je Screen liegt eine identische Kopie.
README, AGENTS.md und die Hilfeseite nachgezogen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Zeitsteuerung fuer Playlist-Eintraege ist seit 6.1.0 dazugekommen.
AGENTS.md versieht Feature-Abschnitte mit einer Versionsangabe - der
Abschnitt "Zeitsteuerung" traegt sie jetzt nach.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
AGENTS.md:
- Helper-Liste nannte playlist_item_enabled(), die es nicht mehr gibt;
ersetzt durch is_item_active() und die neuen Schedule-Helfer
- Playlist-Items: auch Datei-Eintraege koennen Dicts sein, save_playlist
kopiert bestehende Dicts, daher ueberlebt schedule das Umsortieren
- Neuer Abschnitt "Zeitsteuerung": Format, Auswertungsregeln,
Reload-Kopplung ueber playlist_hash() und die beteiligten Stellen.
Festgehalten sind besonders die Punkte, die man beim Umbau kaputt
macht: unlesbare Angaben blenden nicht aus, Mitternachtsfenster
gehoert zum Starttag, daily ignoriert days.
DESIGN.md:
- Playlist-Grid war mit 6 Spalten dokumentiert, tatsaechlich sind es 7
(Edit-Button fehlte). Dazu die Regel, dass Statusmarkierungen in den
.playlist-name-Span gehoeren - als Geschwisterelement verschieben sie
die gesamte Zeile.
- Cards: festgehalten, dass .card global gestylt ist und deshalb nicht
zum Gruppieren von Formularfeldern taugt; dafuer schlichte Zeilen mit
<hr> + <h3>.
- Schedule-Badge dokumentiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
README:
- Feature-Liste und Routen-Tabelle ergaenzt
(POST /admin/<site>/update-playlist-item/<screen>)
- Neuer Abschnitt "Playlist-Eintraege" mit dem Dict-Format fuer URL- und
Datei-Eintraege sowie dem schedule-Objekt: Felder, Beispiele und die
Verhaltensregeln (nur Uhrzeit bei daily/weekly, days nur bei weekly,
Fenster ueber Mitternacht gehoert zum Starttag, unlesbare Angaben
blenden nicht aus, Aktiv-Zustand fliesst in den Playlist-Hash ein)
- Helper-Liste aktualisiert: playlist_item_enabled() gibt es nicht mehr,
dafuer is_item_active(), _schedule_time(), _window_start_date(),
_in_validity_range() und der Filter schedule_text()
Hilfeseite (/admin/help):
- Neuer Abschnitt "Zeitsteuerung" mit Modus-Tabelle, Beispielen und den
Punkten, ueber die man sonst stolpert
- Playlist-Abschnitt: Edit-Button gilt jetzt fuer alle Eintragstypen,
"Zeit"-Badge erklaert
- Priority-Abschnitt: Zeitsteuerung steht dort ebenfalls zur Verfuegung
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Datei stand bereits in .gitignore, war aber weiterhin getrackt -
Ignore-Regeln greifen bei bereits versionierten Dateien nicht. Lokal
bleibt sie erhalten, nur der Repo-Eintrag entfaellt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der vorige Commit 26efed8 war nicht lauffaehig - fehlgeschlagene
Patch-Anwendungen hatten Zeilen aus ihren Bloecken geschoben.
Reparaturen:
- admin(): zerschossene Playlist-Schleife neu aufgebaut
- player(): return render_template war in den else-Zweig gerutscht,
wodurch die View bei aktiver Priority-Playlist None lieferte (HTTP 500)
- playlist_item_enabled() existierte nicht mehr (umbenannt zu
is_item_active), zwei Aufrufe im Player blieben stehen -> NameError
- update_playlist_item(): Absturz bei new_url=null, und der
enabled-Status ging beim Bearbeiten verloren
- Dateityp-Erkennung mit else-Fallback, ftype konnte ungebunden bleiben
Zeitsteuerung:
- Zeitfenster ueber Mitternacht (22:00-02:00) funktionieren; bei weekly
gehoert ein solches Fenster zum Wochentag seines Starts
- Optionaler Gueltigkeitszeitraum (valid_from/valid_until) fuer daily
und weekly, beide Grenzen einzeln optional und inklusiv
- daily/weekly speichern nur noch die Uhrzeit ("08:00") statt eines
Zeitstempels mit bedeutungslosem Datumsanteil; _schedule_time() liest
weiterhin auch Altbestaende mit vollem ISO-Zeitstempel
- playlist_hash() bezieht den ausgewerteten Aktiv-Zustand ein, sonst
bemerkt der Player ein ablaufendes Zeitfenster erst beim naechsten
Reload aus anderem Grund
- Zeitsteuerung auch fuer Datei-Eintraege, nicht nur URLs
- Neuer Filter schedule_text fuer den Tooltip am "Zeit"-Badge
Oberflaeche:
- required lag auf ausgeblendeten Feldern und blockierte das Absenden
des Formulars "URL hinzufuegen" ohne sichtbare Meldung
- updateScheduleDaysVisibility() war innerhalb von DOMContentLoaded
definiert, der Edit-Handler darueber -> ReferenceError bei jedem Klick
- data-schedule mit tojson zerlegte das Attribut, da tojson " nicht
escaped
- Zeitsteuerungs-Block als schlichte Formularzeilen statt als card, die
global den roten Rand und grauen Header erhaelt
- Zeitsteuerung auch in der Priority-Playlist
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>