Native Windows-Auslieferung statt Container
Docker faellt weg. Das Projekt hat keine npm-Abhaengigkeiten und Node fuehrt TypeScript direkt aus - der Container schrieb nur noch drei Programme fest, und dafuer braucht es keine Virtualisierung, sondern einen Ordner. Der Anlass war, dass ADR-0004 zwar `docker compose pull` versprach, es aber nie ein veroeffentlichtes Image gab. Wer installieren wollte, musste whisper.cpp aus dem Quelltext uebersetzen. Plattformschicht (packages/core/src/platform.ts): - Programme werden neben der Anwendung gesucht, nicht im PATH - Daten unter %LOCALAPPDATA%, damit Installation und Update ohne Administratorrechte auskommen - Schriften mitgeliefert: ohne fontsdir setzt libass wortlos eine Ersatzschrift ein - gemessen 720 statt 826 Pixel Zeilenbreite Windows-Eigenheiten, an echtem ffmpeg 8.1 durchprobiert: - Pfade im Filtergraphen brauchen alle drei Schritte (Vorwaertsschraegstriche, escapter Doppelpunkt, Anfuehrungszeichen); je zwei davon reichen nicht - `nice` gibt es nicht, ersetzt durch os.setPriority Auslieferung: - scripts/build-package.ts baut das Paket, laeuft auch unter Linux - install.ps1 ohne Administratorrechte, Autostart ueber den Aufgabenplaner - update legt neue Fassungen bereit; eingespielt wird beim naechsten Start, nie mitten im Stream - ZIP lesen und schreiben ohne Abhaengigkeiten (packages/core/src/zip.ts) Kein `irm ... | iex`-Einzeiler: git.zeasy.dev antwortete instanzweit mit einer Umleitung auf /user/login, und `iex` fuehrte die Anmeldeseite als PowerShell aus. Der Updater verfolgt Umleitungen jetzt nicht und hat keine erfundene Vorgabeadresse mehr. Ausserdem: backup.ps1 war an zwei Stellen dokumentiert, aber nie geschrieben. ADR-0007 ersetzt ADR-0004. 84 Tests, Typpruefung sauber. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AhVSfMFdWnXKCv5JfLnArZ
This commit is contained in:
1 parent
71dd660d01
commit
5f6301268a
41 files changed
+2254
-312
No files matched your search
@@ -1,6 +1,12 @@
|
||||
# ADR-0004: Betrieb in Docker
|
||||
|
||||
**Status:** akzeptiert · **Datum:** 2026-09-09
|
||||
**Status:** ~~akzeptiert~~ **ersetzt durch [ADR-0007](ADR-0007-native-windows.md)** · **Datum:** 2026-09-09
|
||||
|
||||
> Diese Entscheidung gilt nicht mehr. Das Toolkit laeuft nativ unter Windows.
|
||||
> Die Analyse unten bleibt lesenswert - die vier Fallen, die sie beschreibt,
|
||||
> waren real, und zwei davon (Pfaduebersetzung, Kopieren ueber die
|
||||
> WSL2-Bruecke) sind mit dem Container weggefallen statt geloest worden zu
|
||||
> sein. Warum gewechselt wurde, steht in ADR-0007.
|
||||
|
||||
## Kontext
|
||||
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
# ADR-0007: Native Windows-Anwendung statt Container
|
||||
|
||||
**Status:** akzeptiert · **Datum:** 2026-09-09 · **ersetzt:** [ADR-0004](ADR-0004-docker.md)
|
||||
|
||||
## Kontext
|
||||
|
||||
ADR-0004 hat den Betrieb in Docker festgelegt und dabei zwei Dinge versprochen:
|
||||
„Die einzige Voraussetzung auf dem Stream-PC ist Docker Desktop und OBS" und
|
||||
„Updates sind ein `docker compose pull && up -d`".
|
||||
|
||||
Das zweite Versprechen wurde nie eingelöst. Es gab keine CI, kein
|
||||
veröffentlichtes Image, und `image: abdulive/toolkit:dev` zeigte auf nichts.
|
||||
Wer das Toolkit installieren wollte, musste `docker compose build` ausführen —
|
||||
und damit **whisper.cpp aus dem Quelltext übersetzen**, gut zehn Minuten, mit
|
||||
allen Fehlermöglichkeiten eines Compilers. Für Abdu ist das nicht zumutbar.
|
||||
|
||||
Beim Nachdenken über die Reparatur fiel auf, dass die Voraussetzung selbst
|
||||
teurer ist als der Nutzen. Die Kosten stehen ehrlich in ADR-0004: die WSL2-VM
|
||||
belegt im Leerlauf ein bis zwei GB RAM, und Intel QSV ist aus WSL2 heraus nicht
|
||||
verlässlich erreichbar, also bleibt CPU-Encoding — beides auf einem Rechner,
|
||||
der gleichzeitig streamt.
|
||||
|
||||
Dem steht ein Umstand gegenüber, der die ursprüngliche Begründung untergräbt:
|
||||
**Das Projekt hat keine npm-Abhängigkeiten**, und Node führt TypeScript direkt
|
||||
aus (ADR-0001). Es gibt nichts zu bauen. Der Container schrieb also nur noch
|
||||
drei Programme fest — Node, ffmpeg, whisper.cpp — und dafür braucht es keine
|
||||
Virtualisierung, sondern einen Ordner.
|
||||
|
||||
## Entscheidung
|
||||
|
||||
Das Toolkit wird als **native Windows-Anwendung** ausgeliefert. Ein Ordner mit
|
||||
allem darin, ein PowerShell-Installer, ein Updater. Kein Docker, kein WSL2.
|
||||
|
||||
```
|
||||
abdulive/
|
||||
node.exe portable Node-Laufzeit
|
||||
bin/ ffmpeg, ffprobe, whisper-cli und ihre DLLs
|
||||
fonts/ DejaVu Sans (im Repo mitgeliefert, siehe unten)
|
||||
app/ die TypeScript-Quellen, unverändert
|
||||
abdulive.cmd Kommandozeile
|
||||
launcher.ps1 vom Aufgabenplaner gestartet
|
||||
version.json
|
||||
```
|
||||
|
||||
Gebaut wird mit `node scripts/build-package.ts` — lädt die drei Bausteine bei
|
||||
ihren Herausgebern, packt alles zusammen, schreibt Prüfsummen. Das läuft auch
|
||||
in der CI unter Linux.
|
||||
|
||||
## Begründung
|
||||
|
||||
- **Abdu baut nichts.** Herunterladen, `install.ps1`, fertig. Kein Docker
|
||||
Desktop, kein `.wslconfig`, kein Compiler.
|
||||
- **Ein bis zwei GB RAM** stehen wieder dem Stream zur Verfügung.
|
||||
- **Hardware-Encoding wird erreichbar.** Der mitgelieferte ffmpeg ist mit
|
||||
`--enable-libvpl`, `--enable-amf` und `--enable-ffnvcodec` gebaut; QSV und
|
||||
AMF sind nativ ansprechbar. Genutzt wird das noch nicht — aber es ist jetzt
|
||||
möglich, und aus WSL2 heraus war es das nicht.
|
||||
- **Die Pfadübersetzung entfällt.** `mapReplayPath` musste OBS' Windows-Pfade
|
||||
auf `/replay` abbilden; laut Übergabe die Stelle, an der die Clip-Pipeline
|
||||
am ehesten scheitert. Nativ sieht die Anwendung denselben Pfad wie OBS.
|
||||
- **Kein Kopieren über die WSL2-Brücke mehr.** ADR-0004 Punkt 2 verbot das
|
||||
Verarbeiten auf dem Bind-Mount, weil es „ein Vielfaches der Zeit" kostet.
|
||||
Diese Klasse von Fehlern gibt es nicht mehr.
|
||||
|
||||
## Konsequenzen — was dabei zu beachten ist
|
||||
|
||||
**1. Programme werden neben der Anwendung gesucht, nicht im PATH.**
|
||||
`packages/core/src/platform.ts` löst auf: erst die Umgebungsvariable
|
||||
(`FFMPEG_BIN` …), dann `bin/`, dann der PATH. Die Umgebungsvariable steht
|
||||
bewusst vorn — eine kaputte Mitlieferung lässt sich so ohne Neuinstallation
|
||||
überschreiben.
|
||||
|
||||
**2. Schriften müssen mitgeliefert werden.**
|
||||
Im Container kam DejaVu Sans aus `fonts-dejavu-core` und libass fand sie über
|
||||
fontconfig. Windows hat DejaVu nicht. Fehlt der Ordner, setzt libass
|
||||
**wortlos** eine Ersatzschrift ein — gemessen: dieselbe Zeile wird 720 statt
|
||||
826 Pixel breit, ohne jede Fehlermeldung. Deshalb liegen die Schriftdateien
|
||||
unter `assets/fonts/` im Repo, und `assFilter` setzt `fontsdir`.
|
||||
|
||||
**3. Windows-Pfade im ffmpeg-Filtergraphen brauchen drei Schritte.**
|
||||
`C:\Users\…` enthält einen Doppelpunkt (trennt Filteroptionen) und
|
||||
Rückwärtsschrägstriche (ffmpeg-Escapes). An echtem ffmpeg 8.1 durchprobiert:
|
||||
|
||||
| Form | Ergebnis |
|
||||
|---|---|
|
||||
| `ass=filename=C:/x/s.ass` | `No option name near '/x/s.ass'` |
|
||||
| `ass=filename=C\:/x/s.ass` | ebenso |
|
||||
| `ass=filename='C:/x/s.ass'` | ebenso |
|
||||
| `ass=filename='C\:/x/s.ass'` | läuft |
|
||||
|
||||
Anführungszeichen allein schützen den Doppelpunkt nicht, das Escape allein
|
||||
auch nicht. `filterPath()` macht alle drei Schritte, mit Tests.
|
||||
|
||||
**4. `nice` gibt es unter Windows nicht.**
|
||||
Ersetzt durch `os.setPriority` auf die Kind-PID. Das kann beides, braucht
|
||||
keinen Hilfsprozess davor, und das Zurückstufen darf jeder Benutzer.
|
||||
|
||||
**5. Daten liegen unter `%LOCALAPPDATA%\abdulive`, nicht neben dem Programm.**
|
||||
Ein Update tauscht den Programmordner komplett aus; die Datenbank darf dabei
|
||||
nicht mitgehen. `LOCALAPPDATA` und nicht `ProgramData`, weil die Anwendung als
|
||||
angemeldeter Benutzer läuft — dieselbe Sitzung wie OBS. Damit braucht weder
|
||||
Installation noch Update Administratorrechte. Genau daran scheitern
|
||||
Aktualisierungen sonst auf einem Rechner, an dem gerade gestreamt wird.
|
||||
|
||||
**6. Autostart über den Aufgabenplaner, nicht als Windows-Dienst.**
|
||||
Ein Dienst liefe unter SYSTEM in einer anderen Sitzung als OBS, bräuchte
|
||||
Administratorrechte und ein zusätzliches Wrapper-Programm (nssm, WinSW). Die
|
||||
Aufgabe `abdulive` startet bei der Anmeldung, versteckt, mit Neustart nach
|
||||
zwei Minuten bei Absturz.
|
||||
|
||||
**7. Updates werden bereitgelegt, nicht sofort eingespielt.**
|
||||
Windows sperrt die Dateien laufender Programme — `node.exe` lässt sich nicht
|
||||
ersetzen, solange es läuft. `abdulive update` prüft das Manifest, lädt das
|
||||
Paket, **prüft die SHA256** und legt es unter `pending/` ab. `launcher.ps1`
|
||||
tauscht beim nächsten Start aus, bevor irgendetwas startet. Damit gibt es nie
|
||||
einen halb ausgetauschten Ordner, und mitten im Stream wird nichts angefasst.
|
||||
Schlägt der Tausch fehl, läuft die alte Fassung weiter.
|
||||
|
||||
**Kosten, ehrlich benannt:**
|
||||
|
||||
- **Die Umgebung ist nicht mehr festgeschrieben.** Der Container garantierte
|
||||
„kein läuft bei mir". Jetzt garantiert das nur noch der Paketinhalt — Node,
|
||||
ffmpeg und whisper sind mitgeliefert, aber Windows selbst ist es nicht.
|
||||
- **Kein Code-Signing.** SmartScreen warnt beim ersten Start vor einem
|
||||
unbekannten Herausgeber. Ein Zertifikat kostet Geld; bis dahin muss man
|
||||
einmal auf „Trotzdem ausführen" klicken. Steht in `offene-punkte.md`.
|
||||
- **Windows-only.** Ein Linux-Paket gibt es nicht mehr. Für ein Werkzeug, das
|
||||
neben OBS auf einem Windows-Stream-PC läuft, ist das kein Verlust — die
|
||||
Pfade in `platform.ts` kennen den Linux-Fall aber weiterhin, und die Tests
|
||||
laufen dort.
|
||||
- **Drei Bausteine wollen gepflegt werden.** Node, ffmpeg und whisper.cpp
|
||||
aktualisieren sich nicht von selbst. `build-package.ts` holt jeweils die
|
||||
aktuelle Ausgabe und schreibt Name und Prüfsumme nach `version.json` — was
|
||||
drin ist, lässt sich also nachlesen.
|
||||
@@ -5,9 +5,10 @@
|
||||
| [0001](ADR-0001-monorepo-typescript.md) | TypeScript-Monorepo statt gemischter Sprachen | akzeptiert |
|
||||
| [0002](ADR-0002-sqlite.md) | SQLite statt Postgres | akzeptiert |
|
||||
| [0003](ADR-0003-eventsub-websocket.md) | EventSub ueber WebSocket, Chat ueber IRC | akzeptiert |
|
||||
| [0004](ADR-0004-docker.md) | Betrieb in Docker, whisper.cpp statt Python | akzeptiert |
|
||||
| [0004](ADR-0004-docker.md) | Betrieb in Docker, whisper.cpp statt Python | ersetzt durch 0007 |
|
||||
| [0005](ADR-0005-zugangsdaten.md) | Zugangsdaten ueber Einrichtungs-Assistent statt .env | akzeptiert |
|
||||
| [0006](ADR-0006-ein-dach.md) | Ein Dach: lokale Weboberflaeche, lokale Arbeitsprozesse | akzeptiert |
|
||||
| [0007](ADR-0007-native-windows.md) | Native Windows-Anwendung statt Container | akzeptiert |
|
||||
|
||||
Neue Entscheidung: Datei `ADR-<nummer>-<kurzname>.md`, Aufbau Kontext /
|
||||
Entscheidung / Begruendung / Konsequenzen.
|
||||
Reference in new issue
Block a user