Files
signage/README.md
2026-06-05 12:55:01 +02:00

239 lines
6.3 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CANCOM Simple Signage
Browserbasiertes Digital-Signage-System für interne Info-Screens.
---
## Features
- 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**: globale Inhalte wirken auf alle Player
- **Willkommensseite**: bis zu 3 Kundenlogos via OpenAI + Brandfetch
- Pro Screen eigene Playlist mit Drag-&-Drop-Reihenfolge
- Auto-Reload bei Playlist-Änderungen
- Newsticker pro Screen
- **Custom-URL-Button**: pro Screen konfigurierbarer Aktions-Button oben links im Player (öffnet URL in iframe-Overlay mit Zurück-Button oder per Direkt-Weiterleitung)
- Dark Mode (localStorage-persistiert)
- CI-konformes Admin-UI (CANCOM-Design: `brand-surface`, `nav-surface` rot)
---
## Architektur
```
Browser (Player)
Flask App (Server)
├── Admin UI /admin/<site>
├── Player UI /player/<site>/<screen>
├── Priority-Seite /admin/<site>/priority
├── config.json
├── media/
│ ├── <site>/
│ │ ├── <screen>/
│ │ │ ├── bild.jpg
│ │ │ ├── video.mp4
│ │ │ └── welcome.html
│ └── priority/
└── generate_welcome_page.py
```
- **Server:** Python 3 + Flask
- **Player:** Jeder moderne Browser (Chrome Kiosk, Edge, Firefox)
- **State:** `config.json` + Dateisystem
- **Frontend:** Tabler Core + Tabler Icons + SortableJS (CDN)
---
## Projektstruktur
```
signage/
├── app.py # Flask-App (alle Routen)
├── generate_welcome_page.py # Logo-Suche + Willkommensseite-Generierung
├── config.json # Persistente Konfiguration
├── media/
│ ├── <site>/
│ │ ├── lobby/
│ │ ├── casino/
│ │ └── videosysteme/
│ └── priority/
├── templates/
│ ├── admin.html # Admin-Dashboard (Übersicht)
│ ├── priority.html # Priority-Playlist (eigene Seite)
│ ├── customer.html # Willkommensseite-Formular
│ ├── player.html # Player-Ansicht
│ ├── login.html
│ ├── _header.html # Gemeinsamer Header
│ ├── _footer.html # Gemeinsamer Footer
│ └── _styles.html # Zentrale CSS (Variablen, Dark Mode)
├── static/
│ ├── cancom.svg
│ └── wallpaper.png
└── AGENTS.md
```
---
## Installation
### Voraussetzungen
- Python ≥ 3.9
- pip
- ffmpeg (optional, für Videokonvertierung)
### Setup
```bash
pip install flask flask-login werkzeug openai
```
### Starten
```bash
python app.py
```
Server läuft auf `http://localhost:5005`.
### Docker
```bash
docker compose up -d
```
---
## Routen
| Route | Beschreibung |
|-------|-------------|
| `GET /` | 404 kein Root-Endpunkt |
| `GET /login` | Admin-Login |
| `GET /logout` | Ausloggen |
| `GET /admin` | Redirect zum ersten konfigurierten Standort |
| `GET /admin/<site>` | Admin-Dashboard für einen Standort |
| `GET /admin/<site>/priority` | Priority-Playlist (separate Seite) |
| `GET /admin/<site>/update/<screen>` | Screen-Einstellungen speichern (POST) |
| `GET /admin/<site>/upload/<screen>` | Medien hochladen (POST) |
| `GET /admin/<site>/add-url/<screen>` | URL zur Playlist hinzufügen (POST) |
| `GET /admin/<site>/delete/<screen>/<filename>` | Datei löschen (POST) |
| `GET /admin/<site>/playlist/<screen>` | Playlist-Reihenfolge speichern (POST JSON) |
| `GET /player/<site>/<screen>` | Player-Ansicht |
| `GET /playlist/<site>/<screen>/hash` | Playlist-Checksumme (für Auto-Reload) |
| `GET /willkommen?site=<site>` | Willkommensseite-Formular (GET + POST) |
| `POST /api/customer` | API-Endpunkt für Willkommensseite (JSON) |
| `GET /media/<site>/<screen>/<file>` | Medien-Datei ausliefern |
| `GET /media/priority/<file>` | Priority-Medien (global) |
### Admin-Portal
```
http://localhost:5005/admin/<standort>
```
- Screens konfigurieren
- Medien hochladen / löschen
- Playlist per Drag & Drop sortieren
- Priority-Playlist verwalten
- Willkommensseite generieren (bis zu 3 Kundenlogos)
- Custom-URL-Aktionsbutton pro Screen konfigurieren (iframe-Overlay oder Weiterleitung)
### Player-URL
```
http://localhost:5005/player/<standort>/<screen>
```
Beispiel:
```
http://localhost:5005/player/stuttgart/lobby
```
### Willkommensseite
```
http://localhost:5005/willkommen?site=stuttgart
```
Maximal 3 Kunden eingeben → Logos werden via OpenAI + Brandfetch gesucht → `welcome.html` wird in der Lobby-Playlist vorne eingefügt.
---
## Konfiguration (`config.json`)
```json
{
"admin": { "username": "...", "password": "..." },
"sites": {
"stuttgart": {
"screens": {
"lobby": { "playlist": [...], "interval": 10 },
"casino": { "playlist": [...], "interval": 15 }
}
}
},
"priority": {
"enabled": true,
"playlist": [...]
}
}
```
---
## Helper-Funktionen (`app.py`)
- `load_config()` / `save_config()` JSON lesen/schreiben
- `get_site_list(cfg)` alle Standorte sortiert
- `get_screen_config(cfg, site, screen)` Screen-Konfiguration mit Defaults
- `is_url(item)` prüft ob Item eine URL ist
- `normalize_url(item)` normalisiert URL-Item zu `{"url", "zoom"}`
- `playlist_item_name(item)` Name aus String oder Dict extrahieren
- `playlist_item_enabled(item)` Enabled-Status prüfen
- `load_priority_files()` Priority-Playlist + Dateien laden
- `prio_redirect(site)` Redirect-Pfad zur Priority-Seite
---
## Dark Mode
Wird über `localStorage("signage-theme")` persistiert. Umschalt-Button im Header. CSS-Variablen `--ccm-*` in `_styles.html`.
---
## Sicherheit
- Admin-Bereich per Flask-Login geschützt
- Player-Seiten Read-Only
- Externe Nutzung via Reverse Proxy + TLS empfohlen
---
## Git & Medien
> Das Repository ist für Code gedacht, nicht für Medien.
`media/` und Medien-Dateiendungen sind in `.gitignore` ausgeschlossen.
---
## Video-Empfehlungen
- Format: MP4 (H.264)
- Auflösung: max. 1920×1080
```bash
ffmpeg -i input.mov -c:v libx264 -pix_fmt yuv420p -movflags +faststart output.mp4
```
---
## Maintainer
**CANCOM Simple Signage** Interne Lösung, nicht für externe Weitergabe bestimmt.