Commit graph

257 commits

Author SHA1 Message Date
Daniel
987e03a590 Fix bump-version: override alpine/git entrypoint for shell execution
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 15:43:04 +01:00
Daniel
259c87bfd3 Optimize build: Kaniko cache flags, split Dockerfile stages, install-tools script
- Kaniko: --cache-ttl=168h, --snapshot-mode=redo, --compressed-caching=false
- Dockerfile: Split server-build into server-deps + server-build for better layer caching
- Replace rm+reinstall node_modules with npm prune --omit=dev
- Move ffmpeg/yt-dlp install to tools/install-tools.sh (single RUN layer)
- Remove separate ffmpeg-fetch stage and inline curl/yt-dlp install
- Remove $CI_COMMIT_SHA tag destination (unused, saves push time)
- bump-version: alpine/git image instead of alpine + apk add git

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 15:39:01 +01:00
Daniel
6c57419959 Feature: Watch Together - History, Titel-Fetch, Next-Button
Server:
- Video-History Tracking (max 50 Einträge pro Raum)
- History wird bei Skip und Play-Video gespeichert
- Server-seitiger Titel-Fetch via noembed.com als Fallback

Client:
- Aufklappbare History-Sektion im Queue-Panel
- "Weiter" Button mit Text-Label statt nur Icon
- YouTube-Thumbnails in der Warteschlange
- History in RoomState integriert

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 15:31:57 +01:00
GitLab CI
a1a1f31c8e v1.5.7 [skip ci] 2026-03-07 14:08:32 +00:00
Daniel
3455e20a96 Feature: Live Stream-Liste + Toast Notifications
- 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>
2026-03-07 15:05:42 +01:00
GitLab CI
939137cc77 v1.5.6 [skip ci] 2026-03-07 14:01:52 +00:00
GitLab CI
a174e39861 v1.5.5 [skip ci] 2026-03-07 14:01:52 +00:00
Daniel
4947191cb3 Fix: bump-version Reihenfolge - erst checkout, dann VERSION ändern
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 15:00:28 +01:00
Daniel
fa4b379a90 Fix: Stream in gleichem Fenster öffnen + Update-Dialog Abbrechen-Button
- 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>
2026-03-07 14:57:41 +01:00
Daniel
83a8382a6c Fix: bump-version git pull --rebase vor Push
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 14:53:19 +01:00
Daniel
e057a61c55 Fix: optional chaining für setStreaming (alte Electron App Kompatibilität)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 14:47:43 +01:00
GitLab CI
4153d9059b v1.5.4 [skip ci] 2026-03-07 13:33:15 +00:00
Daniel
dfc88210ce Fix: bump-version fetch+checkout main vor push 2026-03-07 14:30:14 +01:00
GitLab CI
d8ec632ac9 v1.5.3 [skip ci] 2026-03-07 13:29:05 +00:00
Daniel
ce2a26ddeb Add: Check-for-Updates Button in Electron App
- Manueller Update-Check per Button im Header
- Modal-Zustaende: checking, downloading, ready, uptodate, error
- IPC: check-for-updates, update-not-available Events
2026-03-07 14:27:09 +01:00
Daniel
c2942737bd Add: Update-Modal mit Download-Fortschritt in Electron App
- Modal-Overlay statt Banner fuer Update-Benachrichtigung
- 3 Zustaende: Downloading (Ladeanimation), Ready (OK-Button), Error
- IPC-Events: update-available, update-ready, update-error
2026-03-07 14:24:59 +01:00
GitLab CI
feeabe147c v1.5.2 [skip ci] 2026-03-07 13:22:16 +00:00
Daniel
8edaf93e30 Fix: bump-version Rule auf CI_COMMIT_TITLE statt MESSAGE 2026-03-07 14:19:18 +01:00
Daniel
9689af4d3a Add: Automatische Versionierung via VERSION-Datei
- VERSION-Datei als Single Source of Truth (startet bei 1.5.1)
- CI liest Version aus Datei statt hardcoded
- Patch-Version wird nach Deploy automatisch gebumpt
- Commit mit [skip ci] verhindert Endlosschleife
2026-03-07 14:17:27 +01:00
Daniel
7bebb7db9a Fix: Stream-close-warning via IPC statt async executeJavaScript
- Renderer meldet Streaming-Status synchron per IPC
- main.js prueft Status synchron im close-Handler
- Kein async Race mehr, Dialog erscheint zuverlaessig
2026-03-07 14:14:51 +01:00
Daniel
e2ae624690 Fix deploy: login to registry + use internal registry address 2026-03-07 14:07:57 +01:00
Daniel
8bfc2b1b0a Fix: Deploy via Docker-Socket statt SSH
Runner laeuft auf adriahub - nutzt Docker-Socket direkt.
Secrets (Discord Tokens, Admin PWD) als CI-Variablen.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 14:03:37 +01:00
Daniel
0301ace4a0 Add: Auto-Deploy nach erfolgreichem CI Build
- Deploy-Stage in CI: SSH auf adriahub nach Build
- deploy.sh auf adriahub: pull + recreate Container
- Nur auf main Branch, nach erfolgreichem Build

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 14:00:45 +01:00
Daniel
7ef4eefc55 Add: Update-Dialog fuer Electron Auto-Updater
- main.js: IPC-Events an Renderer senden wenn Update bereit
- main.js: install-update IPC Handler (quitAndInstall)
- App.tsx: Update-Banner "Neues Update verfuegbar!" mit Restart-Button
- styles.css: Update-Bar Styling passend zum Design-System

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 13:53:26 +01:00
Daniel
06ab7f523b Add: Stream-Warnung beim Beenden der Electron App
Dialog "Stream laeuft noch!" erscheint nur wenn ein aktiver
Video-Stream erkannt wird. Ohne Stream schliesst die App normal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 13:49:53 +01:00
Daniel
5eab3c1956 Add: Auto-Updater fuer Electron App
- Server: /updates Endpoint fuer Squirrel.Windows Update-Feed
- Electron: autoUpdater mit 30min Check-Intervall
- Preload: IPC-Events fuer Update-Status ans Frontend

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 13:45:27 +01:00
Daniel
c8799710ac Fix: Screen Capture in Electron App aktivieren
setDisplayMediaRequestHandler hinzugefügt damit getDisplayMedia
in der Electron App funktioniert (Streaming/Bildschirmfreigabe).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 13:17:32 +01:00
Daniel
0646a1b46e Fix: Downloads aus /data/downloads servieren + Electron Build fixen
- Downloads-Pfad von relativem App-Pfad auf DATA_DIR/downloads geändert
- Electron package.json: author Feld ergänzt (Squirrel-Requirement)
- forge.config.js: fehlende Icon-Referenzen entfernt

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 12:51:53 +01:00
Daniel
17dcd6073f V1.5.0: Version bump + Download-Button Redesign
- Version auf 1.5.0 in allen Packages, CI, Dockerfile, Electron
- Download-Button im gleichen Design wie Version-Badge (bg-secondary, radius, hover accent)
- CI Registry auf adriahub (192.168.1.100:9080) umgestellt

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 12:38:51 +01:00
d6082f8dcf CI: Fix registry to use port 9080 (same as GitLab) 2026-03-07 11:31:13 +00:00
8bb6cec01b CI: Switch registry to adriahub (192.168.1.100:5050) 2026-03-07 11:24:38 +00:00
Daniel
09813b626f Watch Together: Embed-Fehlerbehandlung, klickbare Queue, Video-Titel
- YouTube onError Handler: Erkennt Error 101/150 (Embedding deaktiviert),
  zeigt Fehlermeldung + "Auf YouTube oeffnen" Link, auto-skip nach 3s
- Queue-Items klickbar fuer Host (play_video mit Index)
- Video-Titel werden via noembed.com oEmbed API geholt
- Server-Endpoint: GET /api/watch-together/video-info?url=...
- "Hinzufuegen" Button zeigt Ladezustand waehrend Titel-Fetch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 11:19:59 +01:00
Daniel
e4895a792c Fix: WebSocket-Konflikt zwischen Streaming und Watch Together
Root Cause: ws-Library killt WS-Verbindungen mit HTTP 400 wenn
mehrere WebSocketServer mit { server, path } registriert werden.
Der erste WSS (streaming) hat abortHandshake() fuer watch-together
Verbindungen aufgerufen.

- Beide WSS auf noServer-Modus umgestellt
- Zentrales upgrade-Routing in index.ts nach Pathname
- Frontend: connectWs prueft jetzt auch CONNECTING-State
- Frontend: onclose clobbert wsRef nur noch wenn gleicher Socket
- Frontend: waitForWs hat jetzt 10s Timeout statt Endlosschleife

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 11:02:36 +01:00
Daniel
e748fc97e9 Fix: Watch Together Raum-Erstellung + Download-Button
- Server/Frontend Protokoll-Mismatch behoben (create_room, join_room, room_created, room_joined, playback_state)
- togglePlay sendet jetzt korrekt pause/resume statt toggle_play
- Download-Button: SPA-Fallback fuer /downloads/ verhindert, 404 statt Reload
- download-Attribut am Link hinzugefuegt

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 02:48:43 +01:00
Daniel
73f247ada3 Watch Together Plugin + Electron Desktop App mit Ad-Blocker
Neuer Tab: Watch Together - gemeinsam Videos schauen (w2g.tv-Style)
- Raum-System mit optionalem Passwort und Host-Kontrolle
- Video-Queue mit Hinzufuegen/Entfernen/Umordnen
- YouTube (IFrame API) + direkte Video-URLs (.mp4, .webm)
- Synchronisierte Wiedergabe via WebSocket (/ws/watch-together)
- Server-autoritative Playback-State mit Drift-Korrektur (2.5s Sync-Pulse)
- Host-Transfer bei Disconnect, Room-Cleanup nach 30s

Electron Desktop App (electron/):
- Wrapper fuer Gaming Hub mit integriertem Ad-Blocker
- uBlock-Style Request-Filtering via session.webRequest
- 100+ Ad-Domains + YouTube-spezifische Filter
- Download-Button im Web-Header (nur sichtbar wenn nicht in Electron)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 02:40:59 +01:00
Daniel
4943bbf4a1 Streams oeffnen standardmaessig in neuem Fenster mit Passwortabfrage
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>
2026-03-07 02:11:16 +01:00
Daniel
59ebfc91a9 Fix: Auto-Join via ?viewStream= URL-Parameter funktioniert jetzt
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>
2026-03-07 02:07:49 +01:00
Daniel
470bef62e4 Streaming: Stale-Stream Fix, Broadcast+View gleichzeitig, 3-Punkt-Menü
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>
2026-03-07 01:56:14 +01:00
Daniel
813e017036 Fix: Umlaut-Darstellung im Zurueck-Button korrigiert
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 01:45:47 +01:00
Daniel
3ef25fc10a Beforeunload-Warnung + Vollbild-Button fuer Viewer
- 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>
2026-03-07 01:37:21 +01:00
Daniel
2ee36789b2 Stream auf 60 FPS + 8 Mbps Bitrate angehoben
- getDisplayMedia: frameRate ideal 60, 1920x1080
- WebRTC Sender: maxFramerate 60, maxBitrate 8 Mbps pro Viewer-PC

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 01:34:55 +01:00
Daniel
3f9b446f27 Fix: Schwarzes Bild bei Viewern - WebRTC Race Conditions behoben
- 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>
2026-03-07 01:16:09 +01:00
Daniel
c9378f4cdb Fix: Tab-Auswahl bleibt nach Reload erhalten (localStorage)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 01:10:01 +01:00
Daniel
4aed4e70ab fix(streaming): reliable disconnect + mandatory stream password
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>
2026-03-07 01:00:48 +01:00
Daniel
dacfde4328 fix(streaming): resolve stale closure preventing remote WebRTC connections
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>
2026-03-07 00:51:09 +01:00
Daniel
29bcf67121 feat(streaming): add Screen Streaming plugin with WebRTC
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>
2026-03-07 00:39:49 +01:00
Daniel
9ff8a38547 feat(soundboard): download modal with filename input + fix yt-dlp binary
- Add download modal: filename input, progress phases (input/downloading/done/error)
- Refactor backend: shared handleUrlDownload() with optional custom filename + rename
- Fix Dockerfile: use yt-dlp_linux standalone binary (no Python dependency)
- Modal shows URL type badge (YouTube/Instagram/MP3), spinner, retry on error

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:59:31 +01:00
Daniel
0b2ba0ef86 feat(soundboard): add comprehensive yt-dlp and URL download logging
Every step now logged with timestamps, exit codes, stdout/stderr
streaming in real-time. yt-dlp runs with --verbose flag. Routes log
URL type detection, download progress, normalization, play status.
Error messages include HTTP status codes and specific yt-dlp errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:47:24 +01:00
Daniel
df937f3e40 fix(soundboard): auto-prepend https:// for URL import
URLs pasted without protocol (e.g. instagram.com/reel/...) now work.
normalizeUrl() adds https:// if missing. Input type changed from
"url" to "text" to prevent browser validation blocking paste.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:45:41 +01:00
Daniel
200f03c1f8 feat(soundboard): extend URL download to support YouTube & Instagram
yt-dlp extracts audio as MP3 from YouTube and Instagram links.
Direct MP3 links continue to work as before. URL input field now shows
a type indicator (YT/IG/MP3) and validates all three formats.

Backend: downloadWithYtDlp() spawns yt-dlp with --extract-audio,
saves to SOUNDS_DIR, normalizes if enabled. New /download-url route
for save-only without auto-play. play-url route extended for all types.

Frontend: isSupportedUrl() validates YouTube/Instagram/MP3, dynamic
icon changes per URL type, disabled state when URL is unsupported.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:38:09 +01:00