- Rust 86.6%
- Slint 8.4%
- Shell 3.8%
- PowerShell 1.2%
|
All checks were successful
test / test (push) Successful in 10m13s
release / test (push) Successful in 7m24s
release / build-rpm (push) Successful in 30m30s
release / build-windows (push) Successful in 16m28s
release / build-deb (push) Successful in 16m46s
release / release (push) Successful in 24s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| .vscode | ||
| deploy | ||
| examples | ||
| packaging | ||
| scripts | ||
| src | ||
| ui | ||
| vendor | ||
| .gitignore | ||
| build.rs | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| Plan.md | ||
| PLAN_WINDOWS.md | ||
| README.md | ||
| VERBESSERUNGEN.md | ||
ngenSermon2Usb
Angelehnt an die bestehende USB Tankstelle, um Gottesdienste und andere Veranstaltungen per Auswahl auf einen USB Speicher zu kopieren.
Konzept & Umsetzungsstand
Hinweis: Dieses Dokument beschreibt Konzept und Zielbild. Große Teile sind inzwischen umgesetzt (Stand v0.0.38 — u. a. Slint-GUI, Kopier-/Cache-/Nextcloud-Logik, Hintergrunddienst, HTTPS-Server, Update-Mechanismus, Browser-Tab). Einzelne Punkte beschreiben noch Geplantes und sind im Text als solche markiert („eingeplant", „vorerst", „zu prüfen").
- Umgesetzt in Rust mit Slint als GUI-Toolkit.
- Quellen für die Gottesdienste und Veranstaltungen: ein Nextcloud-Ordner.
- Pro Gottesdienst bzw. Veranstaltung gibt es einen Ordner mit MP3-Dateien und einer JSON- oder TXT-Datei.
- Ein Ordner wird erst dann in die dem Benutzer angezeigte Liste aufgenommen, wenn die zugehörige JSON- oder TXT-Datei vorhanden ist.
- Die GUI zeigt auf der linken Seite eine Übersicht über den USB-Speicher an und reagiert dabei auch auf das An- und Abstöpseln des Speichers.
- Im Hauptbereich gibt es eine Auswahl, welchen Veranstaltungstyp man möchte. Diese Liste lässt sich in einem passwortgeschützten Settings-Bereich verwalten.
- Zusätzlich soll es eine HTTPS-Einstellungsseite und eine HTTPS-Statusseite geben, die ebenfalls passwortgeschützt sind.
Technische Entscheidungen
Nextcloud / Datenquelle
- Zugriff ohne lokalen Nextcloud-Client, direkt per API/WebDAV.
- App-Passwort wird automatisch über den Login Flow v2 angelegt (einmalige Browser-Bestätigung); das echte Nutzerpasswort wird nicht gespeichert.
- Lokaler Cache für Offline-Betrieb und schnellere Anzeige (s. Abschnitt Lokaler Cache).
- Aktualisierung primär per Push (kein dauerndes Pollen):
notify_push(App „Client Push") — der Client öffnet ausgehend eine WebSocket-Verbindung (wss://<server>/push/ws, Endpunkt aus der Capabilities-APInotify_push.endpoints.websocket), authentifiziert mit Benutzername + App-Passwort und empfängt Ereignisse (notify_file,notify_activity, …).- Das Ereignis ist nur ein Signal „etwas hat sich geändert" (in neueren Versionen mit Pfad-Präfix), nicht der Diff → daraufhin ein gezielter, kurzer Scan des betroffenen Ordners statt Vollabgleich.
- Vorteil: Client verbindet sich nach außen → funktioniert hinter NAT/Firewall (LAN-Kiosk + externe Nextcloud). Voraussetzung serverseitig: App
notify_pushaktiv (seit ~NC 21 gebündelt) + Redis.
- Polling alle 3 Minuten nur als Fallback, falls
notify_pushnicht verfügbar ist oder der Socket abreißt (Reconnect mit Backoff). - (Webhooks-App
webhook_listeners, NC 30+, scheidet meist aus: Nextcloud müsste den Kiosk erreichen können — bei LAN-Kiosk + externer Cloud nicht gegeben.)
Gleichzeitige Anfragen begrenzen
Mehrere gleichzeitige Aufrufe an Nextcloud werden bewusst eingeschränkt (verhindert Server-Überlast/Drosselung und schont die Kiosk-Ressourcen; glättet auch die notify_push-getriggerten Nachladungen):
- Eine gemeinsame HTTP-Client-Instanz mit Connection-Pool/Keep-Alive (z. B.
reqwest) — kein neuer Connect pro Datei. - Begrenzte Parallelität per Semaphore, kleines konfigurierbares Limit (Default 2–4 gleichzeitige Requests); überschüssige Arbeit in eine Queue (FIFO).
- Backoff/Retry bei 429/503, dabei den
Retry-After-Header respektieren. - Ggf. getrennte Limits für leichte Metadaten-/List-Requests vs. große Datei-Downloads.
- Beim Kopieren seriell oder max. 2 parallel — der USB-Schreibvorgang ist meist ohnehin der Flaschenhals.
Lokaler Cache
- Einstellbare Schwelle, ab der der Cache reduziert wird — z. B. als maximale Cache-Größe oder als minimal freizuhaltender Speicher. Mit Hysterese: beim Überschreiten der oberen Schwelle wird bis zu einer unteren Schwelle aufgeräumt, damit nicht ständig nachgeräumt wird.
- Verdrängungsstrategie als Kompromiss zwischen „ältestes zuerst löschen" und „am wenigsten gebraucht löschen": pro Eintrag ein Score aus Alter (letzter Zugriff/Download) und Nutzungshäufigkeit; Einträge mit dem niedrigsten Score zuerst entfernen. Gewichtung der beiden Faktoren konfigurierbar.
- Geschützt vor Löschung: gerade angezeigte/markierte oder aktuell kopierte Veranstaltungen.
- Cache-Pfad in den Settings einstellbar: Der Speicherort des lokalen Caches lässt sich konfigurieren (z. B. auf eine größere/andere Platte legen).
- Unkritisch, da die Quelle Nextcloud bleibt — verworfene Cache-Daten lassen sich bei Bedarf jederzeit neu laden.
- Cache-Pfad, Schwelle und Gewichtung werden im passwortgeschützten Settings-Bereich eingestellt.
Gottesdienst-Struktur (Quelle: ngenAudioRecord)
- Die Gottesdienste werden vom Schwesterprojekt ngenAudioRecord erzeugt. Nur der MP3-Export wird nach Nextcloud gespeichert — der Aufnahme-Ordner mit Rohdaten (
session.raw, WAV, Peaks) nicht. - Pro Gottesdienst ein Unterordner mit den MP3-Dateien.
- ngenAudioRecord legt beim Fertigstellen die zugehörige JSON- oder TXT-Datei im Export-Ordner an. Dieses Vorhandensein ist genau der Trigger, dass der Ordner „fertig" ist und in der Liste erscheint.
- Ordnername trägt das Datum am Anfang im Schema
YYYY-MM-DD …(aus ngenAudioRecordspath_template"{date} {sorthelper} {daytime}", z. B.2026-06-18 c Mittag). Daraus lassen sich Jahr und Monat zuverlässig ableiten.- Im Produktivsystem erzeugt die Export-Pfad-Vorlage in ngenAudioRecord diesen datierten Pro-Event-Unterordner bereits. (Nur im Testsystem ist
export_path_templateleer/flach.)
- Im Produktivsystem erzeugt die Export-Pfad-Vorlage in ngenAudioRecord diesen datierten Pro-Event-Unterordner bereits. (Nur im Testsystem ist
Zusatzdatei (JSON/TXT)
- Für die Anzeige ist zunächst nur wichtig, dass eine Datei existiert (s. o. Trigger).
- Anzeige-Text des Albums = Dateiname der JSON/TXT ohne Endung (kein Parsen des Inhalts nötig). Beitragstitel = MP3-Dateiname ohne Endung.
- Datum und Tageszeit kommen weiterhin aus dem Ordnernamen (
YYYY-MM-DD …). - Parsen der Inhalte ggf. später (für reichere Titel/Metadaten).
Veranstaltungstypen & Ordner-Zuordnung
- Je Veranstaltungstyp ein eigener Nextcloud-Oberordner (z. B.
Gottesdienste/,Konferenzen/,Seminare/). - Die Zuordnung Typ → Oberordner erfolgt manuell in den Settings (Anzeigename ⇄ Nextcloud-Pfad). Die Veranstaltungstyp-Liste im Hauptbereich speist sich daraus.
USB-Speicher
- Plug/Unplug-Erkennung: unter Linux via udev, unter Windows selbst ermittelt.
- Mehrere Sticks werden vorerst physikalisch verhindert (Mehrfach-Unterstützung evtl. später).
- Ziel-Layout: Album-Ordner direkt in den Wurzelordner des Sticks.
Kopier-Modi
- Standard (ohne Autoradio): kompletter Veranstaltungsordner mit Struktur, ohne Umbenennung.
- Autoradio-Optimierung (per GUI-Option) — wirkt nur auf die Dateinamen:
- Umbenennung der MP3s, Albumname vorangestellt.
- FAT32-Sanitizing (Umlaute/Sonderzeichen ersetzen).
- Flache Struktur (keine Unterordner).
- Track-Nummern-Präfix für die richtige Reihenfolge.
Verhalten bei vorhandenem Album
- Bereits vorhandenes Album wird einfach überschrieben, mit Meldung „schon vorhanden".
Kopiert-Status
- Erkennung zuerst nur nach Ordnername (Album liegt auf dem Stick → „✓ kopiert").
- Ein Button „Vollständigkeit" ist eingeplant (späterer Abgleich von Dateianzahl/-größe, um unvollständige Kopien zu erkennen).
Sortierung
- Liste nach Datum absteigend (neueste oben), innerhalb eines Tages nach Tageszeit (
sorthelpera–f). - Tracks im Album nach Dateiname / Track-Nummer.
Abbrechen
- Während des Kopierens gibt es einen Abbrechen-Button. Beim Abbrechen wird gefragt:
- aktuellen Beitrag noch fertig kopieren und dann stoppen, oder
- alles bereits Kopierte der Auswahl wieder löschen (Rollback).
Speicher freigeben (Aufräum-Optionen)
Wählbare Möglichkeiten, um Platz auf dem USB-Speicher zu schaffen (z. B. wenn der Platz nicht reicht). Jeweils mit Bestätigung, da löschend:
- Gezielt löschen (Ordner/Album auswählen): einen oder mehrere bestimmte Ordner bzw. Alben auf dem Stick auswählen (Mehrfachauswahl) und gezielt entfernen.
- Alles löschen (Formatieren): kompletten Stick als FAT32 formatieren — entfernt alle Daten.
- Älteste löschen (nach Album/Ordnername): Veranstaltungsordner mit dem ältesten Datum im Ordnernamen (
YYYY-MM-DD-Präfix, = MP3-Album) zuerst entfernen. - Zuerst gespeicherte löschen (nach Dateizugriffsdatum): nach dem Zeitpunkt der Speicherung auf dem Stick (Datei-Zeitstempel) — die zuerst kopierten Dateien zuerst entfernen.
Bei den automatischen „Löschen"-Varianten (Älteste / Zuerst gespeicherte) wird so lange entfernt, bis genug Platz frei ist.
Verfügbarkeit: Das gezielte Löschen wird jederzeit als eigene Aktion angeboten und zusätzlich, wenn der Platz auf dem USB-Speicher knapp wird (zusammen mit den übrigen Aufräum-Optionen).
- Vorschau vor dem Löschen: Bevor tatsächlich gelöscht wird, zeigt eine Vorschau genau, welche Ordner (Alben) entfernt würden — bzw. einzelne Dateien, falls lose Dateien direkt im Wurzelverzeichnis des Sticks liegen. Erst nach Bestätigung wird gelöscht.
GUI: Der Unterschied zwischen Variante 2 und 3 wird dem Nutzer angezeigt — Variante 2 richtet sich nach dem Veranstaltungsdatum (Ordnername), Variante 3 danach, wann auf den Stick kopiert wurde (Dateizeitstempel). Diese kurze Erklärung steht direkt bei den beiden Optionen (s. GUI-Skizze: „Speicher freigeben").
Settings & Passwörter
- Passwörter möglichst sicher, als Hash gespeichert.
- Getrennte Passwörter für GUI-Settings und HTTPS-Seiten; jeweils vorerst nur ein Passwort.
- GUI-Settings und HTTPS-Settings sind inhaltlich identisch (gleicher Funktions-/Einstellungsumfang, dieselbe darunterliegende Konfiguration) — nur die Oberfläche unterscheidet sich (lokale Touch-GUI vs. Browser im LAN).
Anweisung für AI/Implementierung: GUI-Settings und HTTPS-Settings immer gleich/synchron halten. Wird eine Einstellung an einer Stelle hinzugefügt oder geändert, ist sie an der anderen mitzuführen; beide greifen auf dieselbe Konfigurationsquelle zu.
- Der Nextcloud-Login (Login Flow v2) lässt sich daher von beiden Oberflächen anstoßen (lokal mit Touch-Tastatur oder über die HTTPS-Seite von einem anderen Gerät).
- Die Veranstaltungstyp-Liste wird lokal geführt, mit Backup in Nextcloud.
- Auswahl bei Gottesdiensten nach Jahr und Monat (abgeleitet aus dem
YYYY-MM-DD-Präfix des Ordnernamens, s. Gottesdienst-Struktur).
Konfigurations-Ebenen — wo welche Einstellung
Der Kiosk hat mehrere Konfigurations-Ebenen; nicht jede Einstellung gehört in dieselbe.
Die Ebenen:
- Runtime-Settings — GUI = HTTPS, passwortgeschützt, dieselbe Konfigquelle (s. Settings & Passwörter). Was ein Betreuer im Betrieb ohne Root/Neuinstallation ändern soll.
- Lokale Konfig/Zustand — von der App selbst geschrieben, nicht von Hand gepflegt (Hashes, Token, Cache-Index, aktuelle Version).
- Nextcloud-Backup — Teilmenge der Runtime-Settings, für Wiederherstellung.
- Install-Zeit — Agama-Profil + First-Boot-Script, einmalig beim Aufsetzen (OS-/Root-Ebene; s. Kiosk-Installation (openSUSE Leap 16)).
- Paket/RPM — technische Systemintegration, kommt mit dem Update mit (via
.spec), nicht von Hand (s. Build-Script & Paketierung). - Build/CI-Zeit — Geheimnisse + Versionierung in Forgejo Actions.
Zuordnung:
| Einstellung | Ebene | Begründung |
|---|---|---|
| Veranstaltungstyp ↔ Nextcloud-Oberordner | Runtime + NC-Backup | fachlich, ändert sich oft; Liste lokal geführt, Backup in NC |
| Nextcloud-Login (Login Flow v2), App-Passwort | Runtime (anstoßen) + Lokal (Token sicher/Hash) | von beiden Oberflächen auslösbar; Geheimnis nie im Klartext |
| Cache: Pfad, Schwellen, Score-Gewichtung | Runtime | fachliche Tuning-Größen (s. Lokaler Cache) |
| Autoradio-Standard, USB-Verhalten | Runtime | Bedien-Default |
| Feiertage (Liste/Auswahl/Import) | Runtime + NC-Backup | inhaltlich, pflegbar (s. Feiertage) |
| Passwörter (GUI/HTTPS) | Runtime (setzen) → Lokal als Hash | s. Settings & Passwörter |
| Concurrency-Limit (2–4) | Runtime | bewusst konfigurierbar (s. Gleichzeitige Anfragen begrenzen) |
| Update-Kanal, Prüfintervall/Zeitfenster, Auto-Install | Runtime | s. Automatischer Update-Mechanismus |
| HTTPS-Port | Runtime (mit OS-Kopplung, s. u.) | Port wählbar |
Home-Assistant-Browser: Start-URL, Dashboard, Benutzer, Passwort, Kiosk, Button-Beschriftung (homeassistant-Sektion) |
Runtime (GUI = HTTPS) | s. Browser-Tab (Home-Assistant-Seite, Servo); Passwort vom NC-Backup ausgenommen |
| Sprache/Tastatur/Zeitzone (de_DE) | Install-Zeit | „vorerst nur Deutsch" → fix, kein Runtime-Umschalter |
| Hostname, Netzwerk (DHCP/statisch/WLAN) | Install-Zeit | OS-Grundlage, selten geändert |
Kiosk-User + Autologin, graphical.target |
Install-Zeit | einmalige Provisionierung |
Pakete (cage, App), Forgejo-.repo + Token |
Install-Zeit | Bootstrapping der Update-Quelle |
transactional-update/btrfs-Snapshots |
Install-Zeit | Rollback-Fundament |
cage@.service, Daemon-Unit, udev-/polkit-Regel, Update-Timer |
Paket/RPM | gehört zur App-Version, kommt mit Updates mit |
| GPG-Signaturschlüssel, Registry-Upload-Token | Build/CI | Secrets in Forgejo Actions, nie ins Image |
| Version/Release | Build/CI | aus Git-Tag |
Faustregel:
- Fachlich / ändert sich im Betrieb → Runtime (GUI=HTTPS).
- Braucht Root, einmalig beim Aufsetzen → Install-Zeit (Agama).
- Technisch + versionsgebunden → ins RPM (kommt mit Updates).
- Geheim → CI-Secret bzw. lokaler Schlüsselspeicher, nie in Settings/Image.
Kopplungen (Runtime-Setting mit OS-Wirkung): Diese sind Runtime-Settings, wirken aber auf OS-Ebene — deshalb setzt sie der privilegierte Hintergrunddienst um (s. Hintergrunddienst):
- HTTPS-Port ändern → Daemon passt die firewalld-Regel an.
- Cache-Pfad auf andere Platte → Ziel muss gemountet sein (fstab = Install-Zeit) → Daemon prüft/meldet, wenn es fehlt.
- Update-Zeitfenster → der
systemd-Timer feuert regelmäßig, aber der Daemon entscheidet anhand von Zeitfenster und „kein Kopiervorgang aktiv" → OS-Ebene bleibt statisch, nur die App-Logik kennt den Zustand.
Feiertage
- In den Settings wird eine Namensliste der Feiertage angezeigt; einzelne Feiertage sind auswählbar (welche markiert/berücksichtigt werden).
- Eine deutschlandweite Feiertagsliste kann aus dem Internet geholt werden.
- Von Hand lassen sich weitere Feiertage hinzufügen.
- Feiertage steuern die abweichende Zeilen-Markierung in der Gottesdienst-Liste (s. Listendarstellung).
HTTPS-Server (Einstellungs-/Statusseite)
- Erreichbar nur im LAN / lokal.
- Nicht öffentliches Zertifikat (selbstsigniert / lokal).
- Statusseite zeigt Kopiervorgänge und Logs.
- Integrierter Dateibrowser (Cache + USB): zeigt den lokalen Cache und den USB-Inhalt zur Diagnose. In den eigenen HTTPS-Server integriert (z. B.
axummittower-httpServeDirbzw.actix-files), hinter dem bestehenden HTTPS-Passwort — also kein zweites Login. (Nextcloud-Inhalt bleibt über die Nextcloud-Web-UI browsbar.) - HTTPS-Passwort beim ersten Aufruf anlegen: Beim ersten Aufruf der HTTPS-Seite muss zuerst ein Passwort festgelegt werden, bevor Zugriff gewährt wird.
- Nextcloud-Verbindung über die HTTPS-Einstellungsseite einrichtbar: Die Verbindung zu Nextcloud (Login Flow v2) lässt sich auch über die HTTPS-Einstellungsseite einrichten (GUI- und HTTPS-Settings sind identisch).
- Der Server soll die GUI möglichst gar nicht beeinträchtigen: läuft in einem eigenen Thread / eigener Runtime (z. B.
tokioauf einem Hintergrund-Thread), getrennt vom Slint-UI-Thread. Kein Blockieren des UI-Threads, niedrigere Priorität; Datenaustausch nur über entkoppelte, nicht-blockierende Kanäle (z. B. geteilter Zustand/Channel statt direkter UI-Aufrufe).
Browser-Tab (Home-Assistant-Seite, Servo)
Über den Button 🌐 Browser öffnet sich ein Tab mit Adressleiste („‹ Zurück", URL-Zeile, „Öffnen") und Seiten-Ansicht; die Start-URL wird beim Öffnen automatisch geladen. Gedacht für das Home-Assistant-Dashboard (passwortgeschützt, s. u.); Hintergrund und Windows-Plan: PLAN_WINDOWS.md, Phase 4.
Warum Servo: Die Browser-Engine (Servo, Crate servo 0.4 von crates.io) läuft im Prozess und rendert in einen von uns kontrollierten Kontext. Unter cage/Wayland ist das der einzige Weg zu einer Browser-Ansicht im Slint-Fenster (eingebettete Webviews à la wry brauchen Child-Windows, die es unter Wayland nicht gibt) — und derselbe Code trägt später die Windows-Variante.
Bauen & Entwickeln:
- Nur mit
cargo build --features browser-servoeinkompiliert; ohne das Feature zeigt der Tab einen Status-Platzhalter. Erstbau zieht ~1100 zusätzliche Crates. - SpiderMonkey kommt automatisch als Prebuilt von den servo/mozjs-GitHub-Releases (Build-Script lädt per curl) — kein clang/llvm nötig; nur bei Download-Fehlschlag wird aus Quellen gebaut (
MOZJS_ARCHIVEkann eine lokale Kopie vorgeben). primeorderist inCargo.lockauf0.14.0-rc.14festgehalten. servo-script pinnt die Kurven-Crates hart aufp256/p521 =0.14.0-rc.14; das stabileprimeorder 0.14.0verlangt neuScalar: WnafSizeund bricht die RC-Crates (error[E0277]). Wird der Lock neu erzeugt, den Pin wieder setzen:cargo update -p primeorder --precise 0.14.0-rc.14. Deshalb wirdCargo.lockeingecheckt (Release-Builds laufen mit--locked).- Debug-Profil ist spürbar langsam (Servo/Layout unoptimiert) — für echte Seiten-Tests
--releasebzw. die VS-Code-Task „cargo build --release (browser-servo)". VS Code: Launch-Konfiguration „GUI + Daemon (Servo-Browser)";.vscode/settings.jsonaktiviert das Feature für rust-analyzer (sonst giltsrc/browser.rsals inaktiver Code). - Die LLDB-Meldung „no plugin for the language rust" beim Debuggen ist harmlos (nur eingeschränkte Variablen-Anzeige mancher Typen).
Architektur (src/browser.rs, Feature browser-servo):
- Rendern: Servo zeichnet per WebRender in einen
SoftwareRenderingContext(CPU/llvmpipe); beinotify_new_frame_readywird der Puffer mitread_to_imageausgelesen und alsslint::Imagein diebrowser-frame-Property gelegt. Renderer-unabhängig (femtovg heute, Skia für Windows) — bewusst kein GL-Textur-Sharing. Wichtig: keinpresent()(der Software-SwapChain verwirft dabei den Puffer). - Ereignisschleife: Servos
EventLoopWakerstößt überslint::invoke_from_event_loopspin_event_loopan; ein 33-ms-Pump-Timer treibt Animationen und gleicht die Viewport-Größe mit der Sichtfläche ab. - Eingaben: Maus/Scrollrad/Tastatur laufen aus
ui/app-window.slint(TouchArea/FocusScope) über die Callbacksbrowser-pointer/browser-scroll/browser-keynach Servo (Koordinaten: logische Pixel × Skalierungsfaktor). - Schließen verwirft die WebView (Sitzung/Speicher frei, kein persistentes Profil); die Engine bleibt für erneutes Öffnen bestehen.
Automatische HA-Anmeldung: Konfig-Sektion homeassistant (JSON-Konfigdatei):
"homeassistant": {
"url": "http://homeassistant.fritz.box",
"dashboard": "dashboard-bg",
"username": "kiosk",
"password": "…",
"kiosk": true,
"button_label": "🌐 Browser"
}
Alle Felder sind in beiden Settings-Oberflächen editierbar (lokale Touch-GUI wie HTTPS-Seite, gemäß der GUI=HTTPS-Synchronität):
url— Basis-URL der HA-Instanz (Host der Anmeldung).dashboard—url_pathdes Ziel-Dashboards (z. B.dashboard-bg,lovelace); leer = HA-Standard-Dashboard. Die Start-URL des Tabs isturl+/+dashboard. Ein Button „Dashboards von HA laden" listet die vorhandenen Dashboards (per HA-Login-Flow + WebSocketlovelace/dashboards/list) zum direkten Auswählen auf (s.src/homeassistant.rs).username/password— für den Auto-Login; leerer Benutzer/Passwort = kein Auto-Login. Sicherheitsunterschied: Die lokale GUI zeigt das gespeicherte Passwort (maskiert) im Feld; die HTTPS-Seite rendert das Passwortfeld leer (das Geheimnis geht nicht über die Leitung in den Seitenquelltext) — dort bedeutet ein leeres Feld beim Speichern „unverändert lassen".kiosk(Standardtrue) — app-seitiger Kiosk-Modus: Im Tab wird die Adressleiste ausgeblendet (nur „‹ Zurück" bleibt), nach dem Laden blendet ein injiziertes JavaScript HA-Kopfzeile und Seitenleiste aus (über die Shadow-DOM-Bäume, analog zum Community-Plugin kiosk-mode), und ein Navigations-Guard leitet auf die Dashboard-URL zurück, sobald eine Seite den HA-Host verlassen würde. So zeigt der Kiosk nur das eine Dashboard, ohne serverseitige HA-Änderung. (Best effort; die Chrome-Ausblendung hängt an HA-internen Selektoren — Gerätetest s. „Offene Punkte".)button_label(Standard🌐 Browser) — Beschriftung des Buttons, der den Browser-Tab öffnet.
Passwort und Dashboard/Kiosk gelten für den HA-Tab; das Passwort ist vom Nextcloud-Backup ausgenommen.
Nach LoadStatus::Complete wird — nur wenn der Host der geladenen Seite dem Host der Config-URL entspricht — ein JavaScript injiziert, das das Login-Formular sucht (rekursiv durch alle Shadow-DOM-Bäume; die HA-Oberfläche ist eine Lit-App, normales querySelector findet die Felder nicht), Benutzer/Passwort mit input-Events einträgt und abschickt; Wiederholung alle 500 ms bis max. 20 s (SPA rendert das Formular erst nach load). Empfohlen: eigener nicht-administrativer HA-Benutzer mit nur dem einen Dashboard. Passwort wird nur ins Formular injiziert, nie angezeigt, und ist vom Nextcloud-Backup ausgenommen. Leerer Benutzer/Passwort = keine automatische Anmeldung.
vendor/surfman (gepatchtes surfman 0.12.3, derzeit deaktiviert): Seit servo 0.4 löst Cargo ohne den vendored surfman auf — der [patch.crates-io]-Eintrag in Cargo.toml ist daher auskommentiert und der Ordner wird für den Build nicht mehr benötigt. Er bleibt als Referenz erhalten, falls das GL-Problem wieder auftritt. Inhalt des Patches: ein kleiner Fix in create_context (x11/wayland/generic) — schlägt make_current direkt nach der Kontext-Erzeugung fehl, wird der halbfertige EGL-Kontext explizit zerstört und der echte Fehler zurückgegeben, statt dass surfmans Drop-Guard panict und ihn verschluckt. So landet ein GL-Problem als Statusmeldung im Tab statt als App-Absturz. Kandidat für einen Upstream-PR. Vollständige Erklärung des Patches (Diff, Begründung, Rekonstruktion): vendor/surfman-patch.md.
GL-Zusammenspiel Slint ↔ Servo (X11-Entwicklung vs. Wayland-Kiosk): Unter X11 (z. B. SSH-Forwarding) bindet Slint/glutin einen GLX-Kontext, Servo/surfman arbeitet mit EGL — Mesa sperrt beide Richtungen gegeneinander: eglMakeCurrent liefert BadAccess, solange GLX current ist (Symptom: Servo-Banner „Could not create any GL context"), und umgekehrt panict Slint beim Freigeben von GPU-Ressourcen zerstörter Teilbäume, wenn Servos EGL-Kontext gebunden bleibt („Fatal error … freeing graphics resources"). Lösung: gl_interop::ForeignGlGuard (RAII) um jeden Servo-GL-Zugriff — GLX-Zustand sichern und lösen, Servo arbeiten lassen, EGL lösen, GLX wiederherstellen. Unter Wayland/cage (Kiosk) existiert kein GLX → No-Op; andere Plattformen kompilieren leer.
Offene Punkte:
- Test auf dem Kiosk-Gerät: Scroll-Richtung (Vorzeichen-Konvention von
notify_scroll_event), llvmpipe-Performance. - Auto-Login, Kiosk-Chrome-Ausblendung, Dashboard-Auflistung sind gegen HA 2026.7.2 verifiziert (Anmeldung läuft, linke Spalte/Kopfzeile weg, Fensterschließen ohne Absturz). Sie hängen aber an HA-internen Shadow-DOM-Strukturen: Login klickt den
ha-button„Anmelden" und füllt die Felder per nativem Value-Setter; die Chrome-Ausblendung blendetha-drawer→.sidebar-shellaus und setzt--ha-sidebar-width: 0sowiehui-root .header. Bei größeren HA-Updates können die Selektoren nachzuziehen sein (s.LOGIN_JS/KIOSK_JSinsrc/browser.rs). - PIN-Schutz (
pin_hash) und Zeitlimit (max_minutes) aus PLAN_WINDOWS.md Phase 4 sind noch nicht umgesetzt. Laut „Offene Entscheidungen" dort ist das eine bewusste Wahl: Empfehlung ist der HA-Login als einzige Passwort-Hürde, PIN optional — deshalb vorerst nicht eingebaut.
Betrieb, Kiosk & Deployment
Zielplattform
- Kiosk-Modus unter Linux oder Windows.
- Bedienung per Touch: allgemein eine Touch-Tastatur anbieten (für Passwörter, Eingaben).
- Sprache: vorerst nur Deutsch.
Kiosk-Installation (openSUSE Leap 16)
- Zielbild: Das Gerät bootet direkt in die Vollbild-App — ohne Desktop/Login, mit Touch-Bedienung (s. Zielplattform). Wiederanlauf nach Absturz/Update automatisch.
- Unbeaufsichtigte OS-Installation per Agama (Leap 16 hat den YaST-Installer durch Agama ersetzt; klassisches AutoYaST entfällt): Start mit Kernel-Option
inst.auto=<URL-zum-Profil>. Das JSON-Profil beschreibt Partitionierung, Netzwerk, Lokalisierung (de_DE.UTF-8, Tastaturde, ZeitzoneEurope/Berlin), genau einen Benutzer mit Autologin, die Software-Auswahl (Minimal-Basis +cage+ das App-RPM) sowieinit/post-Skripte für die restliche Einrichtung. - Update-Quelle gleich mit einrichten: Das Install-Skript trägt die Forgejo-RPM-Registry als
.repoein (s. Automatischer Update-Mechanismus), sodass die App von dort installiert und später aktualisiert wird. - Kiosk-Laufzeit mit
cage(Wayland-Kiosk-Compositor: zeigt genau eine maximierte App und blockiert alles andere) — passt zu Slint (läuft nativ auf Wayland). Betrieb alssystemd-Service (cage@tty1.service) mit dem Autologin-User undRestart=always→ deckt zugleich den Watchdog/Autostart ab (vgl. Fehlerfall „Absturz der Anwendung"). Default-Targetgraphical.target. (Alternativen:westonmit kiosk-shell oderlabwc.) - Touch-Tastatur: bringt die App selbst mit (s. GUI-Skizze, Einstellungen) → keine separate Wayland-Bildschirmtastatur nötig.
- Systemintegration kommt aus dem RPM (via
.spec/%post, s. Build-Script & Paketierung) und wird beim Install/Update automatisch gesetzt:systemd-Units:cage@.service(App) und der privilegierte Hintergrunddienst (s. Hintergrunddienst).- udev-Regel für die USB-Plug/Unplug-Erkennung (s. USB-Speicher).
- polkit-/sudo-Regel für Formatieren und Mount/Unmount/Eject (gebündelt im Dienst, nicht in der GUI).
- firewalld: HTTPS-Port nur im LAN freigeben (s. HTTPS-Server; eine Port-Änderung zur Laufzeit setzt der Dienst um, s. Konfigurations-Ebenen).
- Rollback-Fundament: Dateisystem auf btrfs mit
transactional-update/Snapshots, damit fehlerhafte Updates automatisch zurückrollen (s. Automatischer Update-Mechanismus). - Alternative — fertiges Image mit KIWI: Statt „installieren + nachkonfigurieren" lässt sich ein vorkonfiguriertes Kiosk-Image bauen (sinnvoll bei vielen identischen Geräten; höherer Build-Aufwand). Für ein bis wenige Geräte ist der Agama-Weg einfacher.
Anleitung: Minimal-Kiosk von der ISO an (Leap 16)
Konkrete Schritte von der ISO bis zum laufenden Kiosk – nur das Nötigste. Für viele Geräte gibt es die unbeaufsichtigte Agama-Variante (s. Kasten am Ende).
1 · ISO laden. Von https://get.opensuse.org/leap/16.0/ das Network- oder
Offline-Installer-Image (x86_64). Prüfsumme verifizieren (die Dateien
*.iso.sha256 / .asc liegen daneben):
sha256sum -c openSUSE-Leap-16.0-*.iso.sha256
2 · Boot-Stick schreiben (⚠ /dev/sdX wird überschrieben – Zielgerät vorher
mit lsblk prüfen):
sudo dd if=openSUSE-Leap-16.0-*.iso of=/dev/sdX bs=4M status=progress oflag=sync
3 · Minimal installieren (ohne Desktop). Vom Stick booten; der Leap-16- Installer (Agama) fragt:
- Region: Sprache Deutsch, Tastatur
de, ZeitzoneEurope/Berlin. - Festplatte: ganze Platte, Vorgabe-Partitionierung – btrfs (Basis für
Rollback /
transactional-update). - Software: nur das Muster „Minimal Base"/Server, keinen Desktop.
- Benutzer: root-Passwort setzen.
Installieren, neu starten, an der Textkonsole als root anmelden.
4 · System aktualisieren und Kiosk-Benutzer anlegen (unter ihm läuft die Kiosk-Sitzung; kein Passwort nötig, die Unit meldet ihn selbst an):
zypper --non-interactive refresh
zypper --non-interactive update
useradd -m kiosk
5 · Registry einbinden, Signaturschlüssel importieren, App installieren:
# Forgejo-RPM-Registry (öffentlich). --gpg-auto-import-keys holt den
# Metadaten-Schlüssel; die .repo aktiviert gpgcheck bereits selbst.
zypper --non-interactive --gpg-auto-import-keys addrepo --refresh \
https://git.bg-ak.de/api/packages/leonhard.suckau/rpm.repo
# Maintainer-Schlüssel für die Paket-Signatur (rpmsign) importieren.
rpm --import https://git.bg-ak.de/leonhard.suckau/ngenSermon2Usb/raw/branch/main/deploy/RPM-GPG-KEY-ngensermon2usb
# Anwendung + Wayland-Kiosk-Compositor + Firewall.
zypper --non-interactive install --no-recommends ngensermon2usb cage firewalld
6 · In den Kiosk booten lassen (die systemd-Units kommen aus dem RPM):
systemctl set-default graphical.target
systemctl enable ngensermon2usb-kiosk@tty1.service # cage + App auf tty1
systemctl enable --now ngensermon2usb-daemon.service # privilegierter Dienst
systemctl enable --now firewalld
reboot
Nach dem Neustart bootet das Gerät vollflächig in die App: cage zeigt genau
die eine maximierte Anwendung, Restart=always fängt Abstürze ab, und die
Kiosk-Unit übernimmt tty1 (Conflicts=getty@tty1) – es erscheint kein
Login-Prompt.
7 · Erststart. Beim ersten Aufruf der HTTPS-Einstellungsseite ein Passwort
setzen und die Nextcloud-Verbindung einrichten (s. HTTPS-Server,
Settings & Passwörter). Updates kommen danach automatisch als RPM aus der
Registry (zypper); der App-eigene Mechanismus ist in Paket-Builds
abgeschaltet (s. Automatischer Update-Mechanismus).
Unbeaufsichtigt (viele Geräte): Statt Schritt 3–6 die Installation mit
inst.auto=<URL zu deploy/agama/ngensermon2usb-kiosk.json>starten. Das Profil setzt Lokalisierung +kiosk-Benutzer (Autologin) + Software-Auswahl und ruft beim ersten Bootdeploy/scripts/kiosk-setup.shauf (Registry, Schlüssel, Units aktivieren). Vorher dieCHANGEME-Passwörter im Profil ersetzen. Die Schritte 4–6 oben entsprechen genau dem, was dieses Skript automatisch tut.
Hintergrunddienst (zu prüfen)
- Vermutlich sinnvoll: ein eigener Hintergrunddienst (Daemon/Service), getrennt von der GUI. Begründung:
- Privilegierte Operationen wie Formatieren und Mount/Unmount/Eject brauchen oft erhöhte Rechte — besser gebündelt im Dienst als in der GUI.
- Läuft unabhängig von der GUI weiter: Nextcloud-Sync/Cache-Pflege, HTTPS-Server, Watchdog/Autostart.
- Die (unprivilegierte) GUI delegiert privilegierte/lange Aufgaben an den Dienst über eine lokale Schnittstelle (Socket/IPC).
- Genaue Aufteilung GUI ⇄ Dienst noch festzulegen.
- Zugriffskontrolle auf den Socket.
/run/ngensermon2usb.sockist dateisystemseitig für alle beschreibbar, weil die unprivilegierte Kiosk-GUI ihn erreichen muss. Wer darüber wirklich Befehle geben darf, entscheidet der Dienst perSO_PEERCRED: erlaubt sind root, der Benutzer des Dienstes selbst und die inipc_allowed_usersgenannten (Default:kiosk, passend zuUser=kioskinngensermon2usb-kiosk@.service). Ohne diese Prüfung könnte jeder lokale Prozess dem root-Dienst u. a.FormatUsb,SetConfigoderSetPasswordschicken — relevant, weil im GUI-Prozess der Servo-Browser entfernte Inhalte rendert. Läuft die GUI unter einem anderen Benutzer, muss dieser inipc_allowed_userseingetragen werden; abgewiesene Zugriffe stehen mit UID im Log. Änderungen wirken nach einem Dienst-Neustart.
Automatischer Update-Mechanismus
- Ziel: Der Kiosk läuft unbeaufsichtigt → Programm-Updates müssen automatisch, sicher und mit Rückfallebene ablaufen, ohne den laufenden Betrieb (v. a. Kopiervorgänge) zu stören.
- Auslieferung als RPM-Paket über die eingebaute Forgejo-Paket-Registry des bestehenden Git-Hosts (
git.bg-ak.de). RPMs sind GPG-signiert → Authentizität/Integrität prüft das Paketsystem; ein selbstgebauter Download-und-Austausch-Mechanismus entfällt. Kein externes openSUSE Build Service nötig. Bei privater Registry kommen die Zugangsdaten (Personal Access Token) in die.repo-Datei:https://<user>:<token>@git.bg-ak.de/api/packages/<owner>/<gruppe>.repo(passt zum Leap-16-Setup mitzypper). - Aus einem Paket installiert aktualisiert ausschließlich die Paketverwaltung. RPM/DEB setzen beim Bauen
NGEN_PACKAGED=1;--updatebricht dann mit Hinweis ab, und die Pakete liefern…-update.{service,timer}gar nicht erst mit. Grund:/usr/bin/ngensermon2usbgehört rpm/dpkg — ein Selbst-Austausch bräche deren Prüfsummen (rpm -V/dpkg -V), hinterließe die Sicherungskopie als unverwaltete Datei in/usr/binund würde beim nächstenzypper up/apt upgradeohnehin überschrieben. Der eingebaute Mechanismus bleibt für Installationen ohne Paketverwaltung erhalten; die Units liegen dafür weiterhin indeploy/systemd/. - Der Update-Ordner muss root gehören und darf für andere nicht schreibbar sein. Die
sha256ausmanifest.jsonbelegt nur Unversehrtheit, nicht Herkunft — das Manifest liegt ja im selben Ordner wie das Binary. Ein welt-schreibbarer Ordner erlaubte deshalb jedem lokalen Benutzer, dem als root laufenden Update-Dienst eigenen Code unterzuschieben (Rechteausweitung). Der Default ist daher/var/lib/ngensermon2usb/updatestatt eines Pfades unter/tmp. Werlocal_dirselbst setzt, muss dieselbe Bedingung einhalten. - Build & Veröffentlichung per Forgejo Actions (CI): Bei einem Release/Tag baut die CI das RPM und lädt es in die Forgejo-Registry hoch; die Kioske ziehen es danach automatisch per
zypper. Vorgeschaltet läuft eine Test-Stufe (cargo test+cargo clippy -D warnings): Sie hängt alsneeds:vor den Paket-Jobs, sodass aus rotem Code kein Paket entsteht. Dieselbe Stufe läuft als eigener Workflow (.forgejo/workflows/test.yml) bei jedem Push aufmainund bei Pull Requests — bewusst ohnebrowser-servo(ein Servo-Build dauert ~15 min und trägt zu den Logik-Tests nichts bei).cargo fmtist kein Gate, weil der Code eigener Formatierung folgt. - Auslösung per
systemd-Timer (kein Dauer-Polling): konfigurierbares Zeitfenster (z. B. nachts), prüft gezielt auf eine neue Version dieses einen Pakets statt vollem Distributions-Upgrade. - Client zieht aktiv vom Repo (ausgehende Verbindung) → funktioniert hinter NAT/Firewall (gleiche Logik wie bei
notify_push, s. Nextcloud / Datenquelle); keine eingehenden Verbindungen nötig. - Koordination mit dem Betrieb: Update nur, wenn kein Kopiervorgang läuft und der USB-Speicher nicht aktiv beschrieben wird; sonst auf das nächste Fenster verschieben. Der privilegierte Hintergrunddienst (s. Hintergrunddienst) führt das Update aus, da er Rechte und App-Zustand kennt.
- Atomar mit Rollback: vorzugsweise
transactional-update(btrfs-Snapshots) für atomare Updates mit automatischem Rollback bei fehlerhaftem Start; mindestens ein Healthcheck nach Neustart — startet die neue Version nicht sauber, automatischer Rückfall auf die vorige (Snapshot bzw. vorheriges RPM). - Neustart nach Update: Nach erfolgreichem Update wird der Kiosk-Service (App) im selben Wartungsfenster sauber neu gestartet (vgl. Autostart/Watchdog,
Restart=always). - Konfig-Migration: Bei Versionssprüngen werden Einstellungen automatisch migriert (vorwärtskompatibles Lesen, Defaults für unbekannte Felder — vgl. Fehlerfall „Konfiguration beschädigt").
- Einstellbar im passwortgeschützten Settings-Bereich (GUI und HTTPS identisch, s. Settings & Passwörter): Update-Kanal (Stabil/Test), Prüfintervall/Zeitfenster, automatisch installieren (ja/nein bzw. nur benachrichtigen).
- Status/Logs: Die HTTPS-Statusseite zeigt aktuelle Version, letzte erfolgreiche Aktualisierung, verfügbare Version und Update-Verlauf/Fehler. Im Kiosk höchstens ein dezenter Hinweis, keine technischen Details (s. Leitlinien Fehlerfälle & Meldungen).
- (Optional) OS-Sicherheitspatches können über denselben Timer mitlaufen (
zypper patch), bleiben aber konzeptionell getrennt vom App-Update.
Build-Script & Paketierung
- Ein einziges Build-Script (z. B.
scripts/build-rpm.sh), das lokal und in der CI identisch läuft („ein Skript, zwei Aufrufer") — so weicht der CI-Build nie vom Entwickler-Build ab. - Schritte des Scripts:
- Version aus dem Git-Tag ableiten (
git describe/Tag → RPM-Version/Release). - Release-Binary bauen:
cargo build --release(Slint-Frontend inklusive). - RPM paketieren aus einer
.spec-Datei (viarpmbuild): enthält das Binary plus die Kiosk-Dateien —cage@.service, Daemon-systemd-Unit, udev-Regel und polkit-Regel (s. Hintergrunddienst) — und%post-Scriptlets, die die Dienste aktivieren/neu starten (greift in den Update-Neustart, s. Automatischer Update-Mechanismus). (Alternative für einfache Fälle:cargo-generate-rpmohne volle.spec.) - RPM signieren (GPG) → wird beim Update vom Paketsystem geprüft.
- Upload in die Forgejo-RPM-Registry (nur in der CI; lokal optional per Flag).
- Version aus dem Git-Tag ableiten (
- Build in einer openSUSE-Leap-16-Umgebung (Container/Buildroot), damit das Binary zu glibc/Bibliotheksständen des Zielsystems passt. Ein Cross-Build vom Entwickler-Rechner (z. B. Fedora) direkt funktioniert nicht verlässlich: glibc ist nicht vorwärtskompatibel (ein auf neuerem System gebautes Binary läuft nicht auf älterem Leap), und systemd-RPM-Makros (
%service_add_postvs.%systemd_post) sowie Paketnamen unterscheiden sich zwischen den Distributionen. Deshalb lokal im Leap-Container bauen —podman run --rm -v "$PWD:/src:Z" -w /src registry.opensuse.org/opensuse/leap:16.0 ./scripts/build-rpm.sh(Wrapper:scripts/build-in-container.sh) — derselbe Aufruf wie in Forgejo Actions, dessen Runner ebenfalls im Leap-Image läuft. - Abhängigkeiten (Slint-/Wayland-Laufzeit, USB-/udev-Bibliotheken) werden als RPM-
Requiresdeklariert, damitzyppersie beim Install/Update mitzieht. - Aufruf aus Forgejo Actions: Der CI-Workflow ruft bei Release/Tag genau dieses Script auf (s. Build & Veröffentlichung per Forgejo Actions).
Debian Trixie (.deb)
Zusätzlich zum RPM entsteht bei jedem Tag ein Debian-Paket für Trixie — nach demselben Muster („ein Skript, zwei Aufrufer") und mit der gleichen Skript-/Verzeichnisstruktur wie bei ngenAudioRecord:
- Build-Script:
scripts/build-deb.sh(lokal im Container:scripts/build-deb-local.sh, Imagedebian:trixie, mit anschließendem Installations-Smoke-Test). Es leitet Version + Debian-Revision aus dem Git-Tag ab, holt per rustup eine aktuelle Toolchain (Slint 1.17 braucht Rust ≥ 1.92, neuer als Distro-cargo), baut das Release-Binary (cargo build --release --features browser-servo, perCARGO_FEATURESänderbar) und paketiert dieselben Dateien wie die.spec— Binary, systemd-Units, udev-/polkit-Regel, PAM — manuell perdpkg-deb(keindebhelper). - Paketdaten liegen in
packaging/deb/:control.in,copyrightund die Maintainer-Skriptepostinst/prerm/postrm+conffiles(die PAM-Datei), die Dienst und Timer überdeb-systemd-helperaktivieren/stoppen (Gegenstück zu den%service_*-Makros). - Abhängigkeiten:
dpkg-shlibdepsermittelt die per ELF gelinkten Bibliotheken (Wayland, fontconfig, freetype, xkbcommon …) mit den zur Build-Distro passenden Paketnamen; per dlopen geladenes GL/EGL sowie die Laufzeit-Dienstecageundpolkitdwerden manuell ergänzt. - Keine Einzelsignatur: anders als beim RPM werden
.deb-Dateien nicht pro Datei signiert — die Forgejo-Debian-Registry signiert die Repo-Metadaten mit ihrem eigenen Schlüssel. - Upload: die CI leitet die Registry-URL aus Server + Owner ab (
https://git.bg-ak.de/api/packages/<owner>/debian/pool/trixie/main/upload); nur dasPACKAGES_TOKEN(Scopewrite:package) ist ein Secret. Auf dem Zielsystem als APT-Quelle einbinden:deb [signed-by=…] https://git.bg-ak.de/api/packages/<owner>/debian trixie main.
GUI-Skizze
Erste Skizze des Layouts (Kiosk, Touch). Dient als Diskussionsgrundlage, nicht final.
Listendarstellung (wichtig)
- In der Liste steht eine Zeile pro Album (= ein Veranstaltungs-/Gottesdienst-Ordner) — nicht jeder Beitrag (jede MP3) einzeln.
- Albumname = Dateiname der JSON/TXT ohne Endung (s. Zusatzdatei).
- Bei Veranstaltungstypen außer Gottesdienst wird nur der Albumname ohne Datum angezeigt (und kein Jahr/Monat-Filter).
- Beim Gottesdienst werden Sonntage als komplette Zeile farbig hinterlegt markiert. Feiertage werden mit einer anderen Farbe markiert. Der Wochentag wird aus dem Datum berechnet (aus dem
YYYY-MM-DD-Präfix), nicht aus der Tageszeit. Die Feiertage stammen aus einer in den Settings verwalteten Liste (s. Feiertage). - In der Gottesdienst-Zeile wird nur der Tag (
TT) angezeigt (Jahr/Monat stehen schon im Filter), dazu die Tageszeit (z. B. „Morgen"/„Abend") — denn an manchen Tagen gibt es zwei Veranstaltungen, die so unterscheidbar bleiben. - Nur über einen besonderen Button am Ende der Zeile (
[ ☰ ]) gelangt man zu den Einzelbeiträgen des Albums. Standardweg ist das Kopieren des kompletten Albums.
Hauptbildschirm (Gottesdienst gewählt)
┌───────────────────────────────────────────────────────────────────────────────┐
│ ngenSermon2Usb [ ⚙ Einstellungen ] │
├──────────────────────┬────────────────────────────────────────────────────────┤
│ USB-Speicher │ Veranstaltungstyp │
│ │ ┌──────────┐┌──────────┐┌──────────┐┌──────────┐ │
│ ● Angesteckt │ │Gottesdnst││ Konferenz││ Seminar ││ Sonstig │ │
│ SanDisk Ultra 32 GB │ └────▲─────┘└──────────┘└──────────┘└──────────┘ │
│ │ │
│ Belegt: │ Jahr [ 2026 ▾ ] Monat [ Juni ▾ ] │
│ ▓▓▓▓▓░░░░░ 12/32 GB │ │
│ │ ┌──────────────────────────────────────────────────┐ │
│ Inhalt: │ │▒▒21 Morgen Predigtreihe Römer 8 ....... [ ☰ ]▒▒│ ← So
│ • 15.06. Predigt │ │ 18 Mittag Bibelstunde ................ [ ☰ ] │ │
│ • 08.06. Predigt │ │▒▒14 Morgen Gemeindesonntag .. ✓ kopiert [ ☰ ]▒▒│ ← So
│ │ │▒▒14 Abend Abendmahlsfeier ............ [ ☰ ]▒▒│ ← So (2. am Tag)
│ [ ⏏ Sicher entfernen]│ │ 11 Abend Gebetsabend ................ [ ☰ ] │ │
│ │ │▒▒07 Morgen Themengottesdienst ......... [ ☰ ]▒▒│ ← So
│ │ └──────────────────────────────────────────────────┘ │
│ │ ☐ Für Autoradio optimieren │
│ │ [ ⬇ Auf USB kopieren ] │
│ │ ▓▓▓▓▓▓▓░░ Kopiere 3/8 … [ ✖ Abbrechen ] │
└──────────────────────┴────────────────────────────────────────────────────────┘
Legende: ▒▒…▒▒ = farbig hinterlegte Sonntagszeile · Feiertage in anderer Farbe · [ ☰ ] = Button „Einzelbeiträge öffnen" · ✓ kopiert = liegt bereits auf dem Stick.
Anderer Veranstaltungstyp (z. B. Konferenz) — nur Album, ohne Datum
│ ┌──────────────────────────────────────────────────┐
│ │ Jugendkonferenz 2026 ................... [ ☰ ] │ (kein Datum,
│ │ Ehe-Seminar ............................ [ ☰ ] │ keine Sonntags-
│ │ Lobpreisabend .............. ✓ kopiert [ ☰ ] │ Markierung,
│ └──────────────────────────────────────────────────┘ kein Jahr/Monat)
Einzelbeiträge (öffnet sich über [ ☰ ])
┌──────────────────────────────────────────────────────────┐
│ ‹ Zurück Gemeindesonntag – 14.06.2026 │
│ ┌────────────────────────────────────────────────────┐ │
│ │ ☐ 01 Begrüßung & Moderation │ │
│ │ ☐ 02 Lobpreis │ │
│ │ ☑ 03 Predigt – Max Müller │ │
│ │ ☐ 04 Abschluss │ │
│ └────────────────────────────────────────────────────┘ │
│ [ Alle ] [ ⬇ Auswahl auf USB kopieren ] │
└──────────────────────────────────────────────────────────┘
Kein USB angesteckt
│ USB-Speicher │ [ ⬇ Auf USB kopieren ] (deaktiviert)
│ ○ Kein Speicher │
│ Bitte anstecken │ ⚠ Bitte einen USB-Speicher anstecken.
Kopieren abbrechen (Dialog)
┌──────────────────────────────────────────────────────────┐
│ Kopieren abbrechen? │
│ Gerade wird kopiert: „03 – Predigt – Max Müller" │
│ │
│ ( ) Aktuellen Beitrag noch fertig kopieren, dann stoppen │
│ ( ) Alles bereits Kopierte wieder löschen (Rückgängig) │
│ │
│ [ Weiter kopieren ] [ Abbrechen … ] │
└──────────────────────────────────────────────────────────┘
Speicher freigeben (Dialog)
Der Unterschied zwischen den Lösch-Varianten wird direkt im Dialog erklärt:
┌──────────────────────────────────────────────────────────────┐
│ Speicher auf dem USB-Stick freigeben │
│ Es werden noch 250 MB benötigt. │
│ │
│ (•) Älteste Veranstaltung zuerst │
│ → nach dem Veranstaltungsdatum (Ordnername, MP3-Album) │
│ │
│ ( ) Zuerst gespeicherte zuerst │
│ → danach, wann es auf den Stick kopiert wurde (Zeitstpl.)│
│ │
│ ( ) Alles löschen (Formatieren) │
│ → entfernt ALLE Daten auf dem Stick │
│ │
│ ( ) Bestimmte Ordner/Alben auswählen (Mehrfachauswahl) │
│ → unten gezielt ankreuzen, was gelöscht werden soll │
│ │
│ Vorschau – wird gelöscht (260 MB): │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 📁 2026-05-03 Morgen Themengottesdienst … 120 MB │ │
│ │ 📁 2026-05-10 Abend Gebetsabend … 95 MB │ │
│ │ 📄 alte_ansage.mp3 (lose im Wurzelordner) 45 MB │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ [ Abbrechen ] [ Löschen … ] │
└──────────────────────────────────────────────────────────────┘
-
Die Vorschau listet genau die betroffenen Ordner (Alben) auf — und einzelne Dateien, falls lose Dateien direkt im Wurzelverzeichnis des Sticks liegen (Symbol 📄). Sie aktualisiert sich je nach gewählter Variante; gelöscht wird erst nach Bestätigung.
-
Bei „Bestimmte Ordner/Alben auswählen" wird die Liste ankreuzbar (Mehrfachauswahl); gelöscht wird genau die Auswahl:
Bestimmte Ordner/Alben löschen: ┌──────────────────────────────────────────────────────┐ │ ☑ 📁 2026-06-07 Morgen Themengottesdienst … 120 MB │ │ ☐ 📁 2026-06-08 Abend Gebetsabend … 95 MB │ │ ☑ 📁 2026-05-31 Morgen Predigtreihe Römer … 130 MB │ │ ☐ 📄 alte_ansage.mp3 (lose im Wurzelordner) 45 MB │ └──────────────────────────────────────────────────────┘ Ausgewählt: 2 Einträge (250 MB) [ Auswahl löschen … ] -
Hinweis: „Veranstaltungsdatum" und „Kopierzeitpunkt" können abweichen, wenn alte Gottesdienste erst spät auf den Stick gezogen werden — deshalb beide Varianten getrennt.
Einstellungen (passwortgeschützt, mit Touch-Tastatur)
┌───────────────────────────────────────────────┐
│ Einstellungen – Anmeldung │
│ Passwort: [ • • • • • • ] │
│ ┌─────────────────────────────────────────┐ │
│ │ q w e r t z u i o p ü ⌫ │ │ ← eingeblendete
│ │ a s d f g h j k l ö ä ↵ │ │ Touch-Tastatur
│ │ ⇧ y x c v b n m , . - │ │
│ │ [ Leertaste ] 123 │ │
│ └─────────────────────────────────────────┘ │
└───────────────────────────────────────────────┘
Nach Login: Tabs für Veranstaltungstypen verwalten, Nextcloud (Login Flow v2), USB / Autoradio-Standard, Feiertage, Cache (Pfad & Schwelle), HTTPS-Passwort. Die HTTPS-Seiten (Status/Logs, Einstellungen) sind kein Teil dieser GUI, sondern werden im Browser auf einem anderen Gerät im LAN aufgerufen.
Fehlerfälle & Meldungen
Leitlinien:
- Kiosk-Meldungen sind kurz, verständlich und nennen eine konkrete Handlung (für Nutzer ohne technisches Wissen).
- Technische Details (Stacktraces, Codes, Pfade) erscheinen nicht im Kiosk, sondern auf der HTTPS-Status-/Log-Seite.
- Wo sinnvoll wird automatisch wiederholt (v. a. Netzwerk), ohne den Nutzer zu blockieren.
- Bei Abbruch eines Kopiervorgangs werden unvollständige Dateien auf dem Stick wieder entfernt.
- Fehler dürfen die GUI nie einfrieren und nicht zum Absturz führen.
Nextcloud / Datenquelle
| Situation | Meldung (Kiosk) | Behebung |
|---|---|---|
| Server nicht erreichbar / kein Netzwerk | „Keine Verbindung zur Nextcloud – es werden die zuletzt geladenen Veranstaltungen angezeigt." | Aus lokalem Cache weiterarbeiten; automatischer Retry im Hintergrund; Netzwerk/Server prüfen (Details im Log). |
| Anmeldung fehlgeschlagen / App-Passwort ungültig oder widerrufen | „Anmeldung bei Nextcloud fehlgeschlagen. Bitte in den Einstellungen neu anmelden." | In den Einstellungen Login Flow v2 erneut durchlaufen → neues App-Passwort. |
| Login Flow nicht bestätigt / Zeitüberschreitung | „Anmeldung nicht abgeschlossen – bitte den Link im Browser bestätigen." | Anmeldevorgang erneut starten. |
| Quellordner fehlt / falscher Pfad | „Quellordner nicht gefunden. Bitte Einstellungen prüfen." | Nextcloud-Pfad in den Einstellungen korrigieren. |
| Einzelne Datei nicht ladbar / Download unvollständig | „Eine Datei konnte nicht geladen werden – neuer Versuch …" | Automatischer Retry; bleibt es fehlerhaft, Eintrag mit Hinweis überspringen. |
| Ordner ohne JSON/TXT | (keine Fehlermeldung) | Erwartetes Verhalten: Ordner erscheint einfach nicht in der Liste, bis ngenAudioRecord die Datei beim Fertigstellen anlegt. |
USB-Speicher
| Situation | Meldung (Kiosk) | Behebung |
|---|---|---|
| Kein Stick angesteckt | „Kein USB-Speicher erkannt. Bitte Stick anstecken." | Kopieren-Button bleibt deaktiviert, bis ein Stick erkannt wird. |
| Stick während des Kopierens abgezogen | „USB-Speicher wurde entfernt – Kopiervorgang abgebrochen." | Unvollständige Dateien werden (falls noch erreichbar) entfernt; Stick wieder anstecken und neu starten. |
| Nicht genug Platz | „Nicht genug Speicherplatz: benötigt X MB, frei Y MB." | Speicher freigeben oder anderen Stick verwenden; Größe wird vor dem Kopieren geprüft. |
| Schreibgeschützt | „USB-Speicher ist schreibgeschützt." | Schreibschutz-Schalter am Stick lösen oder anderen Stick verwenden. |
| Dateisystem nicht beschreibbar/unterstützt | „Auf den USB-Speicher kann nicht geschrieben werden (Dateisystem)." | Stick mit FAT32/exFAT formatieren (Hinweis: Formatieren löscht alle Daten). |
| Zugriffs-/Mount-Fehler | „Auf den USB-Speicher kann nicht zugegriffen werden. Bitte erneut anstecken." | Stick neu anstecken; Details im Log (Rechte/Mount). |
| Mehrere Sticks erkannt | „Mehrere USB-Speicher erkannt. Bitte nur einen anstecken." | Wird i. d. R. physikalisch verhindert; nur einen Speicher anstecken. |
| Sicheres Entfernen fehlgeschlagen (noch in Benutzung) | „Speicher wird noch verwendet und kann nicht sicher entfernt werden." | Kurz warten, bis der Schreibvorgang abgeschlossen ist, dann erneut. |
Kopiervorgang
| Situation | Meldung (Kiosk) | Behebung |
|---|---|---|
| Album liegt bereits auf dem Stick | „Album schon vorhanden – wird überschrieben." | Kein Eingriff nötig; wird überschrieben. |
| Kopieren vom Nutzer abgebrochen | „Kopieren abgebrochen." | Je nach Auswahl: aktuellen Beitrag fertigstellen oder bereits Kopiertes wieder löschen (s. Dialog „Kopieren abbrechen"). |
| Quelldatei zwischenzeitlich entfernt/geändert | „Eine Datei der Veranstaltung ist nicht mehr verfügbar – Liste wird aktualisiert." | Liste neu laden; Vorgang erneut starten. |
| Kopie unvollständig / Prüfsumme passt nicht | „Kopieren unvollständig. Bitte erneut versuchen." | Teil-Dateien aufräumen und erneut kopieren. |
| Autoradio-Optimierung fehlgeschlagen | „Autoradio-Optimierung fehlgeschlagen – bitte erneut versuchen oder Option deaktivieren." | Optimierung deaktiviert kopieren oder erneut versuchen (Details im Log). |
| Ungültige/zu lange Dateinamen für FAT32 | (automatisch bereinigt) | Bei aktiver Autoradio-Optimierung werden Sonderzeichen/Längen bereinigt; sonst Hinweis. |
Einstellungen / Anmeldung
| Situation | Meldung (Kiosk) | Behebung |
|---|---|---|
| Falsches Passwort | „Falsches Passwort." | Erneut eingeben; nach mehreren Fehlversuchen kurze Verzögerung gegen Erraten. |
| Kein Passwort gesetzt (Erststart) | „Bitte ein Passwort für die Einstellungen festlegen." | Beim Ersteinrichten Passwort vergeben (wird als Hash gespeichert). |
| Erster Aufruf der HTTPS-Seite ohne Passwort | „Bitte zunächst ein Passwort für die HTTPS-Seite festlegen." | Beim ersten Aufruf HTTPS-Passwort anlegen; erst danach Zugriff. |
| Einstellungen/Konfiguration beschädigt | „Einstellungen konnten nicht gelesen werden – Standardwerte werden verwendet." | Backup aus Nextcloud wiederherstellen oder neu konfigurieren. |
HTTPS-Server (Meldungen auf Status-/Log-Seite bzw. beim Start)
| Situation | Meldung | Behebung |
|---|---|---|
| Port bereits belegt | „HTTPS-Server konnte nicht starten: Port belegt." | Anderen Port in den Einstellungen wählen; blockierenden Dienst beenden. |
| Zertifikat fehlt/ungültig/abgelaufen | „Zertifikat ungültig oder abgelaufen." | Neues (selbstsigniertes) Zertifikat erzeugen; auf den Clients neu vertrauen. |
| Binden/Netzwerk fehlgeschlagen | „HTTPS-Server nicht erreichbar." | Netzwerk/Firewall im LAN prüfen (Details im Log). Beeinträchtigt die GUI nicht. |
Updates (Meldungen auf Status-/Log-Seite; im Kiosk nur dezenter Hinweis)
| Situation | Meldung | Behebung |
|---|---|---|
| Repo/Netzwerk nicht erreichbar | „Update konnte nicht geprüft werden – wird später erneut versucht." | Automatischer Retry im nächsten Zeitfenster; Netzwerk/Repo prüfen (Details im Log). |
| Signatur/Prüfsumme ungültig | „Update abgelehnt – Signatur ungültig." | Update wird nicht installiert; Paketquelle/Schlüssel prüfen, Administrator informieren. |
| Update während laufendem Kopiervorgang fällig | (keine Meldung) | Erwartetes Verhalten: Update wird verschoben, bis Kopiervorgang/USB-Zugriff beendet ist. |
| Zu wenig Speicher für Update | „Update nicht möglich – zu wenig Speicherplatz." | Cache/Logs aufräumen (s. Lokaler Cache), dann erneut; Details im Log. |
| Update/Neustart fehlgeschlagen | „Aktualisierung fehlgeschlagen – vorige Version wiederhergestellt." | Automatischer Rollback auf die letzte funktionierende Version; Fehler im Log, Administrator informieren. |
System / lokal
| Situation | Meldung | Behebung |
|---|---|---|
| Lokaler Speicher (Cache) voll | „Zu wenig lokaler Speicher – bitte Administrator informieren." | Cache wird ab der eingestellten Schwelle automatisch reduziert (s. Lokaler Cache); zusätzlich Logs aufräumen (Logrotation), ggf. Schwelle senken oder Speicher erweitern. |
| Fehlende lokale Schreibrechte | (Log) | Rechte des Datenverzeichnisses prüfen. |
| Absturz der Anwendung | (automatischer Neustart) | Autostart/Watchdog startet die App neu; letzter Zustand steht im Log. |