jukebox-vibe/README.md
2026-03-05 11:13:03 +01:00

222 lines
7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 <datei>` | Entrance-Sound setzen |
| `?entrance remove` | Entrance-Sound entfernen |
| `?exit <datei>` | 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 | `:<branch-name>`, `:sha` |
Registry: `git.daddelolymp.de/root/jukebox-vibe`
## Lizenz
MIT