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
- Discord Developer Portal oeffnen
- Drei Applications erstellen (z.B. "Jukebox Bot", "Radio Bot", "Notifications Bot")
- 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
- 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:
- web-build - React/Vite Frontend kompilieren
- server-deps - npm install + native Build-Tools (python3, make, g++)
- server-build - TypeScript Backend kompilieren + Dev-Dependencies entfernen
- 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.