Ergänzung Active Button
This commit is contained in:
54
AGENTS.md
54
AGENTS.md
@@ -31,7 +31,7 @@ Standorte (sites) sind die oberste Organisationsebene und gruppieren Screens.
|
||||
| `GET /media/<site>/<screen>/<file>` | Medien-Datei ausliefern |
|
||||
| `GET /media/priority/<file>` | Priority-Medien (global) |
|
||||
| `GET /media/<site>/background/<filename>` | Hintergrundbild der Willkommensseite |
|
||||
| `GET /playlist/<site>/<screen>/hash` | Playlist-Checksumme für Auto-Reload |
|
||||
| `GET /playlist/<site>/<screen>/hash` | Playlist-Checksumme für Auto-Reload + zeichnet Heartbeat auf (Online-Status) |
|
||||
| `GET /willkommen?site=<site>` | Willkommensseite für Standort generieren |
|
||||
| `POST /admin/<site>/upload-background` | Hintergrundbild für Willkommensseite hochladen |
|
||||
| `POST /admin/<site>/delete-background` | Hintergrundbild zurücksetzen auf Standard |
|
||||
@@ -120,7 +120,7 @@ Standorte (sites) sind die oberste Organisationsebene und gruppieren Screens.
|
||||
- `users.json` is NOT gitignored (tracked for initial admin setup, contains no secrets by default).
|
||||
- The app has no configured tests, lint, typecheck, formatter, or CI.
|
||||
- Hardcoded secrets exist in tracked files; do not commit new secrets or reshuffle them casually.
|
||||
- Wichtige Helper-Funktionen in `app.py`: `load_config()`, `save_config()`, `get_site_list()`, `get_screen_config()`, `is_url()`, `normalize_url()`, `playlist_item_name()`, `playlist_item_enabled()`, `load_priority_files()`, `prio_redirect()`, `get_background_url()`, `load_users()`, `save_users()`, `get_user()`, `init_user_db()`, `get_accessible_sites()`.
|
||||
- Wichtige Helper-Funktionen in `app.py`: `load_config()`, `save_config()`, `get_site_list()`, `get_screen_config()`, `is_url()`, `normalize_url()`, `playlist_item_name()`, `playlist_item_enabled()`, `load_priority_files()`, `prio_redirect()`, `get_background_url()`, `load_users()`, `save_users()`, `get_user()`, `init_user_db()`, `get_accessible_sites()`, `record_heartbeat()`, `screen_is_active()`.
|
||||
- Zugriffs-Dekoratoren in `app.py`: `admin_required`, `site_access_required`.
|
||||
- Hintergrundbild der Willkommensseite wird pro Standort unter `media/<site>/background.*` gespeichert; Fallback auf `static/wallpaper.png` wenn keine Datei existiert.
|
||||
- `get_background_url(site)` prüft auf benutzerdefiniertes Hintergrundbild für einen Standort.
|
||||
@@ -129,3 +129,53 @@ Standorte (sites) sind die oberste Organisationsebene und gruppieren Screens.
|
||||
- `search_customer_logo` in `generate_welcome_page.py` nutzt OpenAI GPT-4 + Brandfetch CDN.
|
||||
- `admin_priority` rendert `priority.html` mit `site_list`, `current_site`, `priority_files`, `server_url`.
|
||||
- `static/dva.png`: Bild für den Voice-Agent-Button (optional, per Admin-Toggle ein-/ausblendbar).
|
||||
|
||||
## Heartbeat / Online-Status (seit v6.1.0)
|
||||
|
||||
Der Player-Status (Online/Offline) wird mittels dateibasiertem Heartbeat ermittelt.
|
||||
|
||||
### Funktionsweise
|
||||
|
||||
| Schritt | Beschreibung |
|
||||
|---------|-------------|
|
||||
| **Player-pollt** alle 5s `/playlist/<site>/<screen>/hash` (`checkForUpdates`) | Bestehender Mechanismus, kein Extra-Request |
|
||||
| **Server zeichnet Heartbeat auf** | `record_heartbeat(site, screen)` erstellt/updated `/tmp/signage-heartbeat/<site>/<screen>` via `path.touch()` |
|
||||
| **Admin-UI fragt Status ab** | `screen_is_active(site, screen)` prüft ob `mtime < 60s` alt |
|
||||
| **Anzeige** | Grüner "Online"-Button (filled success) oder roter "Offline"-Button (filled danger) im Card-Header neben "Löschen" |
|
||||
|
||||
### Helper-Funktionen in `app.py`
|
||||
|
||||
```python
|
||||
HEARTBEAT_DIR = Path("/tmp/signage-heartbeat")
|
||||
HEARTBEAT_TIMEOUT = 60 # Sekunden
|
||||
|
||||
def record_heartbeat(site, screen):
|
||||
path = HEARTBEAT_DIR / site / screen
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.touch()
|
||||
|
||||
def screen_is_active(site, screen):
|
||||
path = HEARTBEAT_DIR / site / screen
|
||||
if not path.exists():
|
||||
return False
|
||||
return (time.time() - path.stat().st_mtime) < HEARTBEAT_TIMEOUT
|
||||
```
|
||||
|
||||
### Integration
|
||||
|
||||
- `playlist_hash()`-Route ruft `record_heartbeat()` direkt am Anfang auf
|
||||
- `admin()`-Route setzt `screen_status["online"/"offline"]` via `screen_is_active()` für jeden Screen
|
||||
- Admin-Template (`admin.html`) zeigt beide Buttons als `<button class="btn btn-sm btn-success/btn-danger" onclick="return false;">`
|
||||
- Die Lösch-Buttons (`btn-outline-danger btn-sm`) haben gleiche Größe durch gleiche btn-sm-Klasse, Form-Wrapper hat `m-0 p-0`
|
||||
|
||||
### Docker-Hinweis
|
||||
|
||||
Im Docker-Container liegt der Heartbeat-Pfad unter `/tmp/signage-heartbeat/` im Container. Da die Docker-Umgebung keine Volumes mounted, sind Heartbeats container-lokal. Nach `docker compose restart` werden alle Screens kurz rot, bis die Player innerhalb von max. 60s wieder pollen.
|
||||
|
||||
### Debugging
|
||||
|
||||
```bash
|
||||
# Alle Heartbeat-Dateien anzeigen
|
||||
ls -la /tmp/signage-heartbeat/*/
|
||||
find /tmp/signage-heartbeat -type f -exec ls -la {} \;
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user