Uebergabe auf den aktuellen Stand
Version 0.5.4, 93 Tests, acht ADRs. Neu darin: - Auslieferung: was build-package.ts tut, wie die Veroeffentlichung entsteht, und dass die CI-Pipeline noch nie gelaufen ist - Vier Windows-Fallen, die je einen Fehler verursacht haben und im Fehlerfall nicht nach ihrer Ursache aussehen: stderr als NativeCommandError, Rueckgabewert von & plus $LASTEXITCODE, localhost gegen 127.0.0.1, ffmpeg-Filterpfade - Untertitel: die gemessenen Zahlen statt der alten Schaetzung - Hinweis, dass das Repo oeffentlich ist 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
7775c689be
commit
d231e1c722
1 file changed
+142
-59
+142
-59
@@ -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 <botname>`). 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.
|
||||
Reference in new issue
Block a user