docs: README und Hilfeseite auf Stand 6.2.11 bringen

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Erik Thiele
2026-09-23 19:55:53 +02:00
parent a09375cb31
commit 302811fe29
3 changed files with 24 additions and 10 deletions

View File

@@ -9,8 +9,8 @@ Browserbasiertes Digital-Signage-System für interne Info-Screens.
- Browserbasierter Player (Kiosk-Modus, Chromium, Firefox)
- Bilder, Videos (MP4/H.264), HTML-Seiten, URL-Playlist-Einträge
- **Multi-Standort**: Standorte (sites) gruppieren Screens
- **Priority-Playlist**: pro Standort; die Inhalte laufen auf allen Screens **dieses** Standorts, nicht standortübergreifend
- **Willkommensseite**: bis zu 3 Kundenlogos via OpenAI + Brandfetch oder **manueller Upload mit automatischem Freistellen** (transparenter Hintergrund), pro Standort konfigurierbares Hintergrundbild; erscheint auf allen Screens mit `welcome_enabled` (mehrere möglich), optional mit Ablaufdatum
- **Priority-Playlist**: pro Standort; die Inhalte laufen auf allen Screens **dieses** Standorts, nicht standortübergreifend. Sie werden zusätzlich als **reine Vorschau** oberhalb jeder Screen-Playlist angezeigt (grau, mit „Prio"-Badge), damit sie beim Bearbeiten nicht übersehen werden – bedient wird weiterhin nur auf der Priority-Seite
- **Willkommensseite** (ohne Login erreichbar): bis zu 3 Kundenlogos via OpenAI + Brandfetch oder **manueller Upload mit automatischem Freistellen** (transparenter Hintergrund), pro Standort konfigurierbares Hintergrundbild; erscheint auf allen Screens mit `welcome_enabled` (mehrere möglich), optional mit Ablaufdatum
- Pro Screen eigene Playlist mit Drag-&-Drop-Reihenfolge
- Auto-Reload bei Playlist-Änderungen
- Newsticker pro Screen
@@ -22,8 +22,8 @@ Browserbasiertes Digital-Signage-System für interne Info-Screens.
- **User-Verwaltung**: Mehrere User mit Rollen (Admin / Superuser / User), E-Mail als Login, Passwort-Hashing (scrypt), Berechtigungen pro Standort
- **Passwort-Workflow**: First-Login-Änderung, Admin-Reset mit temporärem Passwort, Notfall-Login bei fehlendem Hash
- **MFA (Multi-Faktor)**: Optionale TOTP-Authentifizierung (Google Authenticator, Authy) per User aktivierbar; QR-Code-Scan + Code-Verifikation, 8 Recovery-Codes, Deaktivierung mit Passwort-Bestätigung, **Trusted Device** (Gerät für 1–30 Tage speichern, überspringt MFA beim nächsten Login)
- **Admin Dashboard**: `/admin/dashboard` – Statistiken (Sites, Screens, User, Admins, Superuser) mit Sparkline-Charts + Trendanzeige, Aktivitätsverlauf
- **Aktivitätsverlauf**: Alle Erstell-/Lösch-/Änderungsaktionen sowie Login/Logout werden in `history.json` protokolliert und im Dashboard angezeigt
- **Admin Dashboard**: `/admin/dashboard` – Statistiken (Sites, Screens, User, Admins, Superuser) mit Sparkline-Charts + Trendanzeige, Aktivitätsverlauf mit Seitennavigation
- **Aktivitätsverlauf**: Alle Erstell-/Lösch-/Änderungsaktionen sowie Login/Logout werden in `history.json` protokolliert (bis zu 1000 Einträge) und im Dashboard seitenweise angezeigt (50 je Seite)
- Tab-basierte Admin-UI pro Screen: Playlist, Einstellungen, Aktionen, Digital Voice Agent, Medien, Info (Tabler Tabs)
- **Zeitsteuerung**: Pro Playlist-Eintrag (URL *und* Datei, auch in der Priority-Playlist) ein Zeitfenster festlegen – einmalig (Datum + Uhrzeit), täglich oder wöchentlich (Uhrzeit + optionaler Gültigkeitszeitraum, wöchentlich zusätzlich mit Wochentagen). Fenster über Mitternacht werden unterstützt. Ein "Zeit"-Badge in der Playlist-Zeile zeigt die Einstellung im Tooltip
- **Query-Parameter-Passthrough**: Per Player-URL übergebene Query-Parameter (z. B. `/player/stuttgart/lobby?customer=acme`) können pro Playlist-URL im Edit-Modal aktiviert werden – standardmäßig aus. Link-Icon in der Playlist-Zeile zeigt Status (an/aus) an.
@@ -207,7 +207,7 @@ Beides fehlte anfangs und machte die Fehlersuche unnötig schwer.
| `GET /login` | Admin-Login |
| `GET /logout` | Ausloggen |
| `GET /admin` | Redirect zum ersten konfigurierten Standort |
| `GET /admin/dashboard` | Admin Dashboard (Statistiken + Verlauf) |
| `GET /admin/dashboard` | Admin Dashboard (Statistiken + Verlauf, `?page=<n>`) |
| `GET /admin/<site>` | Admin-Dashboard für einen Standort |
| `GET /admin/<site>/priority` | Priority-Playlist (separate Seite) |
| `POST /admin/<site>/update/<screen>` | Allgemeine Screen-Einstellungen speichern (Intervall, Newsticker, Bilder/Videos, stay_on_first) |
@@ -226,7 +226,7 @@ Beides fehlte anfangs und machte die Fehlersuche unnötig schwer.
| `POST /admin/<site>/delete-background` | Hintergrundbild zurücksetzen |
| `GET /player/<site>/<screen>` | Player-Ansicht |
| `GET /playlist/<site>/<screen>/hash` | Playlist-Checksumme (für Auto-Reload) + Heartbeat (Online-Status) |
| `GET /willkommen?site=<site>` | Willkommensseite-Formular (GET + POST) |
| `GET /willkommen?site=<site>` | Willkommensseite-Formular (GET + POST) – **ohne Login** |
| `POST /api/customer` | API-Endpunkt für Willkommensseite (JSON) |
| `GET /change-password` | Passwort ändern (First-Login / nach Admin-Reset) |
| `GET /admin/users` | User-Liste (Admin) |
@@ -287,6 +287,8 @@ http://localhost:5005/admin/dashboard
- 5 Statistik-Cards (Standorte, Screens, User, Admins, Superuser) mit ApexCharts-Sparkline + Trendanzeige
- Aktivitätsverlauf (History) als Liste mit Zeitstempel, Aktion und User
- Alle Erstell-/Lösch-/Änderungsaktionen sowie Login/Logout werden protokolliert
- **Seitennavigation**: 50 Einträge je Seite (`HISTORY_PER_PAGE`), Aufruf über `?page=<n>`; aufbewahrt werden 1000 Einträge (`HISTORY_MAX`)
- Kennzahlen und Sparklines beziehen sich immer auf die **jüngsten 30 Aktionen** und ändern sich beim Blättern bewusst nicht – sonst würden die Trendpfeile springen, obwohl sich nichts geändert hat
### Player-URL
@@ -316,6 +318,8 @@ Beispiel:
http://localhost:5005/willkommen?site=stuttgart
```
**Ohne Login erreichbar:** Die Seite ist bewusst nicht durch `@login_required` geschützt, damit auch Mitarbeitende ohne Benutzerkonto eine Begrüßung erstellen können. Ein angemeldeter User sieht dabei weiterhin nur seine freigegebenen Standorte; ohne Anmeldung stehen alle Standorte zur Auswahl, ein unbekannter Standort führt zu 403. Im Aktivitätsverlauf erscheinen solche Einträge als „nicht angemeldet". Die programmatische Variante `POST /api/customer` bleibt angemeldet.
Maximal 3 Kunden eingeben → Logos werden via OpenAI + Brandfetch gesucht → `welcome.html` wird in den Playlists aller Zielscreens vorne eingefügt. Pro Standort kann ein eigenes Hintergrundbild hochgeladen werden (Fallback auf `static/wallpaper.png`).
**Zielscreens:** Jeder Screen mit `welcome_enabled` (Schalter „Willkommensseite hier anzeigen" im Tab Einstellungen). Besitzt kein Screen des Standorts den Schlüssel, greift das alte Verhalten und die Seite geht nur in `lobby`.
@@ -474,6 +478,8 @@ Liegt in `config.json` unter `sites.<site>.priority`, die Medien unter `media/<s
Die Einträge laufen auf allen Screens **dieses** Standorts, eingestreut zwischen den normalen Playlist-Einträgen. Ein anderer Standort ist davon nicht betroffen.
**Vorschau in den Screen-Playlisten:** Ist Priority für den Standort aktiviert, erscheinen die Einträge zusätzlich über jeder Screen-Playlist – ausgegraut, mit rotem „Prio"-Badge und ohne Bedienelemente. Sie liegen bewusst in einer **eigenen `<ul>`**, damit das Speichern der Reihenfolge (`savePlaylist()`) sie nicht mit einsammelt und in die Screen-Playlist schreibt.
> Früher lag die Priority-Playlist global unter `config.priority` und wirkte auf *alle* Standorte. `get_priority_config()` übernimmt einen solchen Altbestand beim ersten Zugriff einmalig in den jeweiligen Standort.
Die Ordnernamen `priority` und `logos` sind unter `media/<site>/` **reserviert** und werden bei der Screen-Erkennung übersprungen – sonst würden sie als Screens in der Oberfläche auftauchen.
@@ -490,7 +496,7 @@ Ein Eintrag ist entweder ein String (Dateiname oder URL, Altbestand) oder ein Di
{
"url": "https://example.com",
"zoom": 1.0, // Zoom-Faktor im Player
"enabled": true, // Checkbox in der Playlist
"enabled": true, // Checkbox in der Playlist (nur der Schalter, nicht das Zeitfenster)
"passthrough_params": false, // Query-Parameter der Player-URL durchreichen
"schedule": { ... } // optional, siehe unten
}
@@ -535,6 +541,9 @@ Optional pro Eintrag. Ohne `schedule` läuft der Eintrag immer (sofern `enabled`
- Unlesbare oder unvollständige Zeitangaben blenden den Eintrag **nicht** aus – ein Konfigurationsfehler soll nicht dazu führen, dass stillschweigend nichts mehr läuft.
- `_schedule_time()` liest neben `"08:00"` auch volle ISO-Zeitstempel, damit Einträge aus älteren Versionen unverändert weiterlaufen.
- Der Aktiv-Zustand fliesst in `/playlist/<site>/<screen>/hash` ein, damit der Player beim Öffnen und Schliessen eines Zeitfensters von selbst neu lädt.
- **Checkbox und Zeitfenster sind getrennt:** Die Checkbox in der Playlist-Zeile zeigt ausschliesslich den gespeicherten Schalter `enabled`, nicht den momentanen Zeitfenster-Zustand. Sie bleibt also gesetzt, auch wenn ein zeitgesteuerter Eintrag gerade nicht läuft. Ob er gerade läuft, sagt das „Zeit"-Badge: blau = läuft, grau = ausserhalb des Fensters (Tooltip nennt den Grund). Abgespielt wird nur, was **beides** erfüllt – Haken gesetzt *und* im Zeitfenster.
> Bis Version 6.2.4 zeigte die Checkbox den ausgewerteten Zustand. Wurde die Playlist ausserhalb des Zeitfensters gespeichert, schrieb die Oberfläche `enabled: false` in die Konfiguration und der Eintrag war dauerhaft abgeschaltet. Der Fehler ist behoben, wirkt aber nicht rückwirkend: bereits betroffene Einträge müssen einmal von Hand wieder aktiviert werden.
---
@@ -552,6 +561,7 @@ Optional pro Eintrag. Ohne `schedule` läuft der Eintrag immer (sofern `enabled`
- `_in_validity_range(schedule, day)` – optionalen Gültigkeitszeitraum prüfen
- `schedule_text(schedule)` – Jinja-Filter: Klartext einer Zeitsteuerung für Tooltips
- `load_priority_files(site)` – Priority-Playlist eines Standorts + Dateien laden
- `_load_history()` / `get_history(limit, offset)` / `get_history_count()` – Aktivitätsverlauf lesen, seitenweise ausschneiden, zählen
- `get_priority_config(cfg, site)` – Priority-Konfiguration des Standorts (übernimmt einmalig einen globalen Altbestand)
- `priority_dir(site)` – Pfad zu `media/<site>/priority/`
- `welcome_target_screens(config, site)` – Zielscreens der Willkommensseite (Fallback `lobby`)
@@ -581,6 +591,7 @@ Wird über `localStorage("signage-theme")` persistiert. Umschalt-Button im Heade
## Sicherheit
- Admin-Bereich per Flask-Login geschützt (E-Mail + Passwort)
- **Ohne Login erreichbar** sind: Player und Medien (die Abspielgeräte melden sich nicht an) sowie das Formular der Willkommensseite. Letzteres legt Dateien an, schreibt in die Konfiguration und löst kostenpflichtige Logo-Abfragen aus – bei einer aus dem Internet erreichbaren Instanz empfiehlt sich eine Einschränkung auf das interne Netz im Reverse Proxy
- Optionale MFA (TOTP) per User aktivierbar (Google Authenticator, Authy)
- 8 Recovery-Codes pro User, einmalig bei Aktivierung angezeigt
- Passwörter gehasht (scrypt) in `users.json`

2
app.py
View File

@@ -53,7 +53,7 @@ HISTORY_FILE = os.path.join(BASE_DIR, "history.json") # Aktivitätsverlauf
HISTORY_MAX = 1000 # so viele Einträge werden aufbewahrt
HISTORY_PER_PAGE = 50 # Einträge je Seite im Dashboard-Verlauf
APP_VERSION = "6.2.10"
APP_VERSION = "6.2.11"
UPLOAD_EXTENSIONS = {".jpg", ".jpeg", ".png", ".mp4"}
app = Flask(__name__)

View File

@@ -104,8 +104,8 @@
<li><strong>Medien hochladen:</strong> Im Tab "Medien" eine Datei auswählen und hochladen. Unterstützt werden Bilder (JPG, PNG) und Videos (MP4).</li>
<li><strong>URL hinzufügen:</strong> Im Tab "Playlist" eine URL eingeben und optional den Zoom-Faktor anpassen.</li>
<li><strong>Sortieren:</strong> Per Drag & Drop die Reihenfolge der Playlist-Einträge ändern (Ziehgriff links).</li>
<li><strong>Deaktivieren:</strong> Mit der Checkbox einzelne Einträge temporär ausblenden.</li>
<li><strong>Löschen:</strong> Über den roten Papierkorb-Button.</li>
<li><strong>Deaktivieren:</strong> Mit der Checkbox einzelne Einträge temporär ausblenden. Die Checkbox ist ein reiner Schalter und hat mit der Zeitsteuerung nichts zu tun: Bei einem zeitgesteuerten Eintrag bleibt der Haken gesetzt, auch wenn der Eintrag gerade nicht läuft. Ob er läuft, zeigt das Zeit-Badge – <span class="badge bg-info text-white">Zeit</span> blau = läuft gerade, <span class="badge bg-secondary-lt">Zeit</span> grau = ausserhalb des Zeitfensters. Abgespielt wird nur, was <em>beides</em> erfüllt: Haken gesetzt und im Zeitfenster.</li>
<li><strong>Löschen:</strong> Über den roten Papierkorb-Button. Die Datei wird dabei entfernt <em>und</em> der Eintrag aus der Playlist genommen.</li>
<li><strong>Bearbeiten:</strong> Der <em>Edit</em>-Button öffnet einen Dialog. Bei URLs lassen sich dort Adresse, Zoom, Query-Parameter-Passthrough und Zeitsteuerung ändern; bei Bildern, Videos und HTML-Seiten die Zeitsteuerung.</li>
<li><strong>Zeitsteuerung:</strong> Einträge können nur zu bestimmten Zeiten laufen – siehe <a href="#help-zeitsteuerung">Zeitsteuerung</a>. Ein Badge <span class="badge bg-info text-white">Zeit</span> in der Playlist-Zeile zeigt an, dass ein Eintrag zeitgesteuert ist; der Tooltip nennt die Einstellung im Klartext.</li>
<li><strong>Query-Parameter-Passthrough:</strong> Per URL-Edit-Button (Stift-Icon) im Playlist-Eintrag kann pro URL gesteuert werden, ob Query-Parameter von der Player-URL an die Playlist-URL übergeben werden. Standardmäßig <strong>aus</strong> – Checkbox "Query-Parameter an diese URL übergeben" aktivieren wenn gewünscht. Ein Link-Icon in der Playlist-Zeile zeigt den Status: <i class="ti ti-link"></i> = an, <i class="ti ti-link-off"></i> = aus.</li>
@@ -177,6 +177,7 @@
<li>Priority muss für den Standort aktiviert sein (<code>config.json → sites.&lt;standort&gt;.priority.enabled</code>)</li>
<li>Die <a href="#help-zeitsteuerung">Zeitsteuerung</a> steht hier genauso zur Verfügung wie in den Screen-Playlists</li>
<li>Jeder Standort hat seine <strong>eigene</strong> Priority-Playlist – Inhalte eines Standorts erscheinen nie auf den Screens eines anderen.</li>
<li><strong>Vorschau in den Screen-Playlisten:</strong> Die Priority-Einträge werden zusätzlich oberhalb jeder normalen Playlist angezeigt – ausgegraut und mit rotem <span class="badge bg-red text-red-fg">Prio</span>-Badge. Das ist eine <em>reine Anzeige</em>: Sie lässt sich dort nicht sortieren, bearbeiten oder löschen. So ist beim Bearbeiten einer Screen-Playlist sofort sichtbar, was dem Screen ohnehin noch vorweg läuft, ohne dass man in den anderen Menüpunkt wechseln muss. Geändert wird weiterhin ausschliesslich auf der Priority-Seite.</li>
</ul>
</div>
</div>
@@ -248,6 +249,7 @@
<div class="card-header"><h3 class="card-title" id="help-willkommen"><i class="ti ti-users me-1"></i>Willkommensseite</h3></div>
<div class="card-body">
<p>Auf der Willkommensseite können bis zu 3 Kundennamen eingegeben werden. Die Logos werden automatisch via OpenAI + Brandfetch gesucht.</p>
<p class="text-muted small"><i class="ti ti-lock-open me-1"></i><strong>Ohne Anmeldung nutzbar:</strong> Das Formular kann auch ohne Benutzerkonto aufgerufen werden – etwa am Empfang. Wer angemeldet ist, sieht weiterhin nur die eigenen Standorte; ohne Anmeldung stehen alle zur Auswahl. Im Aktivitätsverlauf erscheinen solche Einträge als „nicht angemeldet".</p>
<ul>
<li>Aufruf über <code>/willkommen?site=&lt;standort&gt;</code> (oder Menüpunkt)</li>
<li><strong>Zielscreens:</strong> Die generierte <code>welcome.html</code> wird automatisch an den Anfang der Playlist <em>jedes</em> Screens gesetzt, bei dem im Tab "Einstellungen" die Option <em>Willkommensseite hier anzeigen</em> aktiv ist. So lässt sich dieselbe Begrüßung auf mehreren Screens zeigen, ohne sie mehrfach anzulegen. Ist an einem Standort nichts eingestellt, geht sie wie bisher in die Lobby.</li>
@@ -308,6 +310,7 @@
<li><strong>Sparkline:</strong> Kleine Liniendiagramme zeigen den Verlauf der letzten Änderungen</li>
<li><strong>Trend:</strong> Pfeil nach oben/unten mit Netto-Änderung aus den letzten 30 Aktionen</li>
<li><strong>Aktivitätsverlauf:</strong> Alle Erstell-, Lösch-, Änderungsaktionen sowie An-/Abmeldungen werden protokolliert</li>
<li><strong>Blättern:</strong> Der Verlauf zeigt 50 Einträge je Seite; über die Leiste unter der Liste lässt sich weiter zurückblättern. Aufbewahrt werden die letzten 1000 Einträge. Statistik-Cards, Sparklines und Trendpfeile beziehen sich dabei immer auf die jüngsten 30 Aktionen und ändern sich beim Blättern nicht.</li>
</ul>
</div>
</div>