From d00550aa37099595cd6e30b850c9a02000ede3b6 Mon Sep 17 00:00:00 2001 From: Alexander Zielonka Date: Tue, 27 Oct 2026 19:16:04 +0100 Subject: [PATCH] Rueckbau: gestrichene Werkzeuge entfernt, Hub schreibt keinen Chat mehr mit Raid-Scout, Auswertung, VOD-Kapitel, Community-Gedaechtnis, Punkteshop und Recap samt Platzhaltern, Spezifikationen und Konfiguration. Der Hub schickt am Chat zusaetzlich die Sendezeit mit, fuer die Uhrzeit im Pult. Co-Authored-By: Claude Opus 5.5 --- README.md | 25 ++++------ apps/clipper/README.md | 5 -- apps/community/README.md | 5 -- apps/dashboard/README.md | 5 -- apps/hub/src/index.ts | 10 ++-- apps/loyalty/README.md | 5 -- apps/raid-scout/README.md | 5 -- apps/recap/README.md | 5 -- apps/vod-chapters/README.md | 5 -- config/config.example.yaml | 28 ----------- docs/01-architecture.md | 25 +++++----- docs/04-roadmap.md | 21 ++------- docs/07-mvp-plan.md | 4 +- docs/handoff.md | 25 +++++++--- docs/projects/README.md | 8 +--- docs/projects/analytics.md | 68 -------------------------- docs/projects/community-memory.md | 76 ------------------------------ docs/projects/discord-community.md | 2 +- docs/projects/loyalty-shop.md | 71 ---------------------------- docs/projects/raid-network.md | 64 ------------------------- docs/projects/stream-recap.md | 67 -------------------------- docs/projects/vod-chapters.md | 54 --------------------- 22 files changed, 52 insertions(+), 531 deletions(-) delete mode 100644 apps/clipper/README.md delete mode 100644 apps/community/README.md delete mode 100644 apps/dashboard/README.md delete mode 100644 apps/loyalty/README.md delete mode 100644 apps/raid-scout/README.md delete mode 100644 apps/recap/README.md delete mode 100644 apps/vod-chapters/README.md delete mode 100644 docs/projects/analytics.md delete mode 100644 docs/projects/community-memory.md delete mode 100644 docs/projects/loyalty-shop.md delete mode 100644 docs/projects/raid-network.md delete mode 100644 docs/projects/stream-recap.md delete mode 100644 docs/projects/vod-chapters.md diff --git a/README.md b/README.md index cd6afd8..c3eb064 100644 --- a/README.md +++ b/README.md @@ -11,23 +11,18 @@ Betrieb über Docker Compose. Zielgröße des Kanals: ~5–30 gleichzeitige Zuschauer. Alles hier ist auf diese Phase optimiert — nicht auf Skalierung, sondern auf **Wachstum und Bindung**. -## Die neun Tools +## Was es gibt -| # | Tool | Ordner | Zweck | Status | -|---|------|--------|-------|--------| -| 1 | Clip-to-Shorts | `apps/clipper` | Clips → 9:16 mit Untertiteln, Upload-fertig | geplant | -| 2 | Go-Live-Broadcaster | `apps/broadcaster` | Stream-Start → Discord/Bluesky/Instagram | geplant | -| 3 | Raid- & Netzwerk-Tool | `apps/raid-scout` | Raid-Ziele finden, Raid-Historie führen | geplant | -| 4 | Analytics-Dashboard | `apps/dashboard` | Viewer vs. Chat, Titel-Performance, Retention | geplant | -| 5 | VOD-Kapitel | `apps/vod-chapters` | Szenen-/Kategoriewechsel → Timestamps | geplant | -| 6 | Community-Gedächtnis | `apps/community` | Chatter-Profile, Begrüßungen, Overlay-Hinweise | geplant | -| 7 | Chat steuert Dinge | `apps/overlay-server` + `apps/overlay-web` | Overlay, Soundboard, Minigames, Umfragen | geplant | -| 8 | Punktesystem + Shop | `apps/loyalty` | Punkte mit echten Konsequenzen | geplant | -| 9 | Stream-Recap | `apps/recap` | Zusammenfassung nach Streamende in Discord | geplant | +| Teil | Ordner | Zweck | +|------|--------|-------| +| Hub | `apps/hub` | Läuft zentral im LXC: Chat, Overlay für OBS, Pult, Kanalpunkte, Discord, Go-Live-Ping | +| Overlay und Pult | `apps/overlay-server` + `apps/overlay-web` | Browser-Sources für OBS, Pult am Handy und Tablet | +| Go-Live-Ping | `apps/broadcaster` | Stream-Start → Discord | +| Ingest | `apps/ingest` | Läuft auf dem Stream-PC: OBS-Anbindung, `!clip`, 9:16-Render mit Untertiteln | -Dazu der Dienst, der unter allen anderen liegt: - -| — | **Ingest-Daemon** | `apps/ingest` | IRC + Helix → DB, Einrichtungsseite | **läuft** | +Die früher geplanten Werkzeuge (Raid-Scout, Auswertung, VOD-Kapitel, +Community-Gedächtnis, Punkteshop, Recap) sind gestrichen und mit ihren +Spezifikationen entfernt. ## Doku diff --git a/apps/clipper/README.md b/apps/clipper/README.md deleted file mode 100644 index de39171..0000000 --- a/apps/clipper/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# @abdulive/clipper - -Clip-to-Shorts-Pipeline: Trigger -> Replay/Clip -> 9:16 -> Untertitel -> Upload-Kandidat. - -Spezifikation: [docs/projects/clip-shorts.md](../../docs/projects/clip-shorts.md) diff --git a/apps/community/README.md b/apps/community/README.md deleted file mode 100644 index 4014368..0000000 --- a/apps/community/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# @abdulive/community - -Community-Gedaechtnis: Begruessungen, Meilensteine, Overlay-Hinweis. Modul im overlay-server. - -Spezifikation: [docs/projects/community-memory.md](../../docs/projects/community-memory.md) diff --git a/apps/dashboard/README.md b/apps/dashboard/README.md deleted file mode 100644 index 84f1b15..0000000 --- a/apps/dashboard/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# @abdulive/dashboard - -Analytics-Dashboard und Freigabe-Ansicht fuer Clip-Kandidaten. - -Spezifikation: [docs/projects/analytics.md](../../docs/projects/analytics.md) diff --git a/apps/hub/src/index.ts b/apps/hub/src/index.ts index d8cb18c..1fe5263 100644 --- a/apps/hub/src/index.ts +++ b/apps/hub/src/index.ts @@ -269,11 +269,9 @@ export async function runHub(): Promise { }, onMessage: (msg) => { try { - repo.recordMessage(msg, state.streamId); + // Chatnachrichten landen nicht mehr in der Datenbank. Gelesen haben + // sie nur Recap und Auswertung, und die gibt es nicht mehr. state.messages++; - repo.event('chat.message', { - text: msg.text, login: msg.login, isFirst: msg.isFirst, bits: msg.bits, - }, state.streamId, msg.userId, msg.ts); bus.publish({ kind: 'chat', @@ -291,6 +289,7 @@ export async function runHub(): Promise { broadcaster: msg.isBroadcaster, badges: badges.aufloesen(msg.badges), bits: msg.bits, + ts: msg.ts, }); if (msg.isFirst) { @@ -566,9 +565,6 @@ async function pollStream( state.startedLiveAt = live.started_at; state.lastSeenLive = now; state.viewers = live.viewer_count; - if (state.streamId) { - repo.sample(state.streamId, new Date().toISOString(), live.viewer_count); - } sendState(true); } } diff --git a/apps/loyalty/README.md b/apps/loyalty/README.md deleted file mode 100644 index 1c24726..0000000 --- a/apps/loyalty/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# @abdulive/loyalty - -Punktesystem mit Ledger und Shop mit echten Effekten. Modul im overlay-server. - -Spezifikation: [docs/projects/loyalty-shop.md](../../docs/projects/loyalty-shop.md) diff --git a/apps/raid-scout/README.md b/apps/raid-scout/README.md deleted file mode 100644 index 02c07be..0000000 --- a/apps/raid-scout/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# @abdulive/raid-scout - -Raid-Ziele finden und bewerten, Raid-Historie und Erwiderungs-Erinnerung. - -Spezifikation: [docs/projects/raid-network.md](../../docs/projects/raid-network.md) diff --git a/apps/recap/README.md b/apps/recap/README.md deleted file mode 100644 index 74cc2bd..0000000 --- a/apps/recap/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# @abdulive/recap - -Stream-Zusammenfassung nach Streamende als Discord-Post. - -Spezifikation: [docs/projects/stream-recap.md](../../docs/projects/stream-recap.md) diff --git a/apps/vod-chapters/README.md b/apps/vod-chapters/README.md deleted file mode 100644 index e020d42..0000000 --- a/apps/vod-chapters/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# @abdulive/vod-chapters - -Kapitel-Timestamps aus Kategorie- und Szenenwechseln. - -Spezifikation: [docs/projects/vod-chapters.md](../../docs/projects/vod-chapters.md) diff --git a/config/config.example.yaml b/config/config.example.yaml index 87997d7..f6ef649 100644 --- a/config/config.example.yaml +++ b/config/config.example.yaml @@ -95,34 +95,6 @@ broadcaster: mastodon: false instagramStoryImage: false -community: - greetings: - enabled: true - minSecondsBetween: 20 - maxPerStream: 10 - returningAfterDays: 21 - milestones: [5, 10, 25, 50, 100] - suppressWhileStreamerSpeaking: true - overlayHint: true - -raidScout: - minViewers: 5 - maxViewers: 30 - minUptimeMinutes: 30 - maxUptimeMinutes: 300 - languages: [de] - topN: 5 - -recap: - enabled: true - delayMinutesAfterOffline: 10 - minStreamMinutes: 20 - hideViewerNumbersIfWeak: true - topChatters: 3 - topClips: 2 - -loyalty: - enabled: false # spaetere Ausbaustufe # Kanalpunkt-Belohnungen und was sie ausloesen. # # Zugeordnet wird ueber den Titel der Belohnung auf Twitch (Gross-/Klein- diff --git a/docs/01-architecture.md b/docs/01-architecture.md index f99dab8..9a0e294 100644 --- a/docs/01-architecture.md +++ b/docs/01-architecture.md @@ -2,6 +2,9 @@ ## Bild +Stand vor dem Umzug in den Hub (ADR-0008). Raid-Scout, Auswertung, +VOD-Kapitel, Community-Gedaechtnis und Recap sind seit 2026-10-27 gestrichen. + ``` Twitch OBS ┌──────────────────┐ ┌───────────┐ @@ -20,19 +23,15 @@ ┌─────────────────┐ ┌──────────────────────┐ │ SQLite │ │ Event-Bus │ │ data/db/ │ │ (in-proc + WS 4790) │ - └────────┬────────┘ └──────────┬───────────┘ - │ │ - ┌───────────┬───────┼───────────┬───────────┼───────────┬──────────┐ - ▼ ▼ ▼ ▼ ▼ ▼ ▼ - dashboard recap raid-scout vod-chapters community overlay- clipper - server │ - │ │ - overlay-web ffmpeg - (Browser- whisper - Source) │ - data/clips - │ - broadcaster + └─────────────────┘ └──────────┬───────────┘ + │ + ┌─────────┴─────────┐ + ▼ ▼ + overlay-server clipper-Kette + (Pult, Sounds) ffmpeg, whisper + │ │ + overlay-web data/clips + (Browser-Source) ``` ## Prozesse diff --git a/docs/04-roadmap.md b/docs/04-roadmap.md index 4df9dde..4719a38 100644 --- a/docs/04-roadmap.md +++ b/docs/04-roadmap.md @@ -29,24 +29,11 @@ und Chat sowie Zuschauerzahlen vollständig in der DB stehen. **Fertig, wenn:** Erstchatter werden erkannt und begrüßt, Stream-Start wird automatisch angekündigt. -## M4 — Auswertung (Woche 5–6) +## M4 bis M6 — gestrichen -- [ ] `apps/dashboard`: Stream-Zeitachse, Abgangs-Analyse -- [ ] Titel-/Kategorie-Performance mit Stichprobenhinweis -- [ ] Kohortenansicht neu vs. wiederkehrend -- [ ] Betriebsstatus-Seite -- [ ] Spike-Detektor an echten Daten kalibrieren und scharf schalten - -## M5 — Netzwerk (Woche 7) - -- [ ] `apps/raid-scout`: Kandidatensuche, Scoring, `!raidziel` -- [ ] Raid-Historie und Erwiderungs-Erinnerung -- [ ] Overlay-Panel für das Streamende - -## M6 — Recap (Woche 8) - -- [ ] `apps/recap`: Discord-Post nach Streamende -- [ ] Clip-Einbettung, Erstchatter-Begrüßung, Wochenvergleich +Auswertung (`apps/dashboard`), Netzwerk (`apps/raid-scout`) und Recap +(`apps/recap`) sind seit 2026-10-27 gestrichen, samt Spezifikationen. Der Hub +bleibt bei OBS-Anbindung, Overlay, Pult, Kanalpunkten und Discord. ## Später diff --git a/docs/07-mvp-plan.md b/docs/07-mvp-plan.md index 60c1236..99e6600 100644 --- a/docs/07-mvp-plan.md +++ b/docs/07-mvp-plan.md @@ -260,8 +260,8 @@ in unter zwei Minuten entscheiden, welche Clips hochgeladen werden. Der IRC-Client aus S1 liegt ohnehin da, das `first-msg`-Tag ebenso. Eine Begrüßung für Erstchatter, eine für Rückkehrer nach mehr als 21 Tagen, mit -Cooldown und Obergrenze pro Stream. Details in -[`projects/community-memory.md`](projects/community-memory.md). +Cooldown und Obergrenze pro Stream. (Die ausführliche Spezifikation lag in +`projects/community-memory.md` und ist mit dem Community-Gedächtnis gestrichen.) Diese Scheibe steht am Ende, weil sie unabhängig ist und notfalls entfällt. Sie kostet fast nichts und ist das Einzige im MVP, das die Zuschauer direkt diff --git a/docs/handoff.md b/docs/handoff.md index 43cc80d..ab3b44e 100644 --- a/docs/handoff.md +++ b/docs/handoff.md @@ -142,6 +142,15 @@ Soundboard, Szenenwechsel, Clip-Knopf, Stummschaltern, Liegestützen, Vorlese-Freigabe und den Testknöpfen. Beschreibung in [`apps/overlay-web/README.md`](../apps/overlay-web/README.md#das-pult-pult). +**Seit 2026-10-27 mit Chat, nur lesend.** Eigener Reiter am Handy; ab +Tablet-Größe (760×500) steht der Chat fest rechts neben dem gewählten +Reiter, also etwa Szenen und Chat auf einem Bildschirm. Reiner Client-Code in +`pult.js`: der Chat kam schon immer über den Ereignisstrom des Pults, es +braucht weder neue Routen noch Rechte. Neu am Bus ist nur `ts` an der +Chatzeile, für die Uhrzeit. Geprüft im Browser mit `overlay --demo` in vier +Größen (Handy hoch und quer, iPad hoch und quer); auf einem echten Tablet +und im Stream noch nicht. + - **Sounds lädt Abdu selbst hoch**, am Handy über „+ Sound“. Sie liegen auf dem Hub unter `/sounds/`, gespielt wird über die Browser-Source `abdulive Sounds`, die `ingest` selbst in OBS anlegt. @@ -257,7 +266,7 @@ aufgetragen wird er mit `abdulive discord:setup`. Wiederholbar: gefunden wird nichts, gelöscht wird nie. Das ist Vorarbeit für drei Werkzeuge. Die Webhooks für -[Go-Live](projects/go-live-broadcaster.md), [Recap](projects/stream-recap.md) +[Go-Live](projects/go-live-broadcaster.md), Recap (inzwischen gestrichen) und [Clips](projects/clip-shorts.md) liegen fertig im verschlüsselten Speicher unter `goLiveWebhook`, `recapWebhook` und `clipsWebhook`. Wer diese Werkzeuge baut, muss sich um Discord nicht mehr kümmern, sondern nur noch posten. @@ -552,11 +561,15 @@ Wirkung. als Entwurf geht darin auf, die Statusleiste soll ersetzt werden. Danach die Liegestütze-Quelle in OBS eintragen und im Stream einmal beobachten. -**`apps/recap` bauen.** Angefangen, aber nicht committet: `apps/recap/src/recap.ts` -und Ergänzungen in `packages/db/src/repos.ts` liegen nur im Arbeitsstand -(die Typprüfung meckert dort noch über `url: undefined`). Der Webhook liegt -bereit, der Hub hat die Daten. Seit 2026-10-04 wird aus einem sauberen -Checkout ausgerollt, der halbe Recap liegt also nicht mehr im LXC. +**Recap und die übrigen geplanten Werkzeuge sind gestrichen** (2026-10-27). +Raid-Scout, Auswertung, VOD-Kapitel, Community-Gedächtnis, Punkteshop und +Recap sind samt Platzhaltern, Spezifikationen und Konfigurationsabschnitten +entfernt. Der Hub schreibt keine Chatnachrichten und Zuschauerproben mehr in +die Datenbank, gelesen haben die nur diese Werkzeuge; die Tabellen bleiben +stehen. Der angefangene Recap liegt nur im Git-Stash +`recap WIP (vor dem Rueckbau 2026-10-27)` des Rechners, auf dem er +angefangen wurde. Der Webhook `recapWebhook` steht weiter im Discord-Bauplan, +weil das Setup-Skript nie löscht. **Danach S5.** Nicht wegen des Codes, sondern weil das Werkzeug ohne Sichtungsseite für Abdu nicht bedienbar ist. Die Kette funktioniert, aber sie diff --git a/docs/projects/README.md b/docs/projects/README.md index 02ab1aa..9cd1d65 100644 --- a/docs/projects/README.md +++ b/docs/projects/README.md @@ -6,13 +6,7 @@ Entscheidungen, Fallstricke, Abnahmekriterien. | # | Dokument | App | |---|---|---| | — | [Ingest-Daemon](00-ingest.md) | `apps/ingest` | -| 1 | [Clip-to-Shorts](clip-shorts.md) | `apps/clipper` | +| 1 | [Clip-to-Shorts](clip-shorts.md) | `apps/ingest` | | 2 | [Go-Live-Broadcaster](go-live-broadcaster.md) | `apps/broadcaster` | -| 3 | [Raid- und Netzwerk-Tool](raid-network.md) | `apps/raid-scout` | -| 4 | [Analytics-Dashboard](analytics.md) | `apps/dashboard` | -| 5 | [VOD-Kapitel](vod-chapters.md) | `apps/vod-chapters` | -| 6 | [Community-Gedaechtnis](community-memory.md) | `apps/community` | | 7 | [Chat steuert Dinge](chat-control.md) | `apps/overlay-server`, `apps/overlay-web` | -| 8 | [Punktesystem und Shop](loyalty-shop.md) | `apps/loyalty` | -| 9 | [Stream-Recap](stream-recap.md) | `apps/recap` | | — | [Discord-Community](discord-community.md) | `packages/discord` | diff --git a/docs/projects/analytics.md b/docs/projects/analytics.md deleted file mode 100644 index e9ac019..0000000 --- a/docs/projects/analytics.md +++ /dev/null @@ -1,68 +0,0 @@ -# 4 — Analytics-Dashboard (`apps/dashboard`) - -**Wirkrichtung:** Steuerung. Beantwortet die Frage "was funktioniert -eigentlich", die Twitch selbst nicht beantwortet. - -Läuft auf `http://localhost:4792`. Vite + Preact + uPlot, liest direkt aus -SQLite. Keine Authentifizierung, weil nur lokal erreichbar. - -## Seiten - -### Stream-Zeitachse (die wichtigste) - -Eine gemeinsame X-Achse (Stream-Laufzeit), darauf übereinander: - -- Viewerzahl (Linie, aus `viewer_samples`) -- Chat-Nachrichten pro Minute (Balken) -- unterschiedliche Chatter pro 5 min (Linie) -- Marker: Kategoriewechsel, Titelwechsel, Raids rein/raus, Clips, Follows, Subs - -Damit sieht man direkt: An welcher Stelle kamen Leute rein, an welcher gingen -sie, und war der Chat da tot oder wach. **Zusammenhang von Viewerzahl und -Chat-Aktivität ist die Kernfrage** — 15 Zuschauer mit stillem Chat sind -weniger wert als 8 mit lebendigem. - -### Abgangs-Analyse - -Aus `viewer_samples`: Ableitung über die Zeit, die stärksten Abfälle markiert -und mit dem gleichzeitigen `stream_segments`-Eintrag und den Chat-Nachrichten -der Minute davor angereichert. Antwort auf "wann gehen die Leute". - -Wichtige Einschränkung, die im UI stehen muss: `viewer_samples` ist eine -Momentaufnahme der Gesamtzahl, keine Ein-/Austrittsliste. Twitch liefert das -nicht. Ein Abfall von 12 auf 8 kann vier Abgänge oder sechs Abgänge plus zwei -Zugänge bedeuten. Für Chatter ist es exakt (über `user_streams`), für stille -Zuschauer geschätzt. - -### Titel- und Kategorie-Performance - -Aggregation über `stream_segments`: pro Titel/Kategorie die durchschnittliche -Viewerzahl, der Nettozufluss während des Segments, Chat-Rate, gewonnene -Follower pro Stunde. Sortierbar. Mit Hinweis auf die Stichprobengröße — -bei drei Streams pro Titel ist jede Zahl Rauschen, und das Dashboard sagt das, -statt eine Rangliste vorzutäuschen. - -### Chatter: neu vs. wiederkehrend - -Pro Stream ein Stapelbalken: Erstchatter / wiederkehrend (1–4 Streams) / -Stammgast (5+). Dazu eine Kohorten-Tabelle: Von den Erstchattern aus Stream N, -wie viele waren in N+1, N+2, N+3 wieder da. Das ist die Zahl, die tatsächlich -über Wachstum entscheidet. - -### Betriebsstatus - -`GET /health` vom Ingest, letzte Fehler aus `logs/`, Größe der DB, -Clip-Warteschlange. - -## Clip-Freigabe - -Zusätzlich hostet das Dashboard die Freigabe-Ansicht für die Clip-Pipeline -(siehe [`clip-shorts.md`](clip-shorts.md)): Kandidatenliste mit -Videovorschau, Score, Chat-Ausschnitt und den Knöpfen *Übernehmen* / -*Verwerfen*. - -## Abnahmekriterien - -- Die Zeitachse eines abgeschlossenen Streams lädt in unter 2 s. -- Alle Marker liegen zeitlich korrekt (Abgleich gegen das VOD). -- Die Kohorten-Tabelle stimmt mit einer manuellen SQL-Auszählung überein. diff --git a/docs/projects/community-memory.md b/docs/projects/community-memory.md deleted file mode 100644 index 0777c67..0000000 --- a/docs/projects/community-memory.md +++ /dev/null @@ -1,76 +0,0 @@ -# 6 — Community-Gedächtnis (`apps/community`) - -**Wirkrichtung:** Bindung. Bei 10 Zuschauern der Unterschied zwischen -"Zuschauer" und "Community". - -Läuft als Modul im `overlay-server`, nicht als eigener Prozess — es braucht -dieselbe Chat-Verbindung und denselben WS-Kanal zum Overlay. - -## Datenlage - -Alles Nötige liegt bereits in `users` und `user_streams` (siehe -[`../03-data-model.md`](../03-data-model.md)). Dieses Tool ist überwiegend -**Auswertung und Ausgabe**, kaum neue Datenerfassung — deshalb ist es billig, -sobald der Ingest steht. - -## Die drei Ausgaben - -### 1. Chat-Begrüßung - -Ausgelöst durch die erste Nachricht eines Users im laufenden Stream: - -| Fall | Bedingung | Beispiel | -|---|---|---| -| **Erstchatter** | `first-msg`-Tag oder `users.message_count = 0` | "Oh, @name schreibt zum ersten Mal — willkommen!" | -| **Rückkehrer** | letzter Besuch > 21 Tage her | "@name, lange nicht gesehen." | -| **Meilenstein** | `streams_chatted` in {5, 10, 25, 50, 100} | "Stream Nummer 25 für @name." | -| **Stammgast** | `streams_chatted >= 5` | individuelle Begrüßung aus `users.greeting` | -| sonst | — | nichts | - -Regeln, damit es nicht nervt: höchstens eine Begrüßung alle 20 s, höchstens -zehn pro Stream, `muted_greeting` respektiert, und **keine Begrüßung, wenn Abdu -in den letzten 15 s selbst gesprochen hat** (der Ingest weiß über OBS bzw. über -eine Audiopegel-Schwelle, ob gerade geredet wird) — sonst redet der Bot dem -Streamer ins Wort. - -### 2. Overlay-Hinweis für Abdu - -Kleines, nur für Abdu sichtbares Panel (eigene Browser-Source in der -Studio-Ansicht oder zweiter Monitor). Wenn jemand schreibt: - -``` -┌──────────────────────────────────┐ -│ maxi_2k Stream 15 · Sub 3M │ -│ zuletzt: vor 2 Tagen │ -│ Notiz: studiert Maschinenbau, │ -│ spielt selbst Elden Ring │ -│ erste Nachricht: 04.03.2026 │ -└──────────────────────────────────┘ -``` - -**Das ist der eigentliche Wert.** Nicht der Bot, der etwas schreibt, sondern -Abdu, der weiß, mit wem er redet. Ein Bot, der "willkommen zurück" sagt, ist -Deko; ein Streamer, der "na, wie war die Klausur" sagt, bindet Menschen. - -### 3. Notizen - -Chat-Command für Abdu und Mods: `!notiz ` hängt an `users.notes` an. -Im Dashboard editierbar. Das ist die einzige Datenquelle, die Handarbeit -braucht, und die mit dem höchsten Nutzen pro Aufwand. - -## Datenschutz - -Die DB enthält personenbezogene Daten (Chatverläufe, Notizen). Sie liegt lokal, -wird nicht geteilt und nicht in ein Repo committet (`data/` ist in `.gitignore`). -`!vergissmich` löscht auf Wunsch alle Daten eines Users bis auf die anonyme -Aggregatstatistik. Notizen enthalten nichts, was man der Person nicht ins -Gesicht sagen würde. - -## Abnahmekriterien - -- Ein Testkonto, das zum ersten Mal schreibt, wird als Erstchatter erkannt und - genau einmal begrüßt. -- Nach einem Namenswechsel des Testkontos bleibt die Historie erhalten - (Verknüpfung über `user_id`, nicht `login`). -- Das Overlay-Panel zeigt den Hinweis innerhalb von 500 ms nach der Nachricht. -- Zwanzig Nachrichten in fünf Sekunden erzeugen höchstens eine Begrüßung. diff --git a/docs/projects/discord-community.md b/docs/projects/discord-community.md index a5b59fc..4538ed1 100644 --- a/docs/projects/discord-community.md +++ b/docs/projects/discord-community.md @@ -5,7 +5,7 @@ ist der Ort, an dem sie zwischen den Streams noch da sind. Ohne den zweiten Ort faengt jeder Stream bei null an. Der Server ist kein Tool aus der Neunerliste, aber drei davon posten dorthin: -[Go-Live-Broadcaster](go-live-broadcaster.md), [Stream-Recap](stream-recap.md) +[Go-Live-Broadcaster](go-live-broadcaster.md), Stream-Recap (gestrichen) und [Clip-to-Shorts](clip-shorts.md). Deshalb steht die Struktur hier im Repo und nicht nur in einer Oberflaeche. diff --git a/docs/projects/loyalty-shop.md b/docs/projects/loyalty-shop.md deleted file mode 100644 index c8f60d8..0000000 --- a/docs/projects/loyalty-shop.md +++ /dev/null @@ -1,71 +0,0 @@ -# 8 — Punktesystem mit Bedeutung (`apps/loyalty`) - -**Wirkrichtung:** Bindung. Läuft als Modul im `overlay-server`. - -## Warum nicht Channel Points? - -Twitch-Channel-Points funktionieren, haben aber zwei Grenzen: Man kann die -Vergabelogik nicht anpassen (keine Boni für Verhalten, das man belohnen will), -und Einlösungen sind an das Twitch-UI gebunden. Eigene Punkte laufen daneben. - -**Beides parallel betreiben.** Channel Points bleiben für simple Sachen, -eigene Punkte für alles, was Logik braucht. `channel.channel_points_custom_reward_redemption.add` -wird ohnehin schon ingested, also können beide Systeme dieselben Aktionen -auslösen. - -## Vergabe - -| Anlass | Punkte | -|---|---| -| pro 10 Minuten Anwesenheit | 10 | -| ...davon aktiv im Chat | +5 | -| erste Nachricht des Streams | 25 | -| Anwesenheit in Streamminute 1–10 | +50 (belohnt pünktliches Erscheinen) | -| Follow | 200 (einmalig) | -| Sub / Resub | 500 | -| Raid rein | 300 an den Raider | -| Clip, der übernommen wird | 250 an den Auslöser | - -Anwesenheit kommt aus `user_streams.minutes` (Helix-Chatter-Liste alle 5 min), -nicht aus dem Chat allein — sonst bekommen stille Zuschauer nie etwas. - -## Shop - -Der Punkt der Sache ist, dass Einlösungen **wirklich etwas tun**: - -| Artikel | Kosten | Aktion | Freigabe | -|---|---|---|---| -| Streamtitel für 10 min | 5.000 | `PATCH /helix/channels`, Timer setzt zurück | ja | -| Emote-Regen 30 s | 800 | Overlay-Effekt | nein | -| Sound aus dem Board | 300 | Overlay + Audio | nein | -| Challenge für Abdu | 3.000 | Karte im Overlay, Abdu bestätigt | ja | -| Nächstes Spiel bestimmen | 10.000 | Eintrag in die Warteschlange | ja | -| Facecam-Filter 60 s | 1.500 | obs-websocket Filter an | nein | - -`requires_approval` ist bei allem gesetzt, was den Stream nach außen verändert -(Titel!) oder Abdu zu etwas verpflichtet. Titeländerung zusätzlich abgesichert: -Wortfilter, Längenbegrenzung, automatische Rückkehr zum Originaltitel per -Timer, und der Originaltitel wird vorher in `stream_segments` gesichert. - -## Rückerstattung - -Wenn eine Aktion fehlschlägt (OBS nicht erreichbar, Helix-Fehler, Abdu lehnt -ab), werden die Punkte automatisch zurückgebucht und der User im Chat -informiert. `redemptions.status = 'refunded'`. - -## Bilanz-Integrität - -Punkte werden nie direkt auf `users.points` geschrieben, sondern als Zeilen in -einer `points_ledger`-Tabelle geführt; `users.points` ist ein -Materialized-Summenfeld, das über einen Trigger aktualisiert wird. So ist jede -Punktzahl nachvollziehbar und ein Fehler in der Vergabelogik reparierbar, ohne -dass jemandem grundlos Punkte fehlen. - -## Abnahmekriterien - -- Ein Zuschauer, der 30 min anwesend ist und dreimal schreibt, hat exakt die - erwartete Punktzahl. -- Titel-Einlösung ändert den Titel und setzt ihn nach 10 min zurück, auch wenn - der Server dazwischen neu startet (Timer wird persistiert). -- Fehlgeschlagene Einlösung bucht zurück. -- `points_ledger`-Summe stimmt mit `users.points` überein. diff --git a/docs/projects/raid-network.md b/docs/projects/raid-network.md deleted file mode 100644 index b07241b..0000000 --- a/docs/projects/raid-network.md +++ /dev/null @@ -1,64 +0,0 @@ -# 3 — Raid- und Netzwerk-Tool (`apps/raid-scout`) - -**Wirkrichtung:** Reichweite über Menschen statt über Algorithmen. In dieser -Kanalgröße die zuverlässigste Quelle für neue Stammzuschauer. - -## Kandidaten finden - -`GET /helix/streams?game_id=&first=100&language=de`, -seitenweise bis die Viewerzahl unter die Untergrenze fällt (Twitch sortiert -absteigend, also von hinten interessant). Filter: - -- Viewer zwischen `min` und `max` (Default 5–30, konfigurierbar) -- Sprache `de` -- Uptime mindestens 30 min und höchstens 5 h — wer gerade erst angefangen hat, - verliert durch einen Raid nichts, wer gleich aufhört, kann nichts damit - anfangen -- nicht auf der Sperrliste (`config/raid-blocklist.yaml`) - -## Bewertung - -``` -score = 0.35 * viewerNaehe (Ziel: aehnliche Groesse wie wir) - + 0.25 * kategorieUeberlapp (gleiche Kategorie > gleiche Sparte) - + 0.20 * beziehung (schon mal Kontakt gehabt? zurueckgeraidet?) - + 0.10 * frische (lange nicht mehr geraidet) - + 0.10 * uptimeFenster -``` - -`beziehung` kommt aus der `raids`-Tabelle: Wer uns geraidet hat und noch keinen -Raid zurückbekommen hat, steht ganz oben. **Das ist der eigentliche Kern des -Tools** — nicht das Finden von Fremden, sondern das Nicht-Vergessen von -Leuten, die schon Kontakt aufgenommen haben. - -## Oberfläche - -- **Chat-Command `!raidziel`** (nur Mods/Broadcaster): Bot postet die Top 3 mit - Login, Viewerzahl und Kategorie in den Chat. -- **Overlay-Panel**, das Abdu am Streamende einblenden kann: Top 5 als Karten, - Klick kopiert `/raid ` in die Zwischenablage. Bewusst **kein - automatisches Auslösen** — ein Raid ist eine soziale Geste, die einen - Menschen braucht. -- **Dashboard-Seite** mit der vollständigen Raid-Historie. - -## Netzwerk-Gedächtnis - -Für jeden Kanal, mit dem es je Kontakt gab: - -| Feld | Quelle | -|---|---| -| Raids rein / raus, mit Datum und Viewerzahl | `channel.raid` EventSub | -| erwidert ja/nein | berechnet | -| Notizen | manuell im Dashboard | -| letzter Kontakt | berechnet | - -Wöchentliche Erinnerung im Dashboard: "Diese 3 haben dich geraidet, du sie noch -nicht." - -## Abnahmekriterien - -- `!raidziel` liefert im laufenden Stream innerhalb von 3 s drei plausible - Kanäle in der aktuellen Kategorie. -- Ein eingehender Raid landet automatisch in `raids` mit `direction='in'`. -- Ein ausgehender Raid (manuell in Twitch ausgelöst) wird ebenfalls erfasst. -- Kanäle auf der Sperrliste tauchen nie auf. diff --git a/docs/projects/stream-recap.md b/docs/projects/stream-recap.md deleted file mode 100644 index bcfa567..0000000 --- a/docs/projects/stream-recap.md +++ /dev/null @@ -1,67 +0,0 @@ -# 9 — Stream-Recap (`apps/recap`) - -**Wirkrichtung:** Bindung. Gibt Leuten einen Grund, im Discord zu sein, und -hält den Kanal zwischen zwei Streams präsent. - -## Ablauf - -`stream.offline` → 10 Minuten warten (VOD-Verarbeitung, letzte Clips rendern) -→ Zahlen aus der DB ziehen → Discord-Post → optional Bluesky-Kurzfassung. - -## Inhalt - -``` -🔴 Stream vom 09.09. · 3 h 42 min · Elden Ring, Just Chatting - - Peak 17 Zuschauer · Schnitt 11 - 23 Leute im Chat, davon 4 zum ersten Mal - +6 Follower - - Top-Chatter - 1. maxi_2k 84 Nachrichten - 2. lenaaa 61 - 3. der_olli 47 - - Willkommen im Chat 👋 - @neuer1 @neuer2 @neuer3 @neuer4 - - Beste Momente - ▸ "Malenia Versuch 41" clips.twitch.tv/... - ▸ "Der Hund im Hintergrund" clips.twitch.tv/... - - VOD-Kapitel - 00:00 Start - 00:14 Elden Ring - 01:32 Pause - ... - - Nächster Stream: Mittwoch 20 Uhr -``` - -## Regeln, damit es gelesen wird - -- **Namen vor Zahlen.** Der Teil, der Leute in den Discord bringt, ist die - Liste mit ihren Namen darin — nicht die Peak-Viewer-Zahl. Erstchatter werden - namentlich begrüßt, Top-Chatter genannt. -- **Keine schlechten Streams schönreden, aber auch nicht ausstellen.** Wenn Peak - unter der Hälfte des Schnitts der letzten fünf Streams liegt, entfallen die - Viewer-Zahlen und der Post konzentriert sich auf Chat und Momente. Öffentlich - schwache Zahlen zu posten schadet mehr, als es nützt; im Dashboard stehen sie - trotzdem. -- **Kein Post ohne Inhalt.** Streams unter 20 Minuten oder ohne Chat-Aktivität - erzeugen keinen Recap. -- **Clips einbetten, nicht verlinken.** Discord bettet Twitch-Clips ab; die - besten zwei nach `clips.score`. - -## Vergleich zur Vorwoche - -Zweite Zeile, klein: "Chat +18 % ggü. letzten 4 Streams". Nur bei mindestens -vier Vergleichsstreams, sonst weggelassen — Prozentangaben auf Basis von zwei -Datenpunkten sind Unsinn. - -## Abnahmekriterien - -- Der Post erscheint innerhalb von 15 min nach Streamende. -- Alle Zahlen stimmen mit dem Dashboard überein. -- Ein Stream ohne Chat erzeugt keinen Post. -- Clip-Einbettungen funktionieren in Discord (nicht nur als nackte URL). diff --git a/docs/projects/vod-chapters.md b/docs/projects/vod-chapters.md deleted file mode 100644 index 6cb0e86..0000000 --- a/docs/projects/vod-chapters.md +++ /dev/null @@ -1,54 +0,0 @@ -# 5 — VOD-Kapitel (`apps/vod-chapters`) - -**Wirkrichtung:** Steuerung und ein wenig Reichweite (YouTube-Zweitverwertung). - -## Was aufgezeichnet wird - -Während des Streams sammelt der Ingest ohnehin schon: - -| Signal | Quelle | wird Kapitel? | -|---|---|---| -| Kategoriewechsel | EventSub `channel.update` | immer | -| Titelwechsel | EventSub `channel.update` | wenn Kategorie gleich bleibt | -| OBS-Szenenwechsel | obs-websocket | nur bei Szenen aus der Whitelist | -| Stream-Marker | `POST /helix/streams/markers` | immer | -| erstellter Clip | `clips` | als Kapitel-Kandidat | - -OBS-Szenen sind das rauschendste Signal — ein Wechsel auf "BRB" und zurück sind -zwei Wechsel, die kein Kapitel sind. Deshalb Whitelist in `config/obs-scenes.yaml` -plus Mindestabstand von 5 Minuten zwischen Kapiteln; kürzere Segmente werden mit -dem vorherigen verschmolzen. - -## Ausgabe - -Nach `stream.offline`: VOD über `GET /helix/videos?user_id=&type=archive&first=1` -holen, Zeitstempel relativ zu `streams.started_at` umrechnen, Text erzeugen: - -``` -00:00 Start & Begrüßung -00:14 Elden Ring — Malenia, Versuch 40 -01:32 Pause -01:47 Elden Ring — sie ist tot -02:55 Just Chatting — Community-Fragen -``` - -Format wählbar: Twitch-VOD-Beschreibung, YouTube-Kapitel (identisch, muss aber -bei `00:00` beginnen und mindestens drei Einträge mit je mindestens 10 s haben, -sonst zeigt YouTube keine Kapitel an), Discord-Nachricht. - -Twitch erlaubt kein Setzen der VOD-Beschreibung über die API — der Text landet -deshalb in `data/vods//chapters.txt` und wird per Push-Nachricht -zugestellt, plus als Block im Recap-Post. Einfügen dauert zehn Sekunden. - -## Kapitel-Titel - -Der Rohtitel ist der Twitch-Titel bzw. der Kategoriename. Optional (Ausbaustufe 2) -eine Verdichtung aus dem Chat: die häufigsten Substantive im Segment als -Zusatz. Erst sinnvoll, wenn genug Chat-Volumen da ist. - -## Abnahmekriterien - -- Ein Testtream mit zwei Kategoriewechseln und drei Szenenwechseln erzeugt - genau die erwarteten Kapitel. -- Zeitstempel weichen vom VOD um weniger als 5 s ab. -- Kein Kapitel unter 5 Minuten Länge.