Standortauswahl und Multi Logo und Action Button
This commit is contained in:
239
README.md
239
README.md
@@ -1,85 +1,95 @@
|
||||
# 📺 CANCOM Simple Signage
|
||||
# CANCOM Simple Signage
|
||||
|
||||
**CANCOM Simple Signage** ist ein leichtgewichtiges, browserbasiertes Digital-Signage-System auf Basis von **Python + Flask**.
|
||||
|
||||
Ziel ist eine **einfache, robuste und wartbare Lösung** für interne Info-Screens, ohne die Komplexität klassischer Digital-Signage-Plattformen.
|
||||
Browserbasiertes Digital-Signage-System für interne Info-Screens.
|
||||
|
||||
---
|
||||
|
||||
## ✨ Features
|
||||
## Features
|
||||
|
||||
- ✅ Browser-basierter Player (kein nativer Client erforderlich)
|
||||
- ✅ Bilder & Videos (MP4, H.264)
|
||||
- ✅ Pro Screen eine eigene Playlist
|
||||
- ✅ Drag-&-Drop-Reihenfolge im Admin-Portal
|
||||
- ✅ Automatischer Player-Reload bei Änderungen
|
||||
- ✅ Upload & Löschen von Medien
|
||||
- ✅ Screen-Status (aktiv / leer)
|
||||
- ✅ CI-konformes Admin-UI (CANCOM)
|
||||
- ✅ Läuft lokal, in VMs oder auf Proxmox
|
||||
- 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
|
||||
## Architektur
|
||||
|
||||
```
|
||||
Browser (Player)
|
||||
│
|
||||
▼
|
||||
Flask App (Server)
|
||||
├── Admin UI
|
||||
├── Player UI
|
||||
├── Admin UI /admin/<site>
|
||||
├── Player UI /player/<site>/<screen>
|
||||
├── Priority-Seite /admin/<site>/priority
|
||||
├── config.json
|
||||
└── media/
|
||||
└── <screen-name>/
|
||||
├── bild.jpg
|
||||
└── video.mp4
|
||||
├── media/
|
||||
│ ├── <site>/
|
||||
│ │ ├── <screen>/
|
||||
│ │ │ ├── bild.jpg
|
||||
│ │ │ ├── video.mp4
|
||||
│ │ │ └── welcome.html
|
||||
│ └── priority/
|
||||
└── generate_welcome_page.py
|
||||
```
|
||||
|
||||
- **Server:** Python 3 + Flask
|
||||
- **Player:** Jeder moderne Browser (Chrome, Edge, Firefox, Kiosk-Modus)
|
||||
- **Player:** Jeder moderne Browser (Chrome Kiosk, Edge, Firefox)
|
||||
- **State:** `config.json` + Dateisystem
|
||||
- **Frontend:** Tabler + SortableJS (CDN)
|
||||
- **Frontend:** Tabler Core + Tabler Icons + SortableJS (CDN)
|
||||
|
||||
---
|
||||
|
||||
## 📂 Projektstruktur
|
||||
## Projektstruktur
|
||||
|
||||
```
|
||||
signage/
|
||||
├── app.py
|
||||
├── config.json
|
||||
├── app.py # Flask-App (alle Routen)
|
||||
├── generate_welcome_page.py # Logo-Suche + Willkommensseite-Generierung
|
||||
├── config.json # Persistente Konfiguration
|
||||
├── media/
|
||||
│ ├── lobby/
|
||||
│ └── meetingroom/
|
||||
│ ├── <site>/
|
||||
│ │ ├── lobby/
|
||||
│ │ ├── casino/
|
||||
│ │ └── videosysteme/
|
||||
│ └── priority/
|
||||
├── templates/
|
||||
│ ├── admin.html
|
||||
│ ├── player.html
|
||||
│ └── login.html
|
||||
│ ├── 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/
|
||||
└── README.md
|
||||
│ ├── cancom.svg
|
||||
│ └── wallpaper.png
|
||||
└── AGENTS.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Installation
|
||||
## Installation
|
||||
|
||||
### Voraussetzungen
|
||||
|
||||
- Python ≥ 3.9
|
||||
- pip
|
||||
- ffmpeg
|
||||
|
||||
```bash
|
||||
sudo apt install python3 python3-pip ffmpeg
|
||||
```
|
||||
- ffmpeg (optional, für Videokonvertierung)
|
||||
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd signage
|
||||
pip install flask flask-login werkzeug
|
||||
pip install flask flask-login werkzeug openai
|
||||
```
|
||||
|
||||
### Starten
|
||||
@@ -88,72 +98,134 @@ pip install flask flask-login werkzeug
|
||||
python app.py
|
||||
```
|
||||
|
||||
Server läuft auf:
|
||||
Server läuft auf `http://localhost:5005`.
|
||||
|
||||
```
|
||||
http://localhost:5005
|
||||
### Docker
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Betrieb
|
||||
## 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
|
||||
|
||||
```
|
||||
/admin
|
||||
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-URLs
|
||||
### Player-URL
|
||||
|
||||
```
|
||||
/player/<screen-name>
|
||||
http://localhost:5005/player/<standort>/<screen>
|
||||
```
|
||||
|
||||
Beispiel:
|
||||
```
|
||||
http://localhost:5005/player/stuttgart/lobby
|
||||
```
|
||||
|
||||
### Willkommensseite
|
||||
|
||||
```
|
||||
http://server:5000/player/lobby
|
||||
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": [...]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Automatischer Reload
|
||||
## Helper-Funktionen (`app.py`)
|
||||
|
||||
Der Player aktualisiert sich selbst, wenn:
|
||||
|
||||
- Medien hinzugefügt oder gelöscht werden
|
||||
- Playlist-Reihenfolge geändert wird
|
||||
- Screen-Einstellungen angepasst werden
|
||||
- `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
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Git & Medien
|
||||
## Dark Mode
|
||||
|
||||
> **Dieses Repository ist für Code gedacht, nicht für Medien.**
|
||||
|
||||
Empfohlene `.gitignore`:
|
||||
|
||||
```gitignore
|
||||
media/
|
||||
*.mp4
|
||||
*.mov
|
||||
*.jpg
|
||||
*.jpeg
|
||||
*.png
|
||||
```
|
||||
Wird über `localStorage("signage-theme")` persistiert. Umschalt-Button im Header. CSS-Variablen `--ccm-*` in `_styles.html`.
|
||||
|
||||
---
|
||||
|
||||
## 🎞️ Video-Empfehlungen
|
||||
## Sicherheit
|
||||
|
||||
- Format: MP4
|
||||
- Codec: H.264
|
||||
- Auflösung: max. 1920x1080
|
||||
- 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
|
||||
@@ -161,25 +233,6 @@ ffmpeg -i input.mov -c:v libx264 -pix_fmt yuv420p -movflags +faststart output.mp
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Sicherheit
|
||||
## Maintainer
|
||||
|
||||
- Admin-Bereich per Login geschützt
|
||||
- Player-Seiten Read-Only
|
||||
- Externe Nutzung via Reverse Proxy + TLS empfohlen
|
||||
|
||||
---
|
||||
|
||||
## 🧭 Roadmap
|
||||
|
||||
- Zeitsteuerung pro Playlist-Eintrag
|
||||
- Vorschau im Admin-Portal
|
||||
- Mehrere Admin-User
|
||||
- SQLite statt config.json
|
||||
- Docker-Compose Setup
|
||||
|
||||
---
|
||||
|
||||
## 👤 Maintainer
|
||||
|
||||
**CANCOM Simple Signage**
|
||||
Interne Lösung – nicht für externe Weitergabe bestimmt.
|
||||
**CANCOM Simple Signage** – Interne Lösung, nicht für externe Weitergabe bestimmt.
|
||||
|
||||
Reference in New Issue
Block a user