diff --git a/docs/handoff.md b/docs/handoff.md index 7610cc6..9b6c255 100644 --- a/docs/handoff.md +++ b/docs/handoff.md @@ -1,121 +1,204 @@ # Übergabe -Stand **2026-09-09**. Wer hier weitermacht, sollte diese Seite zuerst lesen und -danach [`07-mvp-plan.md`](07-mvp-plan.md). +Stand **2026-09-09**, Version 0.5.4. Wer hier weitermacht, liest zuerst diese +Seite, dann [`07-mvp-plan.md`](07-mvp-plan.md). Für Abdu selbst gibt es das +[Handbuch](handbuch/handbuch.pdf). ## Wo das Projekt steht Vier von sieben Scheiben des MVP „Clip-Knopf" sind gebaut. Die Kette vom -Auslöser bis zum fertigen Short steht **im Code vollständig** — geprüft ist sie +Auslöser bis zum fertigen Short steht im Code vollständig. Geprüft ist sie überall dort, wo es ohne Abdus Stream-PC ging. | Scheibe | Stand | Nachweis | |---|---|---| -| S0 Toolchain + Auslieferung | fertig | `check-env` nativ ohne harte Fehler, Paket gebaut und installiert | +| S0 Toolchain + Auslieferung | fertig | Paket gebaut und installiert, `check-env` ohne harte Fehler, Updater einmal komplett durchgelaufen | | S1 Einrichtung, Auth, DB, Chat | fertig | Daemon läuft, Chat verbunden, Secrets verschlüsselt | | S2 OBS + `!clip` | Code fertig, **nicht abgenommen** | braucht laufendes OBS | | S3 9:16-Render | fertig | Durchlauf mit künstlicher Aufnahme | -| S4 Untertitel | fertig | Durchlauf mit echtem deutschen Clip | -| S5 Onboarding + Sichtung | offen | — | -| S6 Erstchatter-Begrüßung | offen | — | +| S4 Untertitel | fertig | Durchlauf mit echtem deutschen Clip, Ränder nachgemessen | +| S5 Onboarding + Sichtung | offen | | +| S6 Erstchatter-Begrüßung | offen | | -79 Tests, alle grün. Vollständige Liste dessen, was noch fehlt: +93 Tests, alle grün. Was noch fehlt, steht vollständig in [`offene-punkte.md`](offene-punkte.md). ## Was jemand wissen muss, bevor er etwas anfasst -**Es gibt keine Abhängigkeiten und keinen Build.** Node 24 bringt SQLite, -WebSocket, `fetch` und die Ausführung von TypeScript mit. `node apps/cli/main.ts` -läuft direkt. Deshalb gilt: nur *löschbare* TypeScript-Syntax — keine `enum`, -keine Parameter-Properties im Konstruktor, keine `namespace`. `erasableSyntaxOnly` -in der `tsconfig.json` erzwingt das und hat schon einen echten Fehler gefangen. +**Keine Abhängigkeiten, kein Build.** Node 24 bringt SQLite, WebSocket, +`fetch` und die Ausführung von TypeScript mit. `node apps/cli/main.ts` läuft +direkt. Deshalb gilt: nur *löschbare* TypeScript-Syntax, also keine `enum`, +keine Parameter-Properties im Konstruktor, keine `namespace`. +`erasableSyntaxOnly` in der `tsconfig.json` erzwingt das und hat schon einen +echten Fehler gefangen. -**Alles läuft unter einem Dach**, in einem Prozess. Schwere -Arbeit (ffmpeg, whisper) läuft als Kindprozess und darf abstürzen. Der Ingest -darf nie sterben — was er nicht mitschreibt, ist für immer weg. +**Alles läuft in einem Prozess.** Schwere Arbeit (ffmpeg, whisper) läuft als +Kindprozess und darf abstürzen. Der Ingest darf nie sterben. Was er nicht +mitschreibt, ist für immer weg. -**Zugangsdaten kommen aus der Weboberfläche**, nicht aus einer Datei. Sie liegen -verschlüsselt neben der Datenbank, aber bewusst nicht *in* ihr — die Datenbank -wird gesichert und weitergereicht, die Geheimnisse nicht. +**Zugangsdaten kommen aus der Weboberfläche**, nicht aus einer Datei. Sie +liegen verschlüsselt neben der Datenbank, aber bewusst nicht *in* ihr. Die +Datenbank wird gesichert und weitergereicht, die Geheimnisse nicht. -**Rohdateien gehören in den Arbeitsordner**, nicht neben den OBS-Puffer. Das -war unter Docker ein Zeitproblem (Encodieren über die WSL2-Brücke kostete ein -Vielfaches) und ist nativ nur noch Ordnung — der Wiedergabepuffer-Ordner -gehört OBS. +**Das Repo ist seit 2026-09-09 öffentlich.** Damit funktioniert der Einzeiler +zur Installation, und der Updater braucht keinen Token. Es heißt aber auch: +nichts Vertrauliches mehr hineinschreiben, auch nicht in die Doku. -Die Begründungen stehen in [`decisions/`](decisions/), sieben ADRs. Wer eine -davon umwerfen will, sollte sie vorher lesen; jede hat einen Grund, der beim -Bauen aufgetaucht ist. ADR-0004 (Docker) ist durch ADR-0007 ersetzt — die -Analyse darin bleibt trotzdem lesenswert. +Die Begründungen stehen in [`decisions/`](decisions/), acht ADRs. Wer eine +davon umwerfen will, liest sie vorher. ADR-0004 (Docker) ist durch ADR-0007 +ersetzt; die Analyse darin bleibt lesenswert, weil zwei der vier +beschriebenen Fallen mit dem Container weggefallen sind statt gelöst worden +zu sein. ## Loslegen -**Auf Abdus Rechner** läuft eine native Windows-Anwendung — kein Docker, kein -WSL2, nichts zu übersetzen ([ADR-0007](decisions/ADR-0007-native-windows.md)): +Auf Abdus Rechner, eine native Windows-Anwendung: ```powershell irm https://git.zeasy.dev/ZeasyAlex/abdulive/raw/branch/main/scripts/install.ps1 | iex ``` -Der Installer laedt das Sprachmodell, laeuft den Selbsttest, startet den -Daemon und oeffnet die Einrichtungsseite. +Der Installer lädt das Paket, prüft die Prüfsumme, holt das Sprachmodell, +läuft den Selbsttest, startet den Dienst und öffnet die Einrichtungsseite. +Ohne Administratorrechte. Ausführlich in [`05-setup.md`](05-setup.md). -Ausführlich in [`05-setup.md`](05-setup.md). - -**Zum Entwickeln** reicht ein Checkout und Node 24 oder neuer: +Zum Entwickeln reicht ein Checkout und Node 24 oder neuer: ```powershell node apps/cli/main.ts check-env node --test "packages/**/*.test.ts" "apps/**/*.test.ts" -node scripts/build-package.ts --version 0.5.0 # baut dist/*.zip +node scripts/build-package.ts --version 0.5.5 # baut dist/ ``` -Typprüfung (das Einzige, wofür npm gebraucht wird): +Typprüfung, das Einzige wofür npm gebraucht wird: ```powershell npm i typescript@5.9 @types/node npx tsc --noEmit ``` +## Ausliefern + +`build-package.ts` lädt Node, ffmpeg und whisper.cpp bei ihren Herausgebern, +packt alles nach `dist/` und schreibt `abdulive.json`. Dieses Manifest fragt +`abdulive update` auf Abdus Rechner ab. + +Die Veröffentlichung `latest` trägt beide Dateien und wird bei jedem Bau +ersetzt, damit die Adresse gleich bleibt. +`.gitea/workflows/release.yml` macht das beim Tag automatisch. **Die Pipeline +ist noch nie gelaufen**, bisher wurde von Hand veröffentlicht. Der Runner +(`ubuntu-latest`) steht. + +## Windows-Fallen, die schon zugeschlagen haben + +Alle vier haben Zeit gekostet, und keine sieht im Fehlerfall nach ihrer +Ursache aus. Wer an den PowerShell-Skripten arbeitet, sollte sie kennen. + +**stderr beendet das Skript.** Windows PowerShell 5.1 verpackt jede +stderr-Zeile eines nativen Programms in einen `ErrorRecord`. Zusammen mit +`$ErrorActionPreference = 'Stop'` bricht das sofort alles ab. Der Daemon +schreibt im Normalbetrieb Warnungen auf stderr, der Starter hat ihn also bei +seiner ersten Logzeile umgebracht: Aufgabe meldete Code 1, das Protokoll war +leer. Deshalb läuft der Start über `Start-Process` mit getrennten +Umleitungen, und `install.ps1` ruft native Programme über eine Hilfsfunktion +auf, die `ErrorActionPreference` kurz zurückstellt. + +**`& $programm; return $LASTEXITCODE` gibt auch die Ausgabe zurück.** Die +Funktion liefert dann ein Array aus allen Ausgabezeilen plus Exit-Code, und +jeder Vergleich damit ist falsch, ohne dass es auffällt. Ein erfolgreiches +`fetch-model` galt so als fehlgeschlagen. Ausgabe mit `| Out-Host` +durchreichen. + +**`localhost` kostet zwei Sekunden.** Der Dienst lauscht nur auf IPv4, +Windows probiert bei `localhost` zuerst `::1`. Gemessen: 2066 ms bis zum +Rückfall gegenüber 15 ms bei `127.0.0.1`. Eine Bereitschaftsprüfung mit zwei +Sekunden Zeitlimit läuft dadurch immer ab, obwohl der Dienst längst läuft. + +**Windows-Pfade im ffmpeg-Filtergraphen brauchen drei Schritte.** 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 | + +Vorwärtsschrägstriche, escapter Doppelpunkt **und** Anführungszeichen. Je +zwei davon reichen nicht. `filterPath()` in `packages/media/src/ffmpeg.ts` +macht das, mit Tests. + +## Untertitel: was gemessen ist + +**Die Schrift muss mitgeliefert werden.** Im Container kam DejaVu Sans aus +dem Betriebssystem, Windows hat sie nicht. Fehlt `fontsdir`, setzt libass +wortlos eine Ersatzschrift ein. Gemessen: dieselbe Zeile wird 720 statt 826 +Pixel breit, ohne jede Fehlermeldung. Die Dateien liegen unter +`assets/fonts/`. + +**Die Zeilenlänge ist eingemessen, nicht geschätzt.** Vorher stand dort fest +`maxChars: 30`. Das sind bei Schriftgröße 76 rund 1085 px, nutzbar sind 940. +Zusammen mit `WrapStyle: 2`, bei dem libass gar nicht umbricht, lief der Text +links und rechts aus dem Bild. Jetzt wird die Grenze aus Breite und +Schriftgröße abgeleitet, Versalien zählen breiter, und einzelne zu lange +Wörter bekommen eine kleinere Schrift, weil libass innerhalb eines Wortes +nicht umbricht. Deutsche Komposita sind regelmäßig breiter als das Bild. + +Wer die Schrift wechselt, muss `CHAR_WIDTH_RATIO` in `subtitles.ts` neu +einmessen. Sonst bricht die Zeile wieder an der falschen Stelle. + ## Die drei Dinge, die Abdu tun muss 1. **Broadcaster-Konto verbinden.** Die beiden Twitch-Apps (dev.twitch.tv/console/apps, Redirect-URI `http://localhost:4792/callback`) - kann auch jemand anders anlegen — sie hängen nicht am Kanal. Was **nur Abdu** + kann auch jemand anders anlegen, sie hängen nicht am Kanal. Was nur Abdu kann: auf der Einrichtungsseite eingeloggt als er selbst auf „Mit Twitch - verbinden" klicken. Dafür muss die Anwendung auf seinem Rechner schon - laufen; die Seite hört nur auf `127.0.0.1`. + verbinden" klicken. Dafür muss die Anwendung auf seinem Rechner laufen, + die Seite hört nur auf `127.0.0.1`. 2. **OBS einrichten**: obs-websocket an (Port 4455), Wiedergabepuffer 90 s, Hotkey auf „Wiedergabepuffer speichern", getrennte Audiospuren. -3. **Layout umstellen** nach [`obs-layout.md`](obs-layout.md). Die - Ausrichtungsvorlage in OBS über die Szene legen, Quellen einpassen, wieder - ausblenden. Danach `calibrate` zur Kontrolle. +3. **Layout umstellen** nach [`obs-layout.md`](obs-layout.md), danach + `abdulive calibrate` zur Kontrolle. Ohne Punkt 1 liest das Toolkit den Chat anonym mit und kann nichts senden. Ohne Punkt 2 gibt es keine Clips. Ohne Punkt 3 sitzt der Ausschnitt schief. +Dazu eine Kleinigkeit mit Wirkung: das Bot-Konto sollte Moderator sein +(`/mod `). Ohne das gilt ein Limit von 20 Chat-Nachrichten je 30 +Sekunden statt 100, und im Follower-only-Modus kommt der Bot gar nicht durch. + ## Wo ich weitermachen würde -**S5.** Nicht wegen des Codes, sondern weil das Werkzeug ohne Einrichtungs- -Assistenten und Sichtungsseite für Abdu nicht bedienbar ist. Die Kette -funktioniert, aber sie hat noch keine Oberfläche, die jemand ohne Erklärung -benutzt. Abnahmekriterium steht im Plan: *Ein Fremder kommt von „nichts -eingerichtet" bis zum ersten eigenen Clip, ohne die Dokumentation zu lesen.* +**S2 an einem laufenden OBS abnehmen.** Das ist die einzige ungeprüfte Stelle +in der ganzen Kette, und alles Weitere hängt daran. Seit es `abdulive sources` +gibt, ist auch die Frage beantwortbar, welche OBS-Quelle fremden Text ins Bild +malt. Das war vorher nicht zu erraten. -Davor, wenn Gelegenheit ist: **S2 an einem laufenden OBS abnehmen**. Das ist -die einzige ungeprüfte Stelle in der ganzen Kette, und alles Weitere hängt -daran. +**Danach S5.** Nicht wegen des Codes, sondern weil das Werkzeug ohne +Sichtungsseite für Abdu nicht bedienbar ist. Die Kette funktioniert, aber sie +hat keine Oberfläche, auf der man Clips durchgeht und aussortiert. +Abnahmekriterium steht im Plan: *Ein Fremder kommt von „nichts eingerichtet" +bis zum ersten eigenen Clip, ohne die Dokumentation zu lesen.* Installer und +Handbuch decken davon inzwischen ein gutes Stück ab. ## Womit ich nicht zufrieden bin -Die Untertitel sind brauchbar, nicht gut. `ggml-small` verhört sich hörbar -(„Danke" wurde „Dank es"), die Schrift ist unauffällig, und das fortlaufende -Einfärben ist nicht der Stil, der auf Shorts trägt. Sechs konkrete -Verbesserungen stehen in [`offene-punkte.md`](offene-punkte.md). +**Das Aufräumen im Arbeitsordner fehlt komplett.** Rohdateien sammeln sich +unbegrenzt an, mehrere hundert MB je Clip. Das ist die Lücke, die als Erstes +weh tun wird. -Und: Das Aufräumen im Arbeitsordner fehlt komplett. Rohdateien sammeln sich -unbegrenzt an. Das ist die Lücke, die als Erstes weh tun wird. +**Die Untertitel sind brauchbar, nicht gut.** `ggml-small` verhört sich +hörbar („Danke" wurde „Dank es"), DejaVu Sans ist unauffällig, und das +fortlaufende Einfärben ist nicht der Stil, der auf Shorts trägt. Sechs +konkrete Verbesserungen stehen in [`offene-punkte.md`](offene-punkte.md). -Der Updater ist einmal komplett durchgelaufen: 0.4.0 erkannt, 119 MB von -`git.zeasy.dev` geladen, Prüfsumme geprüft, bereitgelegt, von `launcher.ps1` -getauscht, `pending` aufgeräumt. Was noch nie lief, ist die CI-Pipeline. +**Die CI ist geschrieben, aber ungetestet.** Beim ersten Tag zusehen. + +**Das Paket ist nicht signiert.** SmartScreen warnt bei jeder Installation. +Solange nur Abdu installiert, reicht ein Klick. Sobald jemand Drittes es +bekommt, nicht mehr. + +**Es gibt keine Einstellung für den OBS-Wiedergabepuffer-Ordner.** Im +Container kam der Pfad über `OBS_REPLAY_DIR`, nativ fehlt der Weg. Für die +Clip-Kette ist das egal, weil OBS den Pfad über WebSocket meldet. Aber +`calibrate` findet so keine Aufnahmen, und `check-env` warnt zu Recht.