Hintergrundbild Willkommensseite
This commit is contained in:
12
AGENTS.md
12
AGENTS.md
@@ -29,8 +29,11 @@ Standorte (sites) sind die oberste Organisationsebene und gruppieren Screens.
|
|||||||
| `GET /admin/<site>/priority` | Priority-Playlist als separate Seite |
|
| `GET /admin/<site>/priority` | Priority-Playlist als separate Seite |
|
||||||
| `GET /media/<site>/<screen>/<file>` | Medien-Datei ausliefern |
|
| `GET /media/<site>/<screen>/<file>` | Medien-Datei ausliefern |
|
||||||
| `GET /media/priority/<file>` | Priority-Medien (global) |
|
| `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 |
|
||||||
| `GET /willkommen?site=<site>` | Willkommensseite für Standort generieren |
|
| `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 |
|
||||||
| `POST /api/customer` | API-Endpunkt (JSON mit "site"-Feld) |
|
| `POST /api/customer` | API-Endpunkt (JSON mit "site"-Feld) |
|
||||||
| `GET /admin/<site>/add-screen?name=<name>` | Neuen Screen anlegen |
|
| `GET /admin/<site>/add-screen?name=<name>` | Neuen Screen anlegen |
|
||||||
| `POST /admin/<site>/delete-screen/<screen>` | Screen + Medien löschen |
|
| `POST /admin/<site>/delete-screen/<screen>` | Screen + Medien löschen |
|
||||||
@@ -59,8 +62,8 @@ Standorte (sites) sind die oberste Organisationsebene und gruppieren Screens.
|
|||||||
- Neue Standorte können über den `+`-Button im Header oder über `GET /add-site?name=<name>` angelegt werden.
|
- Neue Standorte können über den `+`-Button im Header oder über `GET /add-site?name=<name>` angelegt werden.
|
||||||
- `delete_site` entfernt den Standort aus Config und löscht das Medienverzeichnis rekursiv.
|
- `delete_site` entfernt den Standort aus Config und löscht das Medienverzeichnis rekursiv.
|
||||||
- `config.json["server_url"]` (z. B. `http://signage.ccmake.de`) wird in der Admin-Ansicht für die Player-URLs verwendet.
|
- `config.json["server_url"]` (z. B. `http://signage.ccmake.de`) wird in der Admin-Ansicht für die Player-URLs verwendet.
|
||||||
- Screen-Card-Body hat Tabler-Tabs: **Playlist** (1, aktiv), **Einstellungen** (2), **Medien** (3); Priority-Seite ebenfalls Tabs **Playlist** und **Medien**.
|
- Screen-Card-Body hat Tabler-Tabs: **Playlist** (1, aktiv), **Einstellungen** (2), **Aktionen** (3), **Medien** (4); Priority-Seite ebenfalls Tabs **Playlist** und **Medien**.
|
||||||
- Tab-Reihenfolge in Screen-Cards: Playlist → Einstellungen → Medien.
|
- Tab-Reihenfolge in Screen-Cards: Playlist → Einstellungen → Aktionen → Medien.
|
||||||
- Player-URL im Screen-Header ist ein klickbarer Link in grauer Farbe.
|
- Player-URL im Screen-Header ist ein klickbarer Link in grauer Farbe.
|
||||||
|
|
||||||
## Repo Quirks
|
## Repo Quirks
|
||||||
@@ -68,7 +71,10 @@ Standorte (sites) sind die oberste Organisationsebene und gruppieren Screens.
|
|||||||
- `media/` and media file extensions are gitignored.
|
- `media/` and media file extensions are gitignored.
|
||||||
- The app has no configured tests, lint, typecheck, formatter, or CI.
|
- 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.
|
- 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()`.
|
- 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()`.
|
||||||
|
- 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.
|
||||||
|
- `generate_welcome_html(customer_names, logo_urls, background_url=None)` akzeptiert optionalen `background_url`-Parameter.
|
||||||
- `welcome.html` wird in `media/<site>/lobby/` gespeichert.
|
- `welcome.html` wird in `media/<site>/lobby/` gespeichert.
|
||||||
- `search_customer_logo` in `generate_welcome_page.py` nutzt OpenAI GPT-4 + Brandfetch CDN.
|
- `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`.
|
- `admin_priority` rendert `priority.html` mit `site_list`, `current_site`, `priority_files`, `server_url`.
|
||||||
|
|||||||
99
app.py
99
app.py
@@ -185,6 +185,44 @@ def prio_redirect(site):
|
|||||||
return f"/admin/{site}/priority"
|
return f"/admin/{site}/priority"
|
||||||
|
|
||||||
|
|
||||||
|
def get_background_url(site):
|
||||||
|
"""Prüft, ob für einen Standort ein benutzerdefiniertes Hintergrundbild existiert.
|
||||||
|
Gibt die URL zurück oder None (dann wird das Standard-Wallpaper verwendet)."""
|
||||||
|
site_dir = os.path.join(MEDIA_DIR, site)
|
||||||
|
if not os.path.isdir(site_dir):
|
||||||
|
return None
|
||||||
|
for f in sorted(os.listdir(site_dir)):
|
||||||
|
if f.startswith("background."):
|
||||||
|
ext = os.path.splitext(f)[1].lower()
|
||||||
|
if ext in (".jpg", ".jpeg", ".png"):
|
||||||
|
return f"/media/{site}/background/{f}"
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _regenerate_welcome_for_site(site):
|
||||||
|
"""Regeneriert die Willkommensseite mit aktuellem Hintergrund,
|
||||||
|
falls zuvor Kundendaten gespeichert wurden."""
|
||||||
|
config = load_config()
|
||||||
|
welcome_data = config.get("sites", {}).get(site, {}).get("welcome_data")
|
||||||
|
if welcome_data:
|
||||||
|
names = welcome_data.get("names", [])
|
||||||
|
urls = welcome_data.get("logo_urls", [])
|
||||||
|
if names:
|
||||||
|
bg_url = get_background_url(site)
|
||||||
|
generate_welcome_page.save_welcome_page(names, urls, site=site, background_url=bg_url)
|
||||||
|
print(f"♻️ Willkommensseite für {site} mit aktualisiertem Hintergrund neu generiert")
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------------------------
|
||||||
|
# Medien ausliefern (statische Dateien)
|
||||||
|
# -------------------------------------------------
|
||||||
|
@app.route("/media/<site>/background/<path:filename>")
|
||||||
|
def media_background(site, filename):
|
||||||
|
"""Liefert das Hintergrundbild für die Willkommensseite aus."""
|
||||||
|
path = os.path.join(MEDIA_DIR, site)
|
||||||
|
return send_from_directory(path, filename)
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------
|
# -------------------------------------------------
|
||||||
# User & Login (Flask-Login)
|
# User & Login (Flask-Login)
|
||||||
# -------------------------------------------------
|
# -------------------------------------------------
|
||||||
@@ -285,10 +323,16 @@ def add_customer():
|
|||||||
logo_urls[i] = vu
|
logo_urls[i] = vu
|
||||||
break
|
break
|
||||||
|
|
||||||
html_filename = generate_welcome_page.save_welcome_page(valid_names, valid_urls, site=site)
|
bg_url = get_background_url(site)
|
||||||
|
html_filename = generate_welcome_page.save_welcome_page(valid_names, valid_urls, site=site, background_url=bg_url)
|
||||||
|
|
||||||
if html_filename:
|
if html_filename:
|
||||||
if generate_welcome_page.add_customer_to_lobby_playlist(html_filename, site=site):
|
if generate_welcome_page.add_customer_to_lobby_playlist(html_filename, site=site):
|
||||||
|
# Letzte Kundendaten für Background-Update speichern
|
||||||
|
config = load_config()
|
||||||
|
site_cfg = config.setdefault("sites", {}).setdefault(site, {})
|
||||||
|
site_cfg["welcome_data"] = {"names": valid_names, "logo_urls": valid_urls}
|
||||||
|
save_config(config)
|
||||||
success = f"✅ Willkommensseite mit {len(valid_names)} Kunden erstellt!"
|
success = f"✅ Willkommensseite mit {len(valid_names)} Kunden erstellt!"
|
||||||
else:
|
else:
|
||||||
error = "Fehler beim Hinzufügen zur Playliste"
|
error = "Fehler beim Hinzufügen zur Playliste"
|
||||||
@@ -301,6 +345,7 @@ def add_customer():
|
|||||||
|
|
||||||
config = load_config()
|
config = load_config()
|
||||||
site_list = get_site_list(config)
|
site_list = get_site_list(config)
|
||||||
|
background_url = get_background_url(site)
|
||||||
return render_template(
|
return render_template(
|
||||||
"customer.html",
|
"customer.html",
|
||||||
error=error,
|
error=error,
|
||||||
@@ -312,7 +357,8 @@ def add_customer():
|
|||||||
current_site=site,
|
current_site=site,
|
||||||
version=APP_VERSION,
|
version=APP_VERSION,
|
||||||
year=datetime.now().year,
|
year=datetime.now().year,
|
||||||
hostname=os.uname().nodename
|
hostname=os.uname().nodename,
|
||||||
|
background_url=background_url
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -711,6 +757,55 @@ def admin_priority(site):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------------------------
|
||||||
|
# Admin: Hintergrundbild für Willkommensseite hochladen
|
||||||
|
# -------------------------------------------------
|
||||||
|
@app.route("/admin/<site>/upload-background", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
def upload_background(site):
|
||||||
|
"""Lädt ein Hintergrundbild für die Willkommensseite hoch (pro Standort).
|
||||||
|
Gespeichert als media/<site>/background.<ext>."""
|
||||||
|
file = request.files.get("background")
|
||||||
|
if not file:
|
||||||
|
return redirect(f"/willkommen?site={site}")
|
||||||
|
|
||||||
|
ext = os.path.splitext(file.filename)[1].lower()
|
||||||
|
if ext not in UPLOAD_EXTENSIONS:
|
||||||
|
return "Ungültiger Dateityp", 400
|
||||||
|
|
||||||
|
site_dir = os.path.join(MEDIA_DIR, site)
|
||||||
|
os.makedirs(site_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Alte Hintergrundbilder löschen
|
||||||
|
for f in os.listdir(site_dir):
|
||||||
|
if f.startswith("background."):
|
||||||
|
os.remove(os.path.join(site_dir, f))
|
||||||
|
|
||||||
|
filename = f"background{ext}"
|
||||||
|
file.save(os.path.join(site_dir, filename))
|
||||||
|
|
||||||
|
# Willkommensseite mit neuen Hintergrund neu generieren
|
||||||
|
_regenerate_welcome_for_site(site)
|
||||||
|
|
||||||
|
return redirect(f"/willkommen?site={site}")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/admin/<site>/delete-background", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
def delete_background(site):
|
||||||
|
"""Löscht das Hintergrundbild für die Willkommensseite."""
|
||||||
|
site_dir = os.path.join(MEDIA_DIR, site)
|
||||||
|
if os.path.isdir(site_dir):
|
||||||
|
for f in os.listdir(site_dir):
|
||||||
|
if f.startswith("background."):
|
||||||
|
os.remove(os.path.join(site_dir, f))
|
||||||
|
|
||||||
|
# Willkommensseite mit Standard-Hintergrund neu generieren
|
||||||
|
_regenerate_welcome_for_site(site)
|
||||||
|
|
||||||
|
return redirect(f"/willkommen?site={site}")
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------
|
# -------------------------------------------------
|
||||||
# Admin: Screen-Einstellungen speichern
|
# Admin: Screen-Einstellungen speichern
|
||||||
# -------------------------------------------------
|
# -------------------------------------------------
|
||||||
|
|||||||
24
config.json
24
config.json
@@ -15,7 +15,7 @@
|
|||||||
"screens": {
|
"screens": {
|
||||||
"lobby": {
|
"lobby": {
|
||||||
"interval": 10,
|
"interval": 10,
|
||||||
"show_images": true,
|
"show_images": false,
|
||||||
"show_videos": false,
|
"show_videos": false,
|
||||||
"playlist": [
|
"playlist": [
|
||||||
"welcome.html",
|
"welcome.html",
|
||||||
@@ -34,12 +34,12 @@
|
|||||||
"enabled": false
|
"enabled": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"newsticker_text": "Herzlich Willkommen bei der CANCOM - wir begr\u00fc\u00dfen unsere G\u00e4ste und w\u00fcnschen Ihnen einen angenehmen Tag! !",
|
"newsticker_text": "",
|
||||||
"newsticker_enabled": true,
|
"newsticker_enabled": false,
|
||||||
"custom_url": "https://dva-stage.cancom-ds.de/voice-agent",
|
"custom_url": "https://dva-stage.cancom-ds.de/voice-agent",
|
||||||
"custom_url_label": "Welcome Agent",
|
"custom_url_label": "Welcome Agent",
|
||||||
"custom_url_enabled": false,
|
"custom_url_enabled": false,
|
||||||
"custom_url_target": "redirect"
|
"custom_url_target": "overlay"
|
||||||
},
|
},
|
||||||
"casino": {
|
"casino": {
|
||||||
"interval": 15,
|
"interval": 15,
|
||||||
@@ -70,6 +70,14 @@
|
|||||||
"newsticker_text": "Hallo dies ist ein Test f\u00fcr Michael",
|
"newsticker_text": "Hallo dies ist ein Test f\u00fcr Michael",
|
||||||
"newsticker_enabled": false
|
"newsticker_enabled": false
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"welcome_data": {
|
||||||
|
"names": [
|
||||||
|
"cisco"
|
||||||
|
],
|
||||||
|
"logo_urls": [
|
||||||
|
"https://cdn.brandfetch.io/www.cisco.com/logo?c=1idyd4Tpb2nKaXIIc8T"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"karlsruhe": {
|
"karlsruhe": {
|
||||||
@@ -84,6 +92,14 @@
|
|||||||
"newsticker_text": "Herzlich Willkommen bei der CANCOM - wir begr\u00fc\u00dfen unsere G\u00e4ste und w\u00fcnschen Ihnen einen angenehmen Tag!",
|
"newsticker_text": "Herzlich Willkommen bei der CANCOM - wir begr\u00fc\u00dfen unsere G\u00e4ste und w\u00fcnschen Ihnen einen angenehmen Tag!",
|
||||||
"newsticker_enabled": true
|
"newsticker_enabled": true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"welcome_data": {
|
||||||
|
"names": [
|
||||||
|
"cisco"
|
||||||
|
],
|
||||||
|
"logo_urls": [
|
||||||
|
"https://cdn.brandfetch.io/www.cisco.com/logo?c=1idyd4Tpb2nKaXIIc8T"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ def search_customer_logo(customer_name):
|
|||||||
# HTML-Generierung
|
# HTML-Generierung
|
||||||
# -------------------------------------------------
|
# -------------------------------------------------
|
||||||
|
|
||||||
def generate_welcome_html(customer_names, logo_urls, site="stuttgart"):
|
def generate_welcome_html(customer_names, logo_urls, site="stuttgart", background_url=None):
|
||||||
"""
|
"""
|
||||||
Generiert den HTML-Code für die Willkommensseite.
|
Generiert den HTML-Code für die Willkommensseite.
|
||||||
- Links oben: CANCOM-Logo + "meets" + Kundenlogos (280px Breite)
|
- Links oben: CANCOM-Logo + "meets" + Kundenlogos (280px Breite)
|
||||||
@@ -106,11 +106,14 @@ def generate_welcome_html(customer_names, logo_urls, site="stuttgart"):
|
|||||||
customer_names: Liste der Kundennamen (max. 3)
|
customer_names: Liste der Kundennamen (max. 3)
|
||||||
logo_urls: Liste der Logo-URLs (gleiche Reihenfolge)
|
logo_urls: Liste der Logo-URLs (gleiche Reihenfolge)
|
||||||
site: Standort-Name für die Anzeige
|
site: Standort-Name für die Anzeige
|
||||||
|
background_url: URLs zum Hintergrundbild (None → Standard-Wallpaper)
|
||||||
"""
|
"""
|
||||||
site_display = site.capitalize()
|
site_display = site.capitalize()
|
||||||
names_str = ", ".join(customer_names) if customer_names else "Unbekannt"
|
names_str = ", ".join(customer_names) if customer_names else "Unbekannt"
|
||||||
print(f"✅ Generate - Willkommensseite wird generiert für: {names_str} (site: {site})")
|
print(f"✅ Generate - Willkommensseite wird generiert für: {names_str} (site: {site})")
|
||||||
site_display = site.capitalize()
|
site_display = site.capitalize()
|
||||||
|
|
||||||
|
bg_image = background_url if background_url else "/static/wallpaper.png"
|
||||||
cancom_svg = '''<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xcs="https://www.xtool.com/pages/software" version="1.1" preserveAspectRatio="xMinYMin meet" width="61.682394106284505mm" height="9.909010347638684mm" viewBox="136.55880294685778 209.2954948261807 61.682394106284505 9.909010347638684" xcs:version="2.7.22"><style></style><path transform="matrix(0.158038,0,0,0.158038,133.2558,163.322122)" stroke="none" fill="currentColor" data-view-type="laser" d="M125.9,352.1h18.9L119,291.7h-16.2l-25,60.4h18.2l14.6-38.9L125.9,352.1z M323.6,322 c0,8.8-6.1,16.4-15.4,16.4c-9.1,0-15.4-7.6-15.4-16.4s6.1-16.4,15.2-16.4C317,305.6,323.6,313.4,323.6,322 M340.5,322.3 c0-17.4-13.4-31.3-32.3-31.3c-18.7,0-32.3,14.1-32.3,31.3c0,17.4,13.4,31.3,32.3,31.3C326.9,353.6,340.5,339.4,340.5,322.3 M230.4,322.5c0-8.8,6.1-16.4,14.9-16.4c3,0,5.8,0.8,8.1,2l6.6-13.4c-3-2-8.1-3.8-14.9-3.8c-18.2,0-31.6,14.1-31.6,31.3 c0,18.2,12.6,31.1,31.6,31.1c17.2,0,26-10.6,28.8-21l-13.6-5.6c-1.8,5.8-6.3,11.6-14.4,11.6C236.5,338.4,230.4,331.4,230.4,322.5 M38,322.5c0-8.8,6.1-16.4,14.9-16.4c3,0,5.8,0.8,8.1,2l6.6-13.4c-3-2-8.1-3.8-14.9-3.8c-18.4,0-31.8,14.1-31.8,31.3 c0,18.2,12.6,31.1,31.6,31.1c17.2,0,26-10.6,28.8-21l-13.6-5.6c-1.8,5.8-6.3,11.6-14.4,11.6C44,338.4,38,331.4,38,322.5 M191.8,352.1h14.4v-59.8H190v33.1l-25-33.1h-15.4v60.1h16.2v-34.1L191.8,352.1z M411.2,352.1v-59.8h-17.7l-14.4,23.2l-14.4-23.2 h-17.7v60.1h16.4V318l15.4,23.2h0.3l15.4-23.5v34.6L411.2,352.1L411.2,352.1z" fill-rule="nonzero"></path></svg>'''
|
cancom_svg = '''<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xcs="https://www.xtool.com/pages/software" version="1.1" preserveAspectRatio="xMinYMin meet" width="61.682394106284505mm" height="9.909010347638684mm" viewBox="136.55880294685778 209.2954948261807 61.682394106284505 9.909010347638684" xcs:version="2.7.22"><style></style><path transform="matrix(0.158038,0,0,0.158038,133.2558,163.322122)" stroke="none" fill="currentColor" data-view-type="laser" d="M125.9,352.1h18.9L119,291.7h-16.2l-25,60.4h18.2l14.6-38.9L125.9,352.1z M323.6,322 c0,8.8-6.1,16.4-15.4,16.4c-9.1,0-15.4-7.6-15.4-16.4s6.1-16.4,15.2-16.4C317,305.6,323.6,313.4,323.6,322 M340.5,322.3 c0-17.4-13.4-31.3-32.3-31.3c-18.7,0-32.3,14.1-32.3,31.3c0,17.4,13.4,31.3,32.3,31.3C326.9,353.6,340.5,339.4,340.5,322.3 M230.4,322.5c0-8.8,6.1-16.4,14.9-16.4c3,0,5.8,0.8,8.1,2l6.6-13.4c-3-2-8.1-3.8-14.9-3.8c-18.2,0-31.6,14.1-31.6,31.3 c0,18.2,12.6,31.1,31.6,31.1c17.2,0,26-10.6,28.8-21l-13.6-5.6c-1.8,5.8-6.3,11.6-14.4,11.6C236.5,338.4,230.4,331.4,230.4,322.5 M38,322.5c0-8.8,6.1-16.4,14.9-16.4c3,0,5.8,0.8,8.1,2l6.6-13.4c-3-2-8.1-3.8-14.9-3.8c-18.4,0-31.8,14.1-31.8,31.3 c0,18.2,12.6,31.1,31.6,31.1c17.2,0,26-10.6,28.8-21l-13.6-5.6c-1.8,5.8-6.3,11.6-14.4,11.6C44,338.4,38,331.4,38,322.5 M191.8,352.1h14.4v-59.8H190v33.1l-25-33.1h-15.4v60.1h16.2v-34.1L191.8,352.1z M411.2,352.1v-59.8h-17.7l-14.4,23.2l-14.4-23.2 h-17.7v60.1h16.4V318l15.4,23.2h0.3l15.4-23.5v34.6L411.2,352.1L411.2,352.1z" fill-rule="nonzero"></path></svg>'''
|
||||||
|
|
||||||
logo_html = ""
|
logo_html = ""
|
||||||
@@ -138,7 +141,7 @@ def generate_welcome_html(customer_names, logo_urls, site="stuttgart"):
|
|||||||
width: 100vw; height: 100vh; overflow: hidden;
|
width: 100vw; height: 100vh; overflow: hidden;
|
||||||
font-family: 'Segoe UI', 'Helvetica Neue', sans-serif;
|
font-family: 'Segoe UI', 'Helvetica Neue', sans-serif;
|
||||||
display: flex; align-items: center; justify-content: center;
|
display: flex; align-items: center; justify-content: center;
|
||||||
background-image: url("/static/wallpaper.png");
|
background-image: url("{bg_image}");
|
||||||
background-repeat: no-repeat; background-size: cover;
|
background-repeat: no-repeat; background-size: cover;
|
||||||
}}
|
}}
|
||||||
.screen {{
|
.screen {{
|
||||||
@@ -212,14 +215,15 @@ def generate_welcome_html(customer_names, logo_urls, site="stuttgart"):
|
|||||||
# Speichern + Playlist-Einfügung
|
# Speichern + Playlist-Einfügung
|
||||||
# -------------------------------------------------
|
# -------------------------------------------------
|
||||||
|
|
||||||
def save_welcome_page(customer_names, logo_urls, site="stuttgart"):
|
def save_welcome_page(customer_names, logo_urls, site="stuttgart", background_url=None):
|
||||||
"""Speichert die generierte Willkommensseite als welcome.html im Lobby-Verzeichnis.
|
"""Speichert die generierte Willkommensseite als welcome.html im Lobby-Verzeichnis.
|
||||||
|
background_url: Benutzerdefiniertes Hintergrundbild oder None (Standard).
|
||||||
Gibt den Dateinamen zurück oder None bei Fehler."""
|
Gibt den Dateinamen zurück oder None bei Fehler."""
|
||||||
try:
|
try:
|
||||||
welcome_dir = os.path.join(MEDIA_DIR, site, "lobby")
|
welcome_dir = os.path.join(MEDIA_DIR, site, "lobby")
|
||||||
os.makedirs(welcome_dir, exist_ok=True)
|
os.makedirs(welcome_dir, exist_ok=True)
|
||||||
filepath = os.path.join(os.path.abspath(welcome_dir), WELCOME_FILENAME)
|
filepath = os.path.join(os.path.abspath(welcome_dir), WELCOME_FILENAME)
|
||||||
html_content = generate_welcome_html(customer_names, logo_urls, site=site)
|
html_content = generate_welcome_html(customer_names, logo_urls, site=site, background_url=background_url)
|
||||||
|
|
||||||
with open(filepath, "w", encoding="utf-8") as f:
|
with open(filepath, "w", encoding="utf-8") as f:
|
||||||
f.write(html_content)
|
f.write(html_content)
|
||||||
|
|||||||
@@ -200,6 +200,11 @@
|
|||||||
<i class="ti ti-settings me-1"></i>Einstellungen
|
<i class="ti ti-settings me-1"></i>Einstellungen
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<a href="#actions-{{ screen }}" class="nav-link" data-bs-toggle="tab" role="tab">
|
||||||
|
<i class="ti ti-click me-1"></i>Aktionen
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a href="#media-{{ screen }}" class="nav-link" data-bs-toggle="tab" role="tab">
|
<a href="#media-{{ screen }}" class="nav-link" data-bs-toggle="tab" role="tab">
|
||||||
<i class="ti ti-upload me-1"></i>Medien
|
<i class="ti ti-upload me-1"></i>Medien
|
||||||
@@ -310,7 +315,15 @@
|
|||||||
<label class="form-check-label">Videos anzeigen</label>
|
<label class="form-check-label">Videos anzeigen</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-4">
|
<button type="submit" class="btn btn-primary">
|
||||||
|
Einstellungen speichern
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══ Tab: Aktionen ═══ -->
|
||||||
|
<div class="tab-pane" id="actions-{{ screen }}" role="tabpanel">
|
||||||
|
<form action="/admin/{{ current_site }}/update/{{ screen }}" method="post">
|
||||||
<h3>Aktions-Button (Player)</h3>
|
<h3>Aktions-Button (Player)</h3>
|
||||||
<div class="form-check form-switch mb-3">
|
<div class="form-check form-switch mb-3">
|
||||||
<input class="form-check-input" type="checkbox"
|
<input class="form-check-input" type="checkbox"
|
||||||
@@ -335,7 +348,6 @@
|
|||||||
<option value="redirect" {% if cfg.custom_url_target|default('overlay') == 'redirect' %}selected{% endif %}>Weiterleitung (gleiches Fenster)</option>
|
<option value="redirect" {% if cfg.custom_url_target|default('overlay') == 'redirect' %}selected{% endif %}>Weiterleitung (gleiches Fenster)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary">
|
<button type="submit" class="btn btn-primary">
|
||||||
Einstellungen speichern
|
Einstellungen speichern
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -155,13 +155,56 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════
|
||||||
|
Karte: Hintergrundbild hochladen (pro Standort)
|
||||||
|
═══════════════════════════════════════════════════ -->
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="row align-items-center">
|
||||||
|
<div class="col">
|
||||||
|
<div class="page-pretitle">Willkommensseite</div>
|
||||||
|
<h2 class="page-title">Hintergrund</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label">Aktuelles Hintergrundbild</label>
|
||||||
|
<div class="logo-preview-box" style="min-height:200px; background: #f0f0f0;">
|
||||||
|
<img src="{{ background_url or '/static/wallpaper.png' }}" alt="Hintergrund" style="max-height:180px; width:100%; object-fit:contain; background:transparent; padding:0;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label">Neues Hintergrundbild hochladen</label>
|
||||||
|
<form method="POST" action="/admin/{{ site }}/upload-background" enctype="multipart/form-data">
|
||||||
|
<input type="file" class="form-control mb-2" name="background" accept=".jpg,.jpeg,.png" required>
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
<i class="ti ti-upload me-1"></i>Hochladen
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{% if background_url %}
|
||||||
|
<form method="POST" action="/admin/{{ site }}/delete-background" class="mt-2">
|
||||||
|
<button type="submit" class="btn btn-outline-danger">
|
||||||
|
<i class="ti ti-trash me-1"></i>Zurücksetzen auf Standard
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
<p class="text-muted mt-2 mb-0 small">
|
||||||
|
<i class="ti ti-info-circle me-1"></i>
|
||||||
|
Wenn kein Hintergrundbild hochgeladen ist, wird das Standard-Wallpaper verwendet.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="app-footer">
|
<footer class="app-footer">
|
||||||
{% include "_footer.html" %}
|
{% include "_footer.html" %}
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
window.addEventListener("load", () => {
|
window.addEventListener("load", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user