Files
twitch4steamdeck/plan.md
T
Andre 7d19ccf652 Projektstart
- Phase 1 "Twitch Login" abgeschlossen
2026-04-07 20:11:00 +02:00

185 lines
7.8 KiB
Markdown

# Twitch4SteamDeck — Architekturplan
> Spiegel von `C:\Users\andre\.claude\plans\smooth-shimmying-parasol.md`.
> Fortschritt steht in `todo.md`, aktueller Stand in `CLAUDE_PROGRESS.md`.
## Ziel
Steam-Deck-App zur **werbefreien** Wiedergabe von Twitch-Livestreams und -VODs.
Big-Screen-/10-Foot-UI, vollständig per Gamepad bedienbar. Lokaler VOD-Verlauf
mit Resume. Verteilung als Flatpak.
## Tech-Stack (entschieden)
| Bereich | Wahl |
|---|---|
| Sprache/Runtime | TypeScript + Electron (Main + Renderer) |
| UI | React + CSS, Spatial-Navigation für Gamepad |
| Wiedergabe | externer **mpv**-Prozess via JSON-IPC-Socket |
| Stream-Quelle / Ad-Bypass | **Streamlink** (Subprozess) + `--twitch-disable-ads`, optional TTV.LOL |
| Twitch-Auth | **OAuth 2.0 Device Code Flow** |
| Twitch-Daten | Helix-API (`api.twitch.tv/helix`) |
| Token-Storage | Electron `safeStorage` → `userData/twitch-tokens.bin` |
| Lokale Persistenz | SQLite via `better-sqlite3` (VOD-Verlauf, Settings) |
| Packaging | `electron-builder` → Flatpak |
## MVP-Scope
1. Twitch-Login via Device Code Flow
2. Followed Channels (Liste, Live-Indicator)
3. Live-Stream-Wiedergabe werbefrei (Streamlink → mpv)
4. VOD-Browsing pro Kanal
5. VOD-Wiedergabe werbefrei
6. Lokaler VOD-Verlauf + Resume + „Continue Watching"-Reihe
**Bewusst nicht im MVP:** Chat/Emotes, Suche, Kategorien, PiP, Themes.
## Architektur
```
┌─────────────────────────────────────────────────┐
│ Electron Main Process (Node) │
│ - AuthService (Device Code Flow, Refresh) │
│ - TwitchApiClient (Helix) │
│ - StreamlinkRunner (spawn streamlink) │
│ - MpvController (spawn mpv, JSON-IPC) │
│ - HistoryStore (better-sqlite3) │
│ - SettingsStore │
└──────────────┬──────────────────────────────────┘
│ IPC (contextBridge / preload)
┌──────────────┴──────────────────────────────────┐
│ Electron Renderer (React + TS) │
│ - Screens: Login, Home, Channel, Player │
│ - SpatialNavigation (Gamepad-Fokus) │
│ - GamepadInputService │
└─────────────────────────────────────────────────┘
```
Wiedergabe läuft **außerhalb** Electron in einem mpv-Vollbildfenster.
Electron startet/stoppt mpv, sendet Befehle, lauscht auf `time-pos` für Verlaufsspeicherung.
## Verzeichnisstruktur (Soll)
```
twitch4steamdeck/
├── package.json
├── electron.vite.config.ts
├── electron-builder.yml
├── flatpak/
│ └── tv.twitch4steamdeck.App.yml
├── src/
│ ├── main/
│ │ ├── index.ts ✅
│ │ ├── auth/
│ │ │ ├── deviceCodeFlow.ts ✅
│ │ │ ├── tokenStore.ts ✅
│ │ │ └── authService.ts ✅
│ │ ├── twitch/
│ │ │ ├── helixClient.ts ⏳ Phase 2
│ │ │ └── types.ts ⏳ Phase 2
│ │ ├── playback/
│ │ │ ├── streamlink.ts ⏳ Phase 3
│ │ │ └── mpvController.ts ⏳ Phase 3
│ │ ├── store/
│ │ │ ├── db.ts ⏳ Phase 5
│ │ │ ├── historyRepo.ts ⏳ Phase 5
│ │ │ └── settingsRepo.ts ⏳ Phase 5
│ │ └── ipc/
│ │ └── handlers.ts ✅ (nur Auth)
│ ├── preload/
│ │ └── index.ts ✅
│ └── renderer/
│ ├── index.html ✅
│ └── src/
│ ├── main.tsx ✅
│ ├── App.tsx ✅
│ ├── screens/
│ │ ├── LoginScreen.tsx ✅
│ │ ├── HomeScreen.tsx ⏳ Phase 2
│ │ ├── ChannelScreen.tsx ⏳ Phase 3/4
│ │ └── PlayerLaunchScreen.tsx ⏳ Phase 3
│ ├── components/
│ │ ├── FocusableCard.tsx ⏳ Phase 2
│ │ └── SpatialNav/ ⏳ Phase 2
│ ├── input/
│ │ └── gamepad.ts ⏳ Phase 2
│ ├── types/
│ │ └── t4sd.d.ts ✅
│ └── styles/
│ └── global.css ✅
└── resources/
└── icons/
```
## Kernkomponenten — Spezifikation
### Auth (✅ implementiert)
- Endpoint `POST https://id.twitch.tv/oauth2/device` mit `client_id` + `scopes` (space-sep).
- Anzeige `user_code` + `verification_uri` + QR.
- Polling `POST https://id.twitch.tv/oauth2/token` mit
`grant_type=urn:ietf:params:oauth:grant-type:device_code`.
- Refresh-Token via Electron `safeStorage`.
- Auto-Refresh wenn Helix 401.
- Client-ID via `MAIN_VITE_TWITCH_CLIENT_ID` (`.env` im Projektroot, electron-vite lädt sie).
- Scope MVP: `user:read:follows`.
### Helix-Client (⏳ Phase 2)
MVP-Endpoints:
- `GET /users` (eigener User)
- `GET /channels/followed?user_id=…` (paginiert via `after`)
- `GET /streams?user_id=…` (batched, max 100 IDs/Call)
- `GET /videos?user_id=…&type=archive`
Header: `Client-Id: <id>`, `Authorization: Bearer <access_token>`.
### Streamlink + mpv (⏳ Phase 3)
- `streamlink --twitch-disable-ads --twitch-api-header=Authorization=OAuth <token> --stdout twitch.tv/<channel> best`
- Pipe an `mpv -` mit `--input-ipc-server=/tmp/twitch4sd-mpv.sock --fullscreen --hwdec=vaapi`
- Auf Windows: Named Pipe statt Unix-Socket.
### VOD-History-DB (⏳ Phase 5)
```sql
CREATE TABLE vod_history (
vod_id TEXT PRIMARY KEY,
channel_login TEXT NOT NULL,
channel_display TEXT,
title TEXT,
thumbnail_url TEXT,
duration_seconds INTEGER,
resume_position_seconds INTEGER NOT NULL DEFAULT 0,
watched_at INTEGER NOT NULL,
completed INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX idx_history_watched ON vod_history(watched_at DESC);
```
„Continue Watching": `SELECT … WHERE completed=0 ORDER BY watched_at DESC LIMIT 20`.
Complete-Threshold: `resume_position / duration > 0.95`.
### Big-Screen-UI / Gamepad
- Spatial-Navigation-Lib oder eigene Mini-Implementierung.
- Fokus-Ring deutlich sichtbar.
- Schrift: min. 22px Body, 36px+ Headlines.
- Mapping: D-Pad/Stick = Navigation, A = Aktivieren, B = Zurück, Y = Refresh, Start = Menü, L1/R1 = Tab.
### Flatpak (⏳ Phase 6)
- Runtime: `org.freedesktop.Platform//23.08`, `org.electronjs.Electron2.BaseApp`
- Module: app-bundle, `mpv`, `streamlink` (pip), evtl. `streamlink-ttvlol`
- Permissions: `--share=network`, `--share=ipc`, `--socket=wayland`, `--socket=fallback-x11`,
`--socket=pulseaudio`, `--device=dri`
## Verifikation
End-to-End auf Steam Deck oder Linux-Box:
1. Build: `npm install && npm run build && flatpak-builder --user --install build-dir flatpak/…yml`
2. Login-Flow mit Device-Code + Smartphone
3. Live-Stream 5+ Min ohne Werbe-Unterbrechung (Streamlink-Debug-Logs gegenchecken)
4. VOD ansehen, mpv beenden, neu starten → springt an gespeicherte Position
5. Komplette Bedienung nur mit Steam-Deck-Controller
6. Im Gaming Mode als Non-Steam-Game starten und alles wiederholen
## Offene Punkte (Post-MVP)
- Eigene `client_id` im Build vor Release.
- Chat / Emotes (BTTV/FFZ/7TV).
- Suche, Kategorien, Top-Streams.
- README + ToS-Disclaimer (Twitch-Werbeumgehung kann gegen ToS verstoßen).