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:
ZeasyAlexandClaude Opus 5 committed 2026-09-09 17:39:26 +02:00
1 parent 71dd660d01
commit 5f6301268a
41 files changed
+2254 -312

No files matched your search

+134
View File
@@ -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.