# Jukebox Vibe – Discord Soundboard Self-hosted Discord Soundboard mit Web-UI. Spielt Sounds in Discord Voice Channels, verwaltet per Browser. Dockerized, ein Container, fertig. ## Tech Stack | Komponente | Technologie | |---|---| | **Backend** | Node.js 20, Express, TypeScript, discord.js 14 | | **Voice** | @discordjs/voice 0.19, @discordjs/opus, DAVE E2EE (@snazzah/davey) | | **Frontend** | React 18, Vite, TypeScript, Custom CSS | | **Audio** | ffmpeg (EBU R128 Loudnorm), yt-dlp | | **Deployment** | Multi-Stage Dockerfile, GitLab CI/CD (Kaniko) | ## Features ### Soundboard - **MP3/WAV Playback** in Discord Voice Channels - **Loudness Normalization** (EBU R128) mit PCM-Cache fuer Instant-Playback - **Per-Guild Volume** (0-100%), live adjustable, persistiert - **Party Mode** – zufaellige Sounds alle 30-90 Sekunden - **Stop/Panic** – sofortiger Playback-Stop fuer alle ### Discord Bot - **Entrance Sounds** – persoenlicher Sound beim Channel-Join - **Exit Sounds** – Sound beim Disconnect (nicht bei Channel-Wechsel) - **DM Upload** – Sounds per Direktnachricht an den Bot hochladen - **Voice Resilience** – 3-Tier Reconnect mit Exponential Backoff ### Web-UI - **Sound Grid** mit klickbaren Cards - **Suche** mit optionalem Fuzzy-Matching - **Ordner-Filter** mit farbigen Chips - **Favoriten** (Cookie-basiert) - **Kategorien** und **Badges** (Admin-verwaltet) - **Channel-Selector** gruppiert nach Guild - **Now Playing** Anzeige mit Wellenform-Animation - **5 Themes** – Discord, Midnight, Forest, Sunset, Ocean - **Card-Size Slider** (80-160px) - **Drag & Drop Upload** (Admin) - **MP3-URL Import** – direkter Download und Playback - **Real-Time Sync** via Server-Sent Events (SSE) ### Admin - **Login** mit HMAC-SHA256 Token (HttpOnly Cookie, 7 Tage) - **Bulk Delete / Rename** von Sounds - **Upload** bis zu 20 Dateien (je max. 50MB) - **Kategorien** erstellen, bearbeiten, loeschen, zuweisen - **Custom Badges** zuweisen/entfernen ## Quickstart ### Voraussetzungen - Docker - Discord Bot Token mit Intents: `Guilds`, `GuildVoiceStates`, `GuildMembers`, `DirectMessages`, `MessageContent` ### Setup ```bash git clone https://git.daddelolymp.de/root/jukebox-vibe.git cd jukebox-vibe cp .env.example .env # .env anpassen (DISCORD_TOKEN, ADMIN_PWD) docker compose up -d ``` ### Docker Run (ohne Compose) ```bash docker run -d \ --name jukebox \ -p 8199:8080 \ -e DISCORD_TOKEN=dein_token \ -e ADMIN_PWD=dein_passwort \ -v $(pwd)/sounds:/data/sounds \ --restart unless-stopped \ git.daddelolymp.de/root/jukebox-vibe:latest ``` ## Konfiguration | Variable | Default | Beschreibung | |---|---|---| | `DISCORD_TOKEN` | *erforderlich* | Discord Bot Token | | `ADMIN_PWD` | `''` | Admin-Passwort fuer Web-UI | | `PORT` | `8080` | Server Port | | `SOUNDS_DIR` | `/data/sounds` | Sound-Verzeichnis (Docker Volume) | | `ALLOWED_GUILD_IDS` | `''` | Komma-getrennte Guild-IDs (leer = alle) | | `NORMALIZE_ENABLE` | `true` | Loudness Normalization an/aus | | `NORMALIZE_I` | `-16` | Ziel-Lautstaerke in LUFS | | `NORMALIZE_LRA` | `11` | Loudness Range | | `NORMALIZE_TP` | `-1.5` | True Peak in dBTP | | `NORM_CONCURRENCY` | `2` | Parallele ffmpeg-Prozesse | ## Bot Commands Alle Commands per DM an den Bot oder im Server-Chat: | Command | Beschreibung | |---|---| | `?help` | Hilfe anzeigen | | `?list` | Alle Sounds auflisten | | `?entrance ` | Entrance-Sound setzen | | `?entrance remove` | Entrance-Sound entfernen | | `?exit ` | Exit-Sound setzen | | `?exit remove` | Exit-Sound entfernen | **Upload via DM:** MP3/WAV als Anhang an den Bot senden – wird automatisch gespeichert und normalisiert. ## API ### Public ``` GET /api/health Healthcheck + Stats GET /api/sounds Sound-Liste (query: q, folder, categoryId, fuzzy) GET /api/analytics Top 10 Most Played, Gesamt-Plays GET /api/channels Verfuegbare Voice Channels GET /api/selected-channels Gespeicherte Channel-Auswahl POST /api/selected-channel Channel-Auswahl setzen POST /api/play Sound abspielen (body: soundName, guildId, channelId) POST /api/play-url MP3-URL downloaden und abspielen POST /api/stop Playback stoppen GET /api/volume Volume abfragen POST /api/volume Volume setzen (0-1) POST /api/party/start Party Mode starten POST /api/party/stop Party Mode stoppen GET /api/events SSE Stream (Real-Time Updates) ``` ### Admin (Cookie-Auth) ``` POST /api/admin/login Login (body: password) POST /api/admin/logout Logout GET /api/admin/status Auth-Status pruefen POST /api/upload Dateien hochladen (multipart, max 20x50MB) POST /api/admin/sounds/delete Sounds loeschen (body: paths[]) POST /api/admin/sounds/rename Sound umbenennen GET /api/categories Kategorien auflisten POST /api/categories Kategorie erstellen PATCH /api/categories/:id Kategorie bearbeiten DELETE /api/categories/:id Kategorie loeschen POST /api/categories/assign Kategorien zuweisen POST /api/badges/assign Badges zuweisen POST /api/badges/clear Badges entfernen ``` ## Sound-Dateien ``` /data/sounds/ state.json # Persistierter State (Volumes, Plays, Kategorien, etc.) .norm-cache/ # Normalisierte PCM-Caches airhorn.mp3 # Sounds im Root memes/ # Ordner-Struktur (1 Ebene) bruh.mp3 oof.wav ``` - Formate: `.mp3`, `.wav` - Ordner werden als Filter-Chips im Frontend angezeigt - `.norm-cache/` wird automatisch verwaltet (Cache-Invalidierung bei Datei-Aenderung) ## Loudness Normalization Alle Sounds werden per ffmpeg `loudnorm` (EBU R128) normalisiert: 1. **Startup:** Hintergrund-Sync normalisiert alle uncached Sounds 2. **Cache Hit:** Gecachte PCM-Datei wird direkt gestreamt (kein ffmpeg, instant) 3. **Cache Miss:** ffmpeg streamt live zum Player UND schreibt gleichzeitig in Cache 4. **Upload:** Neue Dateien werden sofort im Hintergrund normalisiert ## Voice Connection 3-stufiges Recovery bei Verbindungsproblemen: 1. **Wait for Ready** (15s Timeout) 2. **Rejoin** im selben Channel (15s Timeout) 3. **Destroy + Fresh Join** (15s Timeout) Lifecycle-Handler mit: - Max 3 Reconnect-Versuche mit Exponential Backoff - Anti-Reentrancy Guard gegen Endlosschleifen - Automatisches State-Cleanup bei totalem Verbindungsverlust ## Projektstruktur ``` jukebox-vibe/ server/ src/index.ts # Server + Discord Bot (Hauptdatei) package.json tsconfig.json web/ src/ App.tsx # React SPA styles.css # Themes + Layout types.ts # TypeScript Types package.json vite.config.ts Dockerfile # Multi-Stage Build (web + server + runtime) docker-compose.yml .gitlab-ci.yml # CI/CD Pipeline (Kaniko) .env.example ``` ## CI/CD GitLab CI baut automatisch bei jedem Push: | Branch | Image Tag | |---|---| | `main` | `:main`, `:latest`, `:sha` | | `nightly` | `:nightly`, `:sha` | | andere | `:`, `:sha` | Registry: `git.daddelolymp.de/root/jukebox-vibe` ## Lizenz MIT