Commit Graph
17 Commits
Author SHA1 Message Date
ZeasyAlexandClaude Opus 5 e87879de9e Uebergabe auf den aktuellen Stand
Stand 2026-09-15. Der Discord-Server ist dazugekommen, der Rest ist
unveraendert: S2 wartet weiter auf ein laufendes OBS.

- Neuer Abschnitt "Der Discord-Server steht": was da ist, und dass die drei
  Webhooks fuer Broadcaster, Recap und Clipper bereitliegen. Wer diese
  Werkzeuge baut, muss nur noch posten.
- Neuer Abschnitt "Discord: was gemessen ist", nach dem Vorbild der
  Windows-Fallen. Vier Dinge, die nicht in der Doku stehen, in der man
  zuerst sucht: das Limit von zwei Umbenennungen je zehn Minuten, die
  Rangfolge-Regel hinter dem irrefuehrenden "Missing Permissions", die
  Schwelle fuer Onboarding und die Namensnormalisierung.
- Zwei Handgriffe fuer Abdu ergaenzt: sich selbst die Rolle geben, und den
  Einladungslink verteilen. An Letzterem haengt, ob der Server ueberhaupt
  jemanden bekommt.
- Ehrlich dazugeschrieben, was offen ist: der Knopf haengt am Daemon, und
  der Bot ist nie unter Last gelaufen.
- Der Hinweis auf die zwei Remotes, damit sie nicht auseinanderlaufen.
- 93 -> 162 Tests.

offene-punkte.md bekommt einen Discord-Abschnitt, die Roadmap den Hinweis,
dass die Discord-Seite von M3 schon steht.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 22:05:03 +02:00
ZeasyAlexandClaude Opus 5 994ce4faf0 Discord: Knopf fuer die Live-Ping-Rolle statt Onboarding
Live-Ping nuetzt nur, wenn man sie sich selbst geben kann. Discords
Onboarding waere der vorgesehene Weg, laesst sich hier aber nicht
einschalten - gemessen, nicht vermutet:

  HTTP 400  Cannot enable onboarding, requirements are not met  (350000)
  sichtbar fuer @everyone: 5   davon beschreibbar: 3
  Discord verlangt:        7   davon beschreibbar: 5

Zwei Kanaele anzulegen, damit eine Schwelle passt, macht den Server leerer
statt besser. Stattdessen ein Knopf unter dem Willkommenstext: ein Druck
holt die Rolle, der naechste gibt sie ab, die Antwort sieht nur, wer
geklickt hat.

Der Knopf braucht eine dauerhafte Verbindung, weil Discord Klicks ans
Gateway oder an eine oeffentliche HTTPS-Adresse liefert und der Stream-PC
keine hat:

- gateway.ts   WebSocket mit Herzschlag, Fortsetzen und Wiederverbinden.
               Bei 4004 und Verwandten wird aufgegeben statt im Kreis zu
               laufen - dagegen hilft nur eine Aenderung an der App.
               intents: 0, der Bot sieht weder Nachrichten noch Mitglieder.
- selfroles.ts Knopfleiste und Rollenwechsel.
- bot.ts       beides zusammen, laeuft im Ingest-Daemon mit. Ohne
               hinterlegtes Token entfaellt er wortlos.

Neuer Befehl `abdulive discord:bot` zum Ausprobieren; im Normalbetrieb
haengt der Bot im Daemon und meldet sich als discordConnected auf der
Statusseite.

Die Knopfleiste gehoert zum Soll-Zustand des Willkommenstextes: fehlt sie,
wird sie nachgereicht, ohne die Nachricht neu zu posten.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 21:59:08 +02:00
ZeasyAlexandClaude Opus 5 3b744caf6a Discord-Community-Server: Bauplan und Einrichtungsbefehl
Der Server ist kein Tool aus der Neunerliste, aber Broadcaster, Recap und
Clipper posten dorthin. Deshalb steht die Struktur als Code im Repo und
nicht nur in einer Oberflaeche.

packages/discord:
- permissions.ts  Rechtebits als BigInt, das Feld ist 64 Bit breit
- api.ts          REST-Client: Warteschlange, Rate Limits, lesbare Fehler
- plan.ts         Rollen, Kanaele, Rechte, AutoMod, Willkommenstext
- apply.ts        traegt den Bauplan auf einen bestehenden Server auf

Neuer Befehl `abdulive discord:setup [--server ID] [--vorschau]`.

Zugeschnitten auf 5 bis 30 gleichzeitige Zuschauer: fuenf sichtbare Kanaele
statt zwanzig, und eine selbst vergebene Rolle Live-Ping statt eines
Rundrufs an alle bei jedem Stream.

Wiederholbar statt einmalig: gefunden wird ueber Namen und frueheren Namen,
danach wird angeglichen. Der zweite Lauf aendert nichts. Geloescht wird nie,
und von Hand gesetzte Rechte-Ausnahmen bleiben stehen.

Drei Dinge, die am echten Server nachgemessen und nicht angenommen wurden:
- Discord schreibt Textkanaele klein und macht aus Leerzeichen Bindestriche;
  Emoji, Umlaute und U+2502 bleiben. normalizeName() bildet das ab, sonst
  geht bei jedem Lauf dieselbe Umbenennung erneut raus.
- Kanalnamen lassen sich nur zweimal je zehn Minuten aendern, danach
  verlangt Discord bis zu neun Minuten Pause. Der Lauf wartet hoechstens
  eine Minute und meldet den Rest.
- Eine Rolle kann nur Rollen unterhalb der eigenen verschieben, auch mit
  Administrator. rolePositions() rechnet den Platz unter der Bot-Rolle aus,
  statt blind 3, 2, 1 zu verlangen.

Zugangsdaten laufen ueber den verschluesselten Speicher (ADR-0005): der
Bot-Token wird verdeckt abgefragt, die drei Webhook-URLs werden nie
ausgegeben und nie geloggt.

Im Quelltext bleibt es bei ae/oe/ue, alles was ein Mitglied auf Discord
liest steht in richtigem Deutsch. Ein Test haelt das fest.

Begruendung, Fallstricke und die Schritte von Hand:
docs/projects/discord-community.md

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 20:43:21 +02:00
ZeasyAlexandClaude Opus 5 d231e1c722 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
2026-09-09 20:54:58 +02:00
ZeasyAlexandClaude Opus 5 7775c689be Handbuch als LaTeX, mit Bauskript
docs/handbuch/handbuch.tex plus bauen.ps1. Acht Seiten: was das Werkzeug
tut, Installation, Einrichtung Schritt fuer Schritt, OBS, Betrieb,
Updates, Sicherung, Deinstallation, Fehlersuche, Dateiablage.

Inhalte aus dem Quelltext gezogen, nicht geschaetzt: Abklingzeiten,
Tonspuren, Ausgabedateien, Routen der Einrichtungsseite.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AhVSfMFdWnXKCv5JfLnArZ
2026-09-09 20:12:26 +02:00
ZeasyAlexandClaude Opus 5 04da6ef802 Doku: Abschnitt zur Deinstallation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AhVSfMFdWnXKCv5JfLnArZ
2026-09-09 20:05:39 +02:00
ZeasyAlexandClaude Opus 5 2cdb4690e5 Doku: der Installer macht die drei Schritte selbst
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AhVSfMFdWnXKCv5JfLnArZ
2026-09-09 18:20:16 +02:00
ZeasyAlexandClaude Opus 5 92f14eaa62 Doku: Installation mit einem Befehl
Getestet wie Abdu es tippt, in frischer Umgebung: laedt, prueft die
Pruefsumme, installiert, legt die Aufgaben an. check-env danach ohne
harte Fehler.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AhVSfMFdWnXKCv5JfLnArZ
2026-09-09 18:01:50 +02:00
ZeasyAlexandClaude Opus 5 08f7c21450 Veroeffentlichung ueber Gitea, BOM-Toleranz, Tests fuer den YAML-Leser
Das Repo ist jetzt oeffentlich, die Pakete haengen an der Veroeffentlichung
`latest`. Damit funktioniert `abdulive update` ohne Token.

- config.example.yaml traegt die gepruefte Update-Adresse
- .gitea/workflows/release.yml baut beim Tag und ersetzt `latest`
- Byte Order Mark: Notepad und `Set-Content -Encoding utf8` schreiben eines,
  und ohne Behandlung hiess der erste Schluessel in der config.yaml
  "\ufeffchannel" - die Einstellung waere stillschweigend ignoriert worden
- Der YAML-Leser hatte gar keine Tests; er liest die Konfiguration, an der
  alles haengt. Jetzt acht.

Der Updater ist einmal komplett durchgelaufen: 0.4.0 erkannt, 119 MB geladen,
Pruefsumme geprueft, bereitgelegt, von launcher.ps1 getauscht.

93 Tests, Typpruefung sauber.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AhVSfMFdWnXKCv5JfLnArZ
2026-09-09 17:43:43 +02:00
ZeasyAlexandClaude Opus 5 5f6301268a 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
2026-09-09 17:39:26 +02:00
ZeasyAlexandClaude Opus 5 71dd660d01 Uebergabe: Stand, offene Punkte, Einstieg fuer den naechsten
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013VTGjd92LsDDWF3frd9FTB
2026-09-09 11:36:34 +02:00
ZeasyAlexandClaude Opus 5 974dfd075b S4: Untertitel aus der Mikrofonspur, plus vorgegebenes OBS-Layout
whisper.cpp laeuft ueber die Tonspur und liefert Tokens; daraus werden
Woerter mit Zeitstempeln (Wortstuecke wie "Sav"+"ina" wieder zusammengesetzt)
und daraus kurze Zeilen im ASS-Format mit wortweiser Hervorhebung. SRT und
Transkript fallen nebenbei ab.

An einem echten deutschen Clip geprueft. Drei Fehler kamen erst dabei heraus:
Zeilen mit einem einzigen Wort bei zoegerndem Sprechen, ein Nachlauf, der in
die naechste Zeile ragte (ASS stapelt gleichzeitige Zeilen uebereinander),
und ein Uebertragsfehler im Zeitformat bei 59,999 s.

Layout wird jetzt VORGEGEBEN statt nachgemessen: ein Vergleich zweier
Aufnahmen zeigte, dass die Facecam von Stream zu Stream anders liegt. Das
Profil "default" beschreibt die Vorgabe (Facecam 480x270 oben links, Chat ab
x=1405, Gameplay-Band 890 breit mittig auf x=960), "bestand-2026-09" haelt
den alten Zustand fuer altes Material fest. Dazu eine Ausrichtungsvorlage als
Bild, die in OBS ueber die Szene gelegt wird, und docs/obs-layout.md.

Befund am echten Clip: im Streambild sind bereits zwei Textebenen eingebrannt
(Spieluntertitel und ein Live-Caption-Overlay). Beides ist im Layout-Dokument
behandelt.

53 Tests gruen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013VTGjd92LsDDWF3frd9FTB
2026-09-09 10:55:54 +02:00
ZeasyAlexandClaude Opus 5 0e020f3073 S3: 9:16-Render mit Warteschlange, nachrangig zum Stream
Aus der Rohdatei entsteht das fertige Hochformat. Der Filtergraph liegt jetzt
in packages/media und wird von calibrate und vom Render-Schritt gemeinsam
benutzt - die Zahlen darin sind eingemessen, sie gehoeren an genau eine Stelle.

Eine Aufgabe nach der anderen, und waehrend gesendet wird standardmaessig
gar nicht (renderWhileLive: false). ffmpeg laeuft unter nice, mit Zeitlimit,
und die letzten Zeilen von stderr landen in der Fehlermeldung statt im Nichts.
Aus dem 90-Sekunden-Puffer werden die letzten 45 Sekunden genommen (-sseof vor
-i, sonst wird die ganze Datei dekodiert und danach verworfen).

Dabei einen eigenen Fehler aus S2 korrigiert: die Rohdatei wurde in den
Windows-Bind-Mount kopiert und dort verarbeitet - genau das, was ADR-0004
Punkt 2 verbietet. Jetzt liegt sie im Arbeits-Volume, auf die Windows-Seite
kommt nur das fertige, kleine Ergebnis.

Verifiziert an einer kuenstlichen Aufnahme mit drei getrennten Tonspuren:
1920x1080/70 s hinein, 1080x1920/45 s heraus, Naht an der richtigen Stelle,
27,9 s Rechenzeit unter nice 15. 39 Tests gruen.

Neuer Befehl `render <datei>` zum Nachrendern nach Layout-Aenderungen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013VTGjd92LsDDWF3frd9FTB
2026-09-09 10:21:58 +02:00
ZeasyAlexandClaude Opus 5 684f10eb02 S2: obs-websocket, Wiedergabepuffer und der !clip-Ausloeser
Eigener obs-websocket-v5-Client (das Protokoll ist klein genug, und das
Projekt bleibt ohne Abhaengigkeiten). Anmeldung, Wiederverbindung mit
wachsender Pause, Ereignisse fuer ReplayBufferSaved und Szenenwechsel.

Der Clipper loest zwei Wege gleichzeitig aus: OBS-Wiedergabepuffer fuer die
Rohdatei in Aufnahmequalitaet, Twitch-Clip fuer die teilbare URL. Faellt
einer aus, ist der andere trotzdem etwas wert. Ein direkt in OBS gedrueckter
Hotkey wird ohne unseren Umweg erkannt und als vollwertiger Ausloeser
behandelt.

Die Pfaduebersetzung Windows -> Container hat eine eigene Datei und eigene
Tests - das ist die Stelle, an der die Pipeline am ehesten scheitert. Dazu
Warten auf den abgeschlossenen Schreibvorgang, bevor die Datei uebernommen
wird.

Zum Testvektor der OBS-Anmeldung: die Spezifikation nennt Salt und Challenge,
aber kein erwartetes Ergebnis. Der Erwartungswert wurde unabhaengig mit
Pythons hashlib aus derselben Beschreibung gerechnet; der Test sagt das im
Kommentar, statt einen amtlichen Vektor vorzutaeuschen.

29 Tests gruen. Die Abnahme von S2 braucht ein laufendes OBS und steht aus.

Ausserdem: ADR-0006 haelt fest, dass alles unter einem Dach laeuft - eine
lokale Weboberflaeche plus Kindprozesse fuer Rechenarbeit. Die Prozessliste
in der Architekturdoku ist entsprechend ersetzt. Der Onboarding-Assistent
ist als Teil von S5 aufgenommen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013VTGjd92LsDDWF3frd9FTB
2026-09-09 10:10:54 +02:00
ZeasyAlexandClaude Opus 5 d07c18441b 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
2026-09-09 09:56:55 +02:00
ZeasyAlexandClaude Opus 5 4ceb61f095 S0 abgenommen: Image gebaut, check-env und calibrate verifiziert
Image 258 MB mit Node 22.23, ffmpeg 5.1.9 (libx264, libass) und
whisper.cpp v1.7.4. check-env laeuft ohne harte Fehler durch; calibrate
erzeugt aus einem 1920x1080-Bild die 1080x1920-Komposition mit den
eingemessenen Ausschnitten.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013VTGjd92LsDDWF3frd9FTB
2026-09-09 08:58:56 +02:00
ZeasyAlexandClaude Opus 5 d09e2b945a Struktur, Doku und S0-Toolchain fuer das abdulive-Toolkit
Monorepo-Geruest fuer neun Streamer-Tools plus den Ingest-Daemon, der
unter sechs davon liegt. Enthaelt:

- docs/: Ueberblick, Architektur, Twitch-Integration, Datenmodell,
  Roadmap, Setup, Hebel-Analyse und den MVP-Plan "Clip-Knopf"
- docs/projects/: je eine Spezifikation pro Tool
- docs/decisions/: vier ADRs (TS-Monorepo, SQLite, EventSub/IRC, Docker)
- docker/: Image mit ffmpeg und whisper.cpp, abhaengigkeitsfreier
  Entrypoint mit check-env, fetch-model und calibrate
- config/layout.yaml: aus einem VOD-Screenshot eingemessener
  Facecam-Ausschnitt (440x330 oben links, Chat-Overlay ab x=1270)

Noch kein Anwendungscode - Scheibe S0 aus docs/07-mvp-plan.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013VTGjd92LsDDWF3frd9FTB
2026-09-09 08:56:09 +02:00