No description
Find a file
Daniel f03fe63bd3
All checks were successful
Build & Deploy / build (push) Successful in 44s
Build & Deploy / deploy (push) Successful in 5s
Build & Deploy / bump-version (push) Successful in 3s
Move clock from Soundboard to app header, display next to version
Clock now shows globally in the header (left of version badge) instead
of being Soundboard-only. Smaller size to fit header layout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 11:45:29 +01:00
.forgejo/workflows Use single data mount for deploy, remove legacy jukebox sounds path 2026-03-11 11:28:37 +01:00
electron v1.9.0 2026-03-11 10:35:36 +01:00
server v1.9.0 2026-03-11 10:35:36 +01:00
tools Optimize build: Kaniko cache flags, split Dockerfile stages, install-tools script 2026-03-07 15:39:01 +01:00
web Move clock from Soundboard to app header, display next to version 2026-03-11 11:45:29 +01:00
.dockerignore Initial commit: Gaming Hub foundation 2026-03-05 22:52:13 +01:00
.gitlab-ci.yml CI: docker image prune nach jedem Deploy 2026-03-09 21:37:36 +01:00
Dockerfile Optimize build: Kaniko cache flags, split Dockerfile stages, install-tools script 2026-03-07 15:39:01 +01:00
README.md v1.8.0: README aktualisiert + Version Bump 2026-03-09 00:20:07 +01:00
VERSION v1.9.5 [skip ci] 2026-03-11 10:42:56 +00:00

Gaming Hub

Plugin-basierte Discord-Bot-Plattform mit Web-Dashboard und Electron Desktop App. Drei Bots (Jukebox, Radio, Notifications) laufen parallel mit eigenem Discord-Token und eigener Voice-Connection pro Guild.

Architektur

gaming-hub/
├── server/                 # Backend (Node.js + Express + TypeScript)
│   └── src/
│       ├── index.ts        # Entry Point, SSE, Plugin-Loader, WebSocket
│       ├── core/
│       │   ├── discord.ts      # Discord.js Client Factory (Multi-Bot)
│       │   ├── plugin.ts       # Plugin-System + Voice Claims
│       │   ├── sse.ts          # Server-Sent Events Broadcasting
│       │   └── persistence.ts  # JSON State auf Disk (Atomic Writes)
│       └── plugins/
│           ├── radio/          # World Radio (3D Globe + FFmpeg)
│           ├── soundboard/     # Jukebox / Soundboard (PCM Cache)
│           ├── lolstats/       # League of Legends Statistiken
│           ├── streaming/      # P2P Live-Streaming (WebRTC)
│           ├── watch-together/ # Synchron Video schauen
│           ├── game-library/   # Steam + GOG Spielebibliothek
│           └── notifications/  # Discord Benachrichtigungen
│
├── web/                    # Frontend (React 19 + Vite + TypeScript)
│   └── src/
│       ├── App.tsx             # Root, Tab-Navigation, SSE-Handler
│       ├── styles.css          # Globale Styles
│       └── plugins/
│           ├── radio/          # 3D Globe UI (Three.js Sprites)
│           ├── soundboard/     # Sound Grid UI + Admin Panel
│           ├── lolstats/       # Summoner-Suche + Match History
│           ├── streaming/      # Stream-Erstellung + Viewer
│           ├── watch-together/ # Raeume, Queue, Chat, Voting
│           └── game-library/   # Spielebibliothek Grid
│
├── electron/               # Desktop App (Windows, Squirrel Installer)
│   ├── main.js             # BrowserWindow, Auto-Updater, Ad-Blocker
│   ├── preload.js           # IPC Bridge (contextBridge)
│   ├── ad-blocker.js        # Request-Filter + Filterliste
│   └── forge.config.js      # Electron Forge (Squirrel.Windows)
│
├── Dockerfile              # Multi-Stage Production Build (4 Stages)
├── .gitlab-ci.yml          # CI/CD (Kaniko Build + Deploy + Electron Build)
└── VERSION                 # Aktuelle Version (SemVer)

Tech Stack

Komponente Technologie Version
Runtime Node.js 24 (slim)
Backend Express 5.x
Frontend React + Vite 19.x / 6.x
Discord discord.js + @discordjs/voice 14.x / 0.19.x
3D Globe globe.gl + three.js 2.35 / 0.172
Audio FFmpeg (GPL Build) + @discordjs/opus latest / 0.10.x
Streaming WebSocket (ws) + WebRTC (Browser) 8.x
Desktop Electron + Squirrel.Windows 33.x
TypeScript tsc 5.9.x
CI/CD GitLab + Kaniko v1.23.2

Plugins

Radio (radio)

  • 3D-Globus mit 30.000+ Radiosendern weltweit (Radio Garden API)
  • NASA Blue Marble Globus-Textur (statisches Satellitenbild)
  • Sender als Sprite-Partikel mit radialer Gradient-Textur (Theme-Farbe)
  • Server-seitiger Tile-Proxy mit In-Memory Cache (max 500 Tiles)
  • FFmpeg PCM-Streaming in Discord Voice Channels
  • Per-Guild Lautstaerke, Favoriten, Suche
  • Voice Stats (Ping, Status, Uptime) via SSE

Soundboard / Jukebox (soundboard)

  • Sound-Upload (MP3/WAV) mit Drag & Drop
  • Automatische Audio-Normalisierung (LUFS, FFmpeg)
  • PCM Memory Cache (Standard 512 MB) fuer sofortige Wiedergabe
  • Kategorien, Badges, Statistiken, Entrance/Exit Sounds
  • Admin-Panel mit HMAC-Token-Authentifizierung
  • Party-Modus (Chaos Mode)

LoL Stats (lolstats)

  • League of Legends Spielerstatistiken via op.gg
  • Summoner-Suche nach Game Name + Tag Line + Region
  • Match History mit Detail-Analyse
  • Letzte Suchen (max 10) persistent gespeichert
  • Unterstuetzte Regionen: NA, EUW, EUNE, KR, JP, BR, LAN, LAS, OCE, TR, RU, PH, SG, TH, TW, VN

Streaming (streaming)

  • Peer-to-Peer Live-Streaming via WebRTC (kein Media-Server noetig)
  • WebSocket-Signaling fuer Offer/Answer/ICE-Austausch
  • Qualitaets-Presets: 720p30, 1080p30, 1080p60, 1440p60, 4K60, 4K165 Ultra
  • Einstellbare Bitrate (2.5 Mbit/s bis 50 Mbit/s je nach Preset)
  • Optionaler Passwortschutz (Server-seitige Verifikation)
  • Viewer-Liste mit Echtzeit-Updates
  • Discord-Benachrichtigungen bei Stream-Start/-Ende (via Notifications Plugin)
  • Stream-Link Auto-Join aus Discord (?viewStream=UUID)
  • Heartbeat-basierte Client-Erkennung (5s Intervall)

Watch Together (watch-together)

  • Synchronisiertes Video-Schauen in Raeumen
  • Video-Queue mit URL-Eingabe
  • Demokratisches Voting (Skip, Pause)
  • Integrierter Chat pro Raum
  • Raum-Passwortschutz
  • Playback-Sync alle 2.5 Sekunden
  • Host/Member-Rollen
  • Auto-Cleanup nach 30s Inaktivitaet

Game Library (game-library)

  • Multi-Plattform Spielebibliothek (Steam + GOG)
  • Steam API Integration (Spielzeit-Tracking)
  • GOG OAuth2 Login Flow (mit Token-Refresh)
  • IGDB Game-Enrichment (Metadaten, Cover-Bilder)
  • Mehrere Benutzerprofile pro Instanz
  • Spiele-Caching mit Ablaufzeit

Notifications (notifications)

  • Discord Embed-Benachrichtigungen fuer andere Plugins
  • Kanal-Abonnement-Verwaltung pro Guild
  • Event-Filterung (stream_start, stream_end, etc.)
  • Konfigurierbare Ziel-Kanaele pro Event-Typ
  • Klickbare Stream-Links in Benachrichtigungen

Electron Desktop App

  • Native Windows-Anwendung (Squirrel.Windows Installer)
  • Automatische Updates via /downloads Endpoint
  • Integrierter Ad-Blocker (Request-Filter + Filterliste)
  • Screen Capture Picker (getDisplayMedia mit nativem Dialog)
  • GOG OAuth Redirect-Handling in Child Windows
  • Stream-Warnung beim Schliessen (wenn Broadcast aktiv)
  • Windows Toast Notifications
  • Custom User-Agent (GamingHubDesktop/{version})

Environment Variables

Erforderlich

Variable Beschreibung
DISCORD_TOKEN_JUKEBOX Discord Bot Token fuer Soundboard/Jukebox
DISCORD_TOKEN_RADIO Discord Bot Token fuer Radio
DISCORD_TOKEN_NOTIFICATIONS Discord Bot Token fuer Benachrichtigungen

Alle drei Bots muessen im Discord Developer Portal separat erstellt werden. Jeder braucht die Intents: GUILDS, GUILD_VOICE_STATES, GUILD_MEMBERS.

Optional

Variable Default Beschreibung
PORT 8080 HTTP Server Port
DATA_DIR /data Persistenter Speicher (State, Sounds)
ADMIN_PWD (leer) Admin-Passwort fuer geschuetzte Bereiche
ALLOWED_GUILD_IDS (leer) Komma-separierte Guild-IDs (Whitelist, leer = alle)
PUBLIC_URL (leer) Oeffentliche URL fuer Notification-Links (z.B. https://hub.example.de)
STEAM_API_KEY (leer) Steam Web API Key fuer Game Library
DISCORD_TOKEN (leer) Legacy Fallback fuer Jukebox

Soundboard-spezifisch

Variable Default Beschreibung
SOUNDS_DIR /data/sounds Verzeichnis fuer Sound-Dateien
NORMALIZE_ENABLE true Audio-Normalisierung aktivieren
NORMALIZE_I -16 LUFS Integrated Loudness
NORMALIZE_LRA 11 LUFS Loudness Range
NORMALIZE_TP -1.5 LUFS True Peak
NORM_CONCURRENCY 2 Parallele Normalisierungs-Threads
PCM_CACHE_MAX_MB 512 Max. PCM Memory Cache in MB

Build-Time (Vite)

Variable Default Beschreibung
VITE_APP_VERSION 1.0.0-dev Angezeigte Version im Frontend
VITE_BUILD_CHANNEL dev Release-Kanal (stable / nightly / dev)

Docker

Image bauen

docker build -t gaming-hub:latest .

Container starten

docker run -d \
  --name gaming-hub \
  --restart unless-stopped \
  -p 8080:8080 \
  -v gaming-hub-data:/data \
  -e DISCORD_TOKEN_JUKEBOX="dein-jukebox-token" \
  -e DISCORD_TOKEN_RADIO="dein-radio-token" \
  -e DISCORD_TOKEN_NOTIFICATIONS="dein-notifications-token" \
  -e ADMIN_PWD="dein-admin-passwort" \
  -e PUBLIC_URL="https://hub.example.de" \
  gaming-hub:latest

Docker Compose

version: "3.8"

services:
  gaming-hub:
    image: gaming-hub:latest
    container_name: gaming-hub
    restart: unless-stopped
    ports:
      - "8080:8080"
    volumes:
      - gaming-hub-data:/data
    environment:
      # Erforderlich
      - DISCORD_TOKEN_JUKEBOX=dein-jukebox-token
      - DISCORD_TOKEN_RADIO=dein-radio-token
      - DISCORD_TOKEN_NOTIFICATIONS=dein-notifications-token
      # Optional
      - ADMIN_PWD=dein-admin-passwort
      - PUBLIC_URL=https://hub.example.de
      - STEAM_API_KEY=dein-steam-api-key
      - ALLOWED_GUILD_IDS=
      # Soundboard Tuning
      - PCM_CACHE_MAX_MB=512
      - NORMALIZE_ENABLE=true

volumes:
  gaming-hub-data:

Unraid Docker Template

<?xml version="1.0"?>
<Container version="2">
  <Name>gaming-hub</Name>
  <Repository>192.168.1.100:5050/root/gaming-hub:latest</Repository>
  <Registry>http://192.168.1.100:9080/</Registry>
  <Network>bridge</Network>
  <Privileged>false</Privileged>
  <Support/>
  <Overview>Discord Gaming Hub - Soundboard, Radio, Streaming, LoL Stats, Watch Together, Game Library</Overview>
  <Category>MediaApp:Other</Category>
  <WebUI>http://[IP]:[PORT:8080]/</WebUI>
  <ExtraParams>--restart unless-stopped</ExtraParams>
  <Config Name="Web UI Port" Target="8080" Default="8080" Mode="tcp" Description="Web Dashboard Port" Type="Port" Display="always" Required="true" Mask="false">8080</Config>
  <Config Name="Data" Target="/data" Default="/mnt/user/appdata/gaming-hub" Mode="rw" Description="Persistenter Speicher" Type="Path" Display="always" Required="true" Mask="false">/mnt/user/appdata/gaming-hub</Config>
  <Config Name="Discord Token Jukebox" Target="DISCORD_TOKEN_JUKEBOX" Default="" Mode="" Description="Discord Bot Token fuer Soundboard" Type="Variable" Display="always" Required="true" Mask="true"/>
  <Config Name="Discord Token Radio" Target="DISCORD_TOKEN_RADIO" Default="" Mode="" Description="Discord Bot Token fuer Radio" Type="Variable" Display="always" Required="true" Mask="true"/>
  <Config Name="Discord Token Notifications" Target="DISCORD_TOKEN_NOTIFICATIONS" Default="" Mode="" Description="Discord Bot Token fuer Benachrichtigungen" Type="Variable" Display="always" Required="true" Mask="true"/>
  <Config Name="Admin Passwort" Target="ADMIN_PWD" Default="" Mode="" Description="Admin-Passwort" Type="Variable" Display="always" Required="false" Mask="true"/>
  <Config Name="Public URL" Target="PUBLIC_URL" Default="" Mode="" Description="Oeffentliche URL fuer Notification-Links" Type="Variable" Display="always" Required="false" Mask="false"/>
  <Config Name="Steam API Key" Target="STEAM_API_KEY" Default="" Mode="" Description="Steam Web API Key fuer Game Library" Type="Variable" Display="advanced" Required="false" Mask="true"/>
  <Config Name="Erlaubte Guild IDs" Target="ALLOWED_GUILD_IDS" Default="" Mode="" Description="Komma-separierte Guild-IDs (leer = alle)" Type="Variable" Display="advanced" Required="false" Mask="false"/>
  <Config Name="PCM Cache MB" Target="PCM_CACHE_MAX_MB" Default="512" Mode="" Description="Max. PCM Memory Cache in MB" Type="Variable" Display="advanced" Required="false" Mask="false">512</Config>
  <Config Name="Normalisierung" Target="NORMALIZE_ENABLE" Default="true" Mode="" Description="Audio-Normalisierung aktivieren" Type="Variable" Display="advanced" Required="false" Mask="false">true</Config>
  <Config Name="Sound-Verzeichnis" Target="SOUNDS_DIR" Default="/data/sounds" Mode="" Description="Sound-Dateien Pfad im Container" Type="Variable" Display="advanced" Required="false" Mask="false">/data/sounds</Config>
</Container>

Lokale Entwicklung

Voraussetzungen

  • Node.js 20+
  • FFmpeg im PATH
  • Drei Discord Bot Tokens

Setup

git clone http://192.168.1.100:9080/root/gaming-hub.git
cd gaming-hub

# Server Dependencies
cd server && npm install && cd ..

# Web Dependencies
cd web && npm install && cd ..

Dev Server starten

# Terminal 1: Backend
cd server
DISCORD_TOKEN_JUKEBOX="..." \
DISCORD_TOKEN_RADIO="..." \
DISCORD_TOKEN_NOTIFICATIONS="..." \
ADMIN_PWD="test" \
DATA_DIR="./data" \
npm run dev

# Terminal 2: Frontend (Proxy auf localhost:8080)
cd web
npm run dev

Backend laeuft auf http://localhost:8080, Frontend auf http://localhost:5173 (mit API-Proxy).

Electron Desktop App (Windows)

cd electron
npm install
npm start

Build fuer Distribution:

cd electron
npx electron-forge make

Erzeugt einen Squirrel.Windows Installer unter electron/out/make/.

Production Build

cd server && npm run build    # -> server/dist/
cd ../web && npm run build    # -> web/dist/

# Starten
cd ../server
NODE_ENV=production node dist/index.js

API Endpoints

Core

Method Pfad Beschreibung
GET /api/health Server-Status, Plugins, Bots, SSE-Clients
GET /api/plugins Plugin-Liste (Name, Version, Description)
GET /api/events SSE-Stream (Snapshot + Live-Updates)
POST /api/admin/login Admin-Login (Body: { password })

Radio Plugin

Method Pfad Beschreibung
GET /api/radio/places Alle Orte fuer den Globus
GET /api/radio/place/:id/channels Sender an einem Ort
GET /api/radio/search?q=... Sender/Orte suchen
GET /api/radio/guilds Verfuegbare Guilds + Voice Channels
POST /api/radio/play Stream starten
POST /api/radio/stop Stream stoppen
POST /api/radio/volume Lautstaerke setzen (0-1)
GET /api/radio/favorites Favoriten lesen
POST /api/radio/favorites Favorit togglen
GET /api/radio/status Aktueller Wiedergabestatus
GET /api/radio/tile/:z/:x/:y Tile-Proxy (Fallback Satellitenbild)

Soundboard Plugin

Method Pfad Beschreibung
GET /api/soundboard/channels Voice Channels aller Guilds
GET /api/soundboard/sounds Sound-Liste (mit Filter/Suche)
POST /api/soundboard/play Sound abspielen
POST /api/soundboard/stop Wiedergabe stoppen
POST /api/soundboard/volume Lautstaerke setzen
POST /api/soundboard/upload Sound hochladen (Multipart)

Streaming Plugin

Method Pfad Beschreibung
WebSocket /ws Signaling (offer, answer, ice, viewer_joined, stream_ended)

Watch Together Plugin

Method Pfad Beschreibung
WebSocket /ws Raum-Sync (create, join, queue, vote, chat, playback)

Game Library Plugin

Method Pfad Beschreibung
GET /api/game-library/profiles Benutzerprofile
POST /api/game-library/profiles Profil erstellen/aktualisieren
GET /api/game-library/games Spieleliste (Steam + GOG)
POST /api/game-library/gog/exchange GOG OAuth Code Exchange

Notifications Plugin

Method Pfad Beschreibung
GET /api/notifications/config Kanal-Konfiguration lesen
POST /api/notifications/config Kanal-Konfiguration speichern

CI/CD Pipeline

GitLab CI mit Kaniko (.gitlab-ci.yml):

Stage Job Beschreibung
build docker-build Kaniko Multi-Platform Image Build
deploy deploy Docker Pull + Run auf adriahub
deploy electron-build Squirrel.Windows Installer + .nupkg + .exe
bump-version bump-version PATCH-Version in VERSION auto-inkrementieren
Branch Tags Version Channel
main latest, main 1.8.0 stable
nightly nightly x.y.z-nightly nightly
andere branch-name x.y.z-dev dev

Registry: 192.168.1.100:5050/root/gaming-hub

SSE Event Types

Alle Clients empfangen Events ueber GET /api/events:

Event Type Plugin Beschreibung
snapshot - Initialer Gesamtstatus beim Connect
radio radio Wiedergabestatus (playing/stopped)
radio_volume radio Lautstaerkeaenderung
radio_voicestats radio Voice-Ping, Gateway-Ping, Status, Uptime
radio_favorites radio Favoriten-Update
soundboard_voicestats soundboard Voice-Verbindungsdetails
soundboard_nowplaying soundboard Aktuell gespielter Sound
soundboard_volume soundboard Lautstaerkeaenderung
soundboard_channel soundboard Channel-Wechsel
soundboard_party soundboard Party-Modus Status

Discord Bot Setup

  1. Discord Developer Portal oeffnen
  2. Drei Applications erstellen (z.B. "Jukebox Bot", "Radio Bot", "Notifications Bot")
  3. Fuer jede Application:
    • Bot erstellen unter "Bot"
    • Token kopieren
    • Privileged Gateway Intents aktivieren:
      • Server Members Intent
      • Message Content Intent (optional)
    • Unter "OAuth2 > URL Generator":
      • Scopes: bot
      • Bot Permissions: Connect, Speak, Use Voice Activity, Send Messages, Embed Links
    • Generierte URL im Browser oeffnen, Bot zum Server einladen
  4. Tokens als DISCORD_TOKEN_JUKEBOX, DISCORD_TOKEN_RADIO und DISCORD_TOKEN_NOTIFICATIONS setzen

Persistenz

Alle Daten werden im DATA_DIR (/data) gespeichert:

/data/
├── sounds/
│   ├── hub-state.json  # Plugin-State (Volumes, Favorites, Channels, Profiles, ...)
│   ├── sound1.mp3
│   ├── subfolder/
│   │   └── sound2.wav
│   └── ...

State wird automatisch bei Aenderungen geschrieben (Atomic Writes mit .tmp + .bak Rotation) und beim Start geladen.

Dockerfile (Multi-Stage)

4 Build-Stages:

  1. web-build - React/Vite Frontend kompilieren
  2. server-deps - npm install + native Build-Tools (python3, make, g++)
  3. server-build - TypeScript Backend kompilieren + Dev-Dependencies entfernen
  4. runtime - Finales Image (node:24-slim) mit FFmpeg + kompiliertem Code

Finales Image enthaelt nur Production Dependencies, kein TypeScript/Dev-Tooling.

Streaming Qualitaets-Presets

Der Streamer kann vor dem Broadcast ein Preset waehlen:

Preset Aufloesung FPS Bitrate
720p30 1280x720 30 2.5 Mbit/s
1080p30 1920x1080 30 5 Mbit/s
1080p60 1920x1080 60 8 Mbit/s
1440p60 2560x1440 60 14 Mbit/s
4K60 3840x2160 60 25 Mbit/s
4K165 Ultra 3840x2160 165 50 Mbit/s

Standard: 1080p60. Das Dropdown ist waehrend eines aktiven Broadcasts deaktiviert.