From 1251cc278a861b5b1400fb53b13f4c31870b286b Mon Sep 17 00:00:00 2001 From: Andre <200930841+Andre-Bzk@users.noreply.github.com> Date: Sun, 10 May 2026 12:13:34 +0200 Subject: [PATCH] feat: add quality selection, improve chapter panel UX, and show VOD view counts Quality selection during playback: - Add getAvailableQualities() in streamlink via --json, sorted by fixed order - Expose playback:get-qualities IPC channel (handlers, preload, type declarations) - Add quality panel in PlaybackOverlay: - Button + dropdown - Keyboard navigation (X: open, arrows: navigate, Enter: confirm, Escape: close) - Quality change triggers streamlink restart; VOD resumes at current position - Available in ChannelScreen (Live + VOD) and AppShell global overlay (Live) - Add QualityIcon Chapter panel UX improvements: - Video no longer pauses when chapter panel opens - PlaybackOverlay is hidden via conditional render instead - Remove wasPlayingBeforeChapters state (no longer needed) - X button seeks to video start when no chapters are found, with hint in panel UI VOD cards and defaults: - Show view count with eye icon on VOD cards (matching playback overlay style) - Change default streamBadgeMode from 'language' to 'both' --- CLAUDE.md | 34 ++- README.md | 18 +- package.json | 2 +- src/main/ipc/handlers.ts | 9 +- src/main/playback/playbackService.ts | 11 +- src/main/playback/streamlink.ts | 37 ++++ src/preload/index.ts | 7 +- src/renderer/src/components/Icons.tsx | 11 + .../src/components/PlaybackOverlay.tsx | 101 ++++++++- src/renderer/src/context/SettingsContext.tsx | 2 +- src/renderer/src/screens/AppShell.tsx | 73 +++++- src/renderer/src/screens/ChannelScreen.tsx | 207 ++++++++++++++---- src/renderer/src/styles/global.css | 160 +++++++++++++- src/renderer/src/types/t4sd.d.ts | 3 +- 14 files changed, 594 insertions(+), 81 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 512d33a..8166392 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,6 +1,6 @@ # Twitch4SteamDeck — CLAUDE.md -Ad-freier Twitch-Client für das Steam Deck. Electron + React, gamepad-navigierbar, Big-Screen-UI (auf Linux/Steam Deck: Fenster maximiert auf Primärdisplay; im Windows-Dev: 1280x800). Unterstützt Live-Streams und VODs mit Resume und Kapitelwahl. Deployment als Flatpak auf dem Steam Deck. +Twitch-Client für das Steam Deck. Electron + React, gamepad-navigierbar, Big-Screen-UI (auf Linux/Steam Deck: Fenster maximiert auf Primärdisplay; im Windows-Dev: 1280x800). Unterstützt Live-Streams und VODs mit Resume und Kapitelwahl. Deployment als Flatpak auf dem Steam Deck. --- @@ -24,7 +24,7 @@ Electron Main Process ├── AuthService — Twitch Device Code Flow, Token-Verwaltung (safeStorage) ├── HelixClient — Twitch Helix REST API + GQL (Kapitel) ├── PlaybackService — Live-/VOD-Orchestrierung -│ └── streamlink.ts — getStreamUrl() via streamlink --stream-url +│ └── streamlink.ts — getStreamUrl() + getAvailableQualities() via streamlink ├── historyRepo — SQLite VOD-Verlauf (Resume, Completed) └── gamepadReader — Linux /dev/input/js* Joystick-Leser @@ -52,6 +52,8 @@ Renderer (React) - **VOD-Playback:** ChannelScreen → IPC `playback:start-vod` → PlaybackService → `streamlink --stream-url twitch.tv/videos/` → HLS-URL → IPC-Event `playback:hls-url` → Renderer → `VideoPlayer` (hls.js, seekTo startPosition) - **Overlay:** `PlaybackOverlay` (z-index: 300) liegt als normales DOM-Element über `VideoPlayer` (z-index: 100) — kein Fenster-Layering nötig - **Seek/Pause/Stop:** direkt über `videoRef.current` (kein IPC-Roundtrip) +- **Qualitätswechsel:** `videoRef.current.stop()` → `startLive/startVod(quality)` → neuer `playback:hls-url` Event — streamlink-Neustart nötig, da Single-Bitrate-HLS (kein hls.js Level-Switch möglich) +- **Qualitätsliste:** `IPC playback:get-qualities` → `streamlink --json ` → `Object.keys(streams)` sortiert nach fixem Order-Array - **Position-Tracking:** `VideoPlayer` meldet alle 5s via IPC `playback:report-position` → Main → SQLite - **Gamepad:** `/dev/input/js*` (Linux/Gaming-Mode) **oder** `navigator.getGamepads()` (Windows/Dev) → synthetische `KeyboardEvent`s → alle Screen-Handler reagieren auf Keys @@ -100,8 +102,8 @@ src/main/ ipc/ handlers.ts — Alle ipcMain.handle()-Registrierungen + Event-Forwarding playback/ - playbackService.ts — Orchestrator: streamlink --stream-url → HLS-URL → playback-hls-url Event - streamlink.ts — getStreamUrl() via streamlink --stream-url (Prozess-Spawning, URL-Extraktion: letzte https://-Zeile) + playbackService.ts — Orchestrator: streamlink --stream-url → HLS-URL → playback-hls-url Event; startVod(quality?); getAvailableQualities() + streamlink.ts — getStreamUrl() + getAvailableQualities() via streamlink (--stream-url für URL, --json für Qualitätsliste) types.ts — Quality-Typ, PlaybackEvent, HlsUrlPayload store/ db.ts — SQLite-Init, WAL-Modus, Migration (vod_history-Tabelle) @@ -120,18 +122,18 @@ src/renderer/src/ App.tsx — Auth-Gate, Gamepad-Init main.tsx — React-DOM-Bootstrap, SettingsProvider screens/ - AppShell.tsx — Tab-Routing, Sidebar/Main-Fokus-Split, Globaler Playback-Overlay (direkter Stream-Start ohne ChannelScreen) + AppShell.tsx — Tab-Routing, Sidebar/Main-Fokus-Split, Globaler Playback-Overlay (direkter Stream-Start ohne ChannelScreen), Qualitätswahl für Live LoginScreen.tsx — Device-Code-Login, QR-Code, Countdown FollowingScreen.tsx — Gefolgte Kanäle (Grid), Live/Offline-Sort BrowseScreen.tsx — Top-Streams-Shelf (A=Direkt-Play, X=Kanalseite) + Kategorien-Grid (Infinite Scroll) CategoryScreen.tsx — Streams einer Kategorie (A=Direkt-Play, X=Kanalseite) - ChannelScreen.tsx — Channel-Detail, VOD-Shelf, VideoPlayer + PlaybackOverlay, Kapitel-Panel + ChannelScreen.tsx — Channel-Detail, VOD-Shelf, VideoPlayer + PlaybackOverlay, Kapitel-Panel, Qualitätswahl StreamListScreen.tsx — Sprachgefilterte Stream-Liste DE/EN (A=Direkt-Play, X=Kanalseite) SettingsScreen.tsx — streamBadgeMode, sidebarWidth, badgeGap AccountScreen.tsx — Nutzerinfo, Logout components/ VideoPlayer.tsx — hls.js