Duplizierte Auth-Logik aus Notifications, Game Library und Streaming
Plugins komplett entfernt (-251 Zeilen). Alle Plugins nutzen jetzt
die zentrale Auth aus core/auth.ts via isAdmin Prop.
Admin-Buttons (Settings-Zahnrad) erscheinen nur noch wenn global
eingeloggt. Kein separater Login pro Tab mehr noetig.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cleanupViewer() ruft jetzt document.exitFullscreen() auf,
bevor der Viewer aus dem DOM entfernt wird. Verhindert
dass die Navbar nach Fullscreen-Stream verschwindet.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- remoteStreamRef speichert MediaStream aus ontrack, damit er nicht
verloren geht wenn das <video>-Element noch nicht gemountet ist
- useEffect verbindet Stream mit Video sobald beides bereit ist
- Explizites play() mit Mute-Fallback bei Autoplay-Blockierung
(neuer Tab ohne User-Interaktion, z.B. Discord-Link)
- Debug-Logging aus Notification-Config entfernt
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Neues Notification-Plugin mit eigenem Discord-Bot
- Admin-Modal im Streaming-Tab für Channel-Konfiguration
- Automatische Benachrichtigungen bei Stream-Start/Ende
- Stream-Links mit Passwort-Hinweis in Discord-Embeds
- Konfigurierbare Events pro Channel (stream_start, stream_end)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Electron: setDisplayMediaRequestHandler zeigt jetzt immer einen modalen Picker
mit Thumbnails statt automatisch die letzte Quelle zu verwenden
- Passwort bei Streams ist jetzt optional (Server + Frontend)
- Streams ohne Passwort: direkter Beitritt ohne Modal
- hasPassword wird korrekt im stream_available Event übertragen
- Windows Toast-Notifications via Electron Notification API für
"Stream gestartet" und "Neuer Stream" Events
- Browser-Variante nutzt weiterhin Web Notification API
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- stream_available/stream_ended WS-Events verarbeiten
- WS sofort beim Mount verbinden (nicht nur beim Broadcasting)
- WS reconnect immer aktiv (nicht nur bei aktivem Stream)
- Toast Notifications: neuer Stream, Update verfügbar/bereit
- Notification Permission beim App-Start anfragen
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Stream-Tile Klick öffnet Join-Modal statt neues Fenster
- checkForUpdates optional chaining für alte Electron App
- Abbrechen-Button im Update-Check Dialog
- 15s Timeout falls Electron nicht antwortet
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Klick auf Stream-Tile oeffnet neues Fenster via ?viewStream= URL.
Passwort-Modal erscheint automatisch im neuen Fenster nach dem Laden.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
App.tsx wechselt automatisch zum Streaming-Tab wenn ?viewStream= in der URL steht.
StreamingTab nutzt ref-basierten Ansatz: Stream-ID wird beim Mount gespeichert,
Passwort-Modal oeffnet sich sobald die Stream-Liste vom Server geladen ist.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server:
- Dual-Role: Client kann gleichzeitig broadcasten UND zuschauen
(broadcastStreamId + viewingStreamId statt single role)
- POST /api/streaming/disconnect Beacon-Endpoint fuer
zuverlaessigen Cleanup bei Page-Unload
- Heartbeat auf 5s reduziert (schnellere Erkennung)
Frontend:
- pagehide + sendBeacon: Streams werden sofort aufgeraeumt wenn
Browser geschlossen/neugeladen wird
- ICE Routing: Broadcaster-Map wird zuerst geprueft, dann Viewer-PC
→ Broadcast + View im selben Tab moeglich
- 3-Punkt-Menü mit Stream-Details, "In neuem Fenster oeffnen" und
"Link teilen" (Clipboard)
- Auto-Join via ?viewStream=... Query-Parameter (fuer geteilte Links)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- beforeunload Event verhindert versehentliches Verlassen/Reload
waehrend Broadcasting oder Viewing aktiv ist
- Vollbild-Button im Viewer-Header (Fullscreen API)
- Fullscreen-State wird korrekt getrackt und Icon wechselt
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Doppelter Offer entfernt (onnegotiationneeded + explizit createOffer)
- ICE Candidate Queuing: Candidates werden gepuffert bis setRemoteDescription
fertig ist, statt sie zu verwerfen
- Cleanup bei Re-Offer: vorherige PeerConnection wird sauber geschlossen
- Pending Candidates werden bei Disconnect/Leave aufgeraeumt
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Disconnect:
- Server-side heartbeat ping/pong every 10s with 25s timeout
- Detects and cleans up dead connections (browser closed, network lost)
- ws.terminate() on heartbeat timeout triggers handleDisconnect
Password:
- Stream password is mandatory (server rejects start_broadcast without)
- Password stored server-side, never sent to clients
- Viewers must enter password via modal before joining
- Lock icon on tiles, WRONG_PASSWORD error shown in modal
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The WebSocket onmessage handler captured isBroadcasting=false at creation
time. When ICE candidates arrived from remote viewers, the handler looked
up viewerPcRef instead of peerConnectionsRef, dropping all candidates.
Fix: use refs (isBroadcastingRef, viewingRef, handleWsMessageRef) so the
WS handler always reads current state. connectWs() now has [] deps and
delegates to handleWsMessageRef.current for every message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New plugin: browser-based screen sharing via Chrome Screen Capture API.
Multi-stream grid layout (Rustdesk-style tiles) with live previews.
- Server: WebSocket signaling at /ws/streaming (SDP/ICE relay)
- Server: http.createServer for WebSocket attachment
- Frontend: StreamingTab with broadcaster/viewer modes
- Frontend: tile grid, fullscreen viewer, LIVE badges
- Supports multiple concurrent streams
- Peer-to-peer video via WebRTC (no video through server)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>