- Rust 86%
- Slint 12.2%
- Shell 1.8%
| .forgejo/workflows | ||
| .vscode | ||
| deploy | ||
| examples | ||
| packaging | ||
| scripts | ||
| src | ||
| ui | ||
| .gitignore | ||
| build.rs | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| Plan.md | ||
| README.md | ||
ngenSermon2Usb
Angelehnt an die bestehende USB Tankstelle, um Gottesdienste und andere Veranstaltungen per Auswahl auf einen USB Speicher zu kopieren.
Plan
Hinweis: Das ist erstmal nur ein Plan.
- 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: ngenRecord)
- Die Gottesdienste werden vom Schwesterprojekt ngenRecord 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.
- ngenRecord 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 ngenRecordspath_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 ngenRecord diesen datierten Pro-Event-Unterordner bereits. (Nur im Testsystem ist
export_path_templateleer/flach.)
- Im Produktivsystem erzeugt die Export-Pfad-Vorlage in ngenRecord 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 |
| 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).
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.
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.
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). - 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. - 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).
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 ngenRecord 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. |