6 Commits
Author SHA1 Message Date
ZeasyAlexandClaude Opus 5.5 eb9eab949e Liegestuetze: Zaehler aus Kanalpunkten, Overlay und Korrektur von Hand
Neue Aktion `liegestuetze` fuer Belohnungen: jede Einloesung zaehlt um
`anzahl` hoch (Vorgabe 5). Der Stand liegt in der Datenbank und
uebersteht einen Neustart. Browser-Source /liegestuetze zeigt ihn, die
Uebersichtsseite hat Knoepfe zum Herunterzaehlen und Setzen.

Nebenbei: POST /tts landete bei der Overlay-Seite statt bei der
Freigabe. Seiten werden jetzt nur noch bei GET ausgeliefert.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-04 00:15:50 +02:00
ZeasyAlexandClaude Opus 5 bc2c8f6cbe Overlay: fuenf Browser-Sources fuer OBS
Einblendungen, Chat, Statusleiste, Effekte, Pausenbild. Kein Build, kein
Framework - OBS laedt die Dateien direkt, und jede Zwischenstufe waere ein
Ding, das mitten im Stream kaputtgehen kann.

Server-Sent Events statt WebSocket, entgegen der Skizze in chat-control.md:
Node bringt einen WebSocket-*Client* mit, aber keinen Server, `EventSource`
verbindet sich von allein neu, und die Richtung stimmt - das Overlay hoert
nur zu. Gegen die tote Browser-Source nach einem Neustart stehen drei Dinge:
der eingebaute Reconnect, ein Herzschlag als echtes Ereignis (ein
SSE-Kommentar haelt die Verbindung offen, ist im Browser aber unsichtbar),
und ein Zustands-Schnappschuss beim Verbinden.

Abos, Raids, Bits und Loeschungen kommen ueber IRC-USERNOTICE und CLEARCHAT
herein; das wurde bisher weggeworfen. Follows fehlen weiter, die gibt es nur
ueber EventSub.

GIFs im Chat: Twitch schickt dafuer einen Tag `gifs`, den wir nicht kannten.

  gifs=0-22|Pnd7qLFuGCOntZcNKB|https://media0.giphy.com/media/.../giphy.gif
  PRIVMSG #abdulive_ :[Idk GIF by Respective]

Der Nachrichtentext ist nur ein Platzhalter, der Bereich markiert ihn.
Ausgewertet wird er jetzt; ohne das stand woertlich "[Idk GIF by Respective]"
im Bild. Gefunden wurde der Tag durch einen Rohmitschnitt - in 3094
Nachrichten aus acht grossen Kanaelen war kein einziges GIF, weil die Adresse
eben nicht im Text steht.

Zwei Fehler, die beim Durchklicken im Browser aufgefallen sind:

- Die Aufraeumfunktion im Chat zaehlte Zeilen, die erst nach der
  Ausblend-Animation aus dem DOM verschwinden, und lief in eine
  Endlosschleife. In OBS waere die Quelle beim vierzehnten Chatbeitrag
  eingefroren.
- Der Bereichsparser der GIFs war zu nachsichtig: `-1-4` zerfaellt beim
  Trennen in ['', '1', '4'], und `Number('')` ist 0 - der Bereich saehe
  gueltig aus und wuerde den falschen Textteil ersetzen.

Auf der Uebersichtsseite steht fuer jede Einblendung, jede Chat-Variante und
jeden Effekt ein Knopf. Ohne den liesse sich eine Raid-Einblendung nur
pruefen, indem man auf einen echten Raid wartet. Was einen Zustand setzt, ist
waehrend eines Streams gesperrt; "Stand zuruecksetzen" ausdruecklich nicht,
sonst kaeme man aus einem erfundenen Zustand nicht mehr heraus.

build-package.ts nimmt jetzt auch html/css/js mit - sonst liefert das Paket
404 statt Overlay.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 00:13:28 +02:00
ZeasyAlexandClaude Opus 5 c4dc6ee04f Go-Live-Ping: Discord meldet den Streamstart
Der billigste Hebel im Repo, und bis jetzt nur Vorarbeit: die Webhooks lagen
seit der Discord-Einrichtung bereit, gepostet hat nie jemand.

Ablauf: neuer Stream erkannt, eine Minute warten (Twitch setzt Titel und
Kategorie erst kurz nach dem Start, wer sofort postet kuendigt den Titel des
letzten Streams an), Daten frisch holen, Webhook posten, Rolle Live-Ping
anpingen.

Der Ping funktioniert nur mit `allowed_mentions` im Nachrichtenkoerper. `<@&ID>`
allein faerbt die Erwaehnung lila ein und benachrichtigt niemanden - der
Fehler, den man erst nach drei leeren Streams bemerkt. Dagegen steht ein
eigener Test.

Gegen den doppelten Post stehen drei Dinge, denn wer zweimal in zehn Minuten
angepingt wird, nimmt sich die Rolle wieder ab und ist damit fuer immer stumm:

- Tabelle `posts` mit eindeutigem Index je Stream und Plattform. Nur
  *gesendete* Posts sperren; ein fehlgeschlagener Versuch darf wiederholt
  werden, sonst kostet ein Netzwerkaussetzer die ganze Ankuendigung.
- Abklingzeit von sechs Stunden, gegen die neue Stream-ID nach einem
  Verbindungsabbruch.
- Ausgeloest wird nur beim erkannten Neustart, nie im Fortsetzungszweig.

`stream_id` ist bewusst kein Fremdschluessel: ein Post ist die Quittung fuer
etwas, das den Rechner verlassen hat, und muss auch dann schreibbar sein,
wenn es die Sitzung nicht gibt - beim Probelauf etwa.

Dazu ein vierter Webhook in #technik-log. Der Entwurfsmodus postet dieselbe
Nachricht dorthin, ohne Ping und nur fuer Mods sichtbar. So sieht man das
Ergebnis, bevor es der Server sieht.

Die Rollenaufloesung aus selfroles.ts liegt jetzt in roles.ts, weil der Ping
sie auch braucht: ein Webhook kann eine Rolle nicht ueber ihren Namen
anpingen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 00:12:35 +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 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