S1: Einrichtungs-Assistent, Twitch-Auth, Datenbank und Chat-Aufnahme
Zugangsdaten kommen jetzt aus der App statt aus einer .env: ein Einrichtungs-Assistent auf http://localhost:4792/setup nimmt Client-ID, Secret und OBS-Passwort entgegen, der OAuth-Rueckruf laeuft auf denselben Server. Gespeichert wird verschlueselt (AES-256-GCM) in einem Volume, bewusst nicht in der Datenbank - die wird auf die Windows-Seite gesichert. Siehe ADR-0005. Technikbasis vereinfacht: Node 24 bringt node:sqlite, WebSocket, fetch und die Ausfuehrung von TypeScript mit. Das Projekt hat damit null Laufzeitabhaengigkeiten und keinen Build-Schritt; pnpm-Workspaces und die Paketmanifeste sind entfallen, Importe laufen ueber die imports-Map der Wurzel-package.json. erasableSyntaxOnly verhindert Syntax, die das Type Stripping stillschweigend entfernen wuerde. Siehe Nachtrag 2 in ADR-0001. Enthalten: - packages/core: Config, Layout, Logger mit Secret-Maskierung, Retry, YAML - packages/db: Migrationen, Repositories, alle SQL-Anweisungen an einem Ort - packages/twitch: Secret-Speicher, OAuth, Helix mit Token-Bucket, IRC - apps/ingest: Daemon, Einrichtungsseite, Spike-Erkennung - 20 Tests (IRC-Parser, Spike-Detektor, Datenbankschicht) Der Chat verbindet sich anonym, solange nichts hinterlegt ist - damit laesst sich die Datenaufnahme pruefen, bevor die Twitch-Apps existieren. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013VTGjd92LsDDWF3frd9FTB
This commit is contained in:
1 parent
4ceb61f095
commit
d07c18441b
82 files changed
+2775
-838
No files matched your search
+57
-31
@@ -36,14 +36,34 @@ gibt. Vorher ist sie nur Ballast.
|
||||
|---|---|
|
||||
| S0 Container + Toolchain | **fertig** — Image 258 MB, `check-env` ohne harte Fehler |
|
||||
| Layout eingemessen | **fertig** — `config/layout.yaml`, vorgezogen aus S3 |
|
||||
| S1 Auth + DB + IRC-Ingest | als Nächstes |
|
||||
| S1 Einrichtung + Auth + DB + IRC-Ingest | **fertig** — 20 Tests grün, Daemon läuft |
|
||||
| S2–S6 | offen |
|
||||
|
||||
**S1 abgenommen am 2026-09-09.** Der Daemon läuft, hängt am Chat, die
|
||||
Einrichtung ist unter `http://localhost:4792/setup` erreichbar.
|
||||
|
||||
Beim Bauen hat sich die Technikbasis vereinfacht: Node 24 bringt SQLite,
|
||||
WebSocket, `fetch` und die Ausführung von TypeScript mit, deshalb hat das
|
||||
Projekt **null Laufzeitabhängigkeiten und keinen Build-Schritt**. pnpm-Workspaces
|
||||
und die Paketmanifeste sind entfallen. Siehe Nachtrag 2 in
|
||||
[ADR-0001](decisions/ADR-0001-monorepo-typescript.md).
|
||||
|
||||
Nachgewiesen:
|
||||
|
||||
- 20 Tests grün (IRC-Parser, Spike-Detektor, Datenbankschicht)
|
||||
- Chat verbindet sich **anonym**, solange keine Zugangsdaten hinterlegt sind —
|
||||
damit lässt sich die Datenaufnahme prüfen, bevor die Twitch-Apps existieren
|
||||
- Zugangsdaten überstehen die Runde durch die Einrichtungsseite, liegen
|
||||
verschlüsselt mit Rechten `0600` im Volume, tauchen weder im HTML noch in der
|
||||
Datenbank noch in einer Volltextsuche im Klartext auf
|
||||
- Was noch aussteht: die Strecke IRC → Datenbank im Livebetrieb. Die Teile sind
|
||||
einzeln getestet, die Verdrahtung wird beim ersten echten Stream sichtbar.
|
||||
|
||||
**S0 abgenommen am 2026-09-09.** Im Image: Node 22.23, ffmpeg 5.1.9 mit
|
||||
libx264 und libass, whisper.cpp v1.7.4. `check-env` prüft Werkzeuge,
|
||||
Volumes, Layout-Geometrie, OBS-Erreichbarkeit und Zugangsdaten; die fünf
|
||||
verbleibenden Warnungen (Sprachmodell, OBS, drei `.env`-Schlüssel) sind auf
|
||||
dieser Entwicklungsmaschine erwartbar.
|
||||
libx264 und libass, whisper.cpp v1.7.4, Sprachmodell `ggml-small` geladen.
|
||||
`check-env` prüft Werkzeuge, Volumes, Layout-Geometrie, OBS-Erreichbarkeit und
|
||||
Zugangsdaten; die verbleibenden Warnungen (OBS nicht erreichbar, noch keine
|
||||
Zugangsdaten hinterlegt) sind auf dieser Entwicklungsmaschine erwartbar.
|
||||
|
||||
`calibrate` wurde mit einem echten 1920×1080-Bild durchgespielt: 1080×1920
|
||||
heraus, Ausschnitte an der richtigen Stelle. Damit ist der Filtergraph für S3
|
||||
@@ -56,13 +76,6 @@ und **die Facecam ist 4:3, nicht 16:9**. Beides ist in
|
||||
[`projects/clip-shorts.md`](projects/clip-shorts.md) dokumentiert und in
|
||||
`config/layout.yaml` aufgelöst.
|
||||
|
||||
Das Einmessen der Facecam war eigentlich Teil von S3, ließ sich aber aus dem
|
||||
gelieferten Screenshot sofort erledigen. Dabei kamen zwei Dinge heraus, die das
|
||||
geplante Layout verändert haben — **der Chat ist ins Streambild eingebrannt**
|
||||
und **die Facecam ist 4:3, nicht 16:9**. Beides ist in
|
||||
[`projects/clip-shorts.md`](projects/clip-shorts.md) dokumentiert und in
|
||||
`config/layout.yaml` aufgelöst.
|
||||
|
||||
## Umfang
|
||||
|
||||
### Drin
|
||||
@@ -101,13 +114,19 @@ in ein eigenes Volume, `scripts/check-env` als Selbsttest im Container.
|
||||
**Fertig, wenn:** `docker compose run --rm toolkit check-env` meldet ffmpeg,
|
||||
whisper.cpp, Modell und die Schreibrechte auf allen Volumes als OK.
|
||||
|
||||
### S1 — Auth und Datenaufnahme · ~2 Tage
|
||||
### S1 — Einrichtung, Auth und Datenaufnahme · ~3 Tage
|
||||
|
||||
OAuth-Flow (`auth`-Kommando, Callback auf Port 4780), verschlüsselter
|
||||
Token-Store mit automatischem Refresh, Helix-Client mit Rate-Limit-Bucket,
|
||||
DB-Migrationen für `streams`, `users`, `user_streams`, `chat_messages`,
|
||||
`viewer_samples`, `clips`. IRC-Client, der jede Nachricht schreibt.
|
||||
Stream-Sessions über Helix-Polling im Minutentakt.
|
||||
**Einrichtungs-Assistent** auf `http://localhost:4792/setup`: Client-ID und
|
||||
-Secret werden dort eingegeben, nicht in eine Datei. Verschlüsselter
|
||||
Secret-Speicher im Volume, OAuth-Flow mit Rücksprung auf denselben Port,
|
||||
Token-Refresh. Siehe [ADR-0005](decisions/ADR-0005-zugangsdaten.md).
|
||||
|
||||
Dazu Helix-Client mit Rate-Limit-Bucket, DB-Migrationen für `streams`, `users`,
|
||||
`user_streams`, `chat_messages`, `viewer_samples`, `clips`, ein IRC-Client, der
|
||||
jede Nachricht schreibt, und Stream-Sessions über Helix-Polling im Minutentakt.
|
||||
|
||||
> Der Assistent war ursprünglich nicht eingeplant und kostet etwa einen Tag
|
||||
> mehr. Dafür entfällt der `.env`-Schritt aus der Inbetriebnahme komplett.
|
||||
|
||||
**Fertig, wenn:** Nach einem echten Stream stehen alle Nachrichten in
|
||||
`chat_messages` und eine korrekte Zeile in `streams`.
|
||||
@@ -140,10 +159,12 @@ korrekt sitzender Facecam oben und Gameplay unten.
|
||||
|
||||
### S4 — Untertitel · ~1,5 Tage
|
||||
|
||||
Audiospur extrahieren (16 kHz Mono WAV), whisper.cpp mit `ggml-small` und
|
||||
`--language de`, Ausgabe als SRT mit Wort-Zeitstempeln, Umwandlung in ASS mit
|
||||
wortweisem Highlight, Stil aus `config/subtitle-style.ass`, Einbrennen.
|
||||
Sicherheitsabstand nach unten mindestens 320 px.
|
||||
**Nur die Mikrofonspur** extrahieren (OBS nimmt getrennt auf: Mikro Spur 2,
|
||||
Spielton Spur 3, Mischung Spur 1) als 16 kHz Mono WAV, whisper.cpp mit
|
||||
`ggml-small` und `--language de`, Ausgabe als SRT mit Wort-Zeitstempeln,
|
||||
Umwandlung in ASS mit wortweisem Highlight, Stil aus
|
||||
`config/subtitle-style.ass`, Einbrennen. Sicherheitsabstand nach unten
|
||||
mindestens 320 px. Ins Video kommt weiterhin die Mischung von Spur 1.
|
||||
|
||||
**Fertig, wenn:** `final.mp4` hat lesbare, zeitlich passende deutsche
|
||||
Untertitel, und der Text wird auf dem Handy von der TikTok-Oberfläche nicht
|
||||
@@ -174,12 +195,13 @@ merken — deshalb ist sie trotzdem drin.
|
||||
|
||||
| Woche | Scheiben | Ergebnis |
|
||||
|---|---|---|
|
||||
| 1 | S0, S1 | Läuft im Container, schreibt jeden Stream mit |
|
||||
| 1 | ~~S0~~, S1 | Einrichtung im Browser, schreibt jeden Stream mit |
|
||||
| 2 | S2, S3 | Knopfdruck erzeugt ein fertiges 9:16-Video |
|
||||
| 3 | S4, S5, S6 | Untertitel, Sichtungsseite, Begrüßung |
|
||||
|
||||
Rund neun Arbeitstage. Realistisch drei Kalenderwochen, wenn nebenher noch
|
||||
etwas anderes läuft.
|
||||
Rund zehn Arbeitstage (S0 erledigt, S1 durch den Einrichtungs-Assistenten einen
|
||||
Tag teurer). Realistisch drei Kalenderwochen, wenn nebenher noch etwas
|
||||
anderes läuft.
|
||||
|
||||
## Definition of Done für das gesamte MVP
|
||||
|
||||
@@ -200,7 +222,7 @@ Ein echter Stream, ohne Eingriff von außen:
|
||||
| Risiko | Wahrscheinlichkeit | Gegenmaßnahme |
|
||||
|---|---|---|
|
||||
| Encoding kostet Frames im Stream | mittel | `-preset veryfast`, CPU-Limit im Compose-File, Schalter `renderWhileLive: false` — dann läuft alles nach Streamende |
|
||||
| whisper.cpp versteht Spielgeräusche statt Sprache | mittel | Falls OBS getrennte Audiospuren aufnimmt, nur die Mikrofonspur transkribieren. Sonst Rauschgatter vorschalten. |
|
||||
| whisper.cpp versteht Spielgeräusche statt Sprache | ~~mittel~~ **gelöst** | OBS nimmt getrennte Spuren auf; transkribiert wird nur das Mikrofon (Spur 2). |
|
||||
| Twitch ändert die Ableitung der Clip-MP4-URL | niedrig | Betrifft nur den Zweitweg; die Rohdatei kommt aus OBS. Gekapselt in einer Datei. |
|
||||
| Replay-Buffer-Pfad-Abbildung Windows ↔ Container | mittel | In S2 als Erstes lösen, mit einem Testlauf vor allem anderen |
|
||||
| Docker Desktop belastet den Stream-PC | mittel | `.wslconfig` mit Speicher- und CPU-Grenze; wenn es stört, ist ein Betrieb ohne Container jederzeit möglich, weil nur ffmpeg und whisper.cpp fehlen |
|
||||
@@ -208,13 +230,17 @@ Ein echter Stream, ohne Eingriff von außen:
|
||||
## Was Abdu vorher tun muss
|
||||
|
||||
1. Docker Desktop installieren, WSL2-Backend aktivieren
|
||||
2. Zwei Twitch-Apps anlegen (siehe [`05-setup.md`](05-setup.md))
|
||||
2. Zwei Twitch-Apps anlegen, Redirect-URI `http://localhost:4792/callback`
|
||||
(siehe [`05-setup.md`](05-setup.md)). Client-ID und Secret **nicht**
|
||||
irgendwo eintragen — die kommen in den Einrichtungs-Assistenten.
|
||||
3. In OBS: obs-websocket aktivieren (Port 4455, Passwort), Wiedergabepuffer auf
|
||||
90 Sekunden, Hotkey auf „Wiedergabepuffer speichern" legen
|
||||
4. **Einen Screenshot der laufenden Szene** schicken — daraus wird der
|
||||
Facecam-Crop eingemessen
|
||||
5. Klären, ob OBS Mikrofon und Spiel auf getrennte Audiospuren aufnimmt (macht
|
||||
die Untertitel deutlich besser)
|
||||
4. ~~Screenshot der laufenden Szene schicken~~ — **erledigt**, Crop ist
|
||||
eingemessen und steht in `config/layout.yaml`
|
||||
5. ~~Getrennte Audiospuren klären~~ — **erledigt**, OBS nimmt getrennt auf;
|
||||
Whisper bekommt nur die Mikrofonspur
|
||||
6. In GTA die spieleigenen Untertitel ausschalten (werden vom Ausschnitt rechts
|
||||
abgeschnitten, und die eigenen liegen ohnehin darüber)
|
||||
|
||||
## Danach
|
||||
|
||||
|
||||
Reference in new issue
Block a user