diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 3a3bd10..3a25324 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -29,13 +29,13 @@ jobs: run: | if [[ "${{ github.ref_name }}" == "main" ]]; then echo "tag=main" >> $GITHUB_OUTPUT - echo "version=1.0.0" >> $GITHUB_OUTPUT + echo "version=1.1.0" >> $GITHUB_OUTPUT echo "channel=stable" >> $GITHUB_OUTPUT else # Ersetze Slashes durch Bindestriche für gültige Docker Tags CLEAN_TAG=$(echo "${{ github.ref_name }}" | sed 's/\//-/g') echo "tag=$CLEAN_TAG" >> $GITHUB_OUTPUT - echo "version=1.0.0-nightly" >> $GITHUB_OUTPUT + echo "version=1.1.0-nightly" >> $GITHUB_OUTPUT echo "channel=nightly" >> $GITHUB_OUTPUT fi diff --git a/Dockerfile b/Dockerfile index 7365c69..91f8191 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ RUN npm install --no-audit --no-fund COPY web/ . # Umgebungsvariable für React Build verfügbar machen (Vite liest nur VITE_*) ARG VITE_BUILD_CHANNEL=stable -ARG VITE_APP_VERSION=1.0.0 +ARG VITE_APP_VERSION=1.1.0 ENV VITE_BUILD_CHANNEL=$VITE_BUILD_CHANNEL ENV VITE_APP_VERSION=$VITE_APP_VERSION RUN npm run build diff --git a/FEATURE_BRANCH.md b/FEATURE_BRANCH.md index bb5474f..e4c0d47 100644 --- a/FEATURE_BRANCH.md +++ b/FEATURE_BRANCH.md @@ -35,6 +35,11 @@ git push origin main git branch -d feature/mein-experiment ``` +## Versionierung & Changelog +- Versionen werden in `README.md` (Badge) gepflegt +- Änderungen dokumentieren wir in `CHANGELOG.md` +- Nightly-Entwicklung: Features zuerst im Branch `feature/nightly`, Merge nach `main` für Release + ## Docker Images - `:latest` - Hauptversion (main branch) - `:feature-nightly` - Feature Version diff --git a/README.md b/README.md index 3301e76..bf9376e 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,59 @@ -# 🎵 Jukebox 420 - Discord Soundboard v1.0.0 +# Jukebox 420 – Discord Soundboard (v1.1.1) -Ein modernes, feature-reiches Discord Soundboard mit Web-Frontend, Discord-Bot und Docker-Deployment. Perfekt für Gaming-Communities, Streamer und Discord-Server. +A modern, self‑hosted Discord soundboard with a slick web UI and a Discord bot that plays sounds into your voice channels. Easy to run via Docker, fun to use with friends. - +   ## ✨ Features -### 🎮 **Kern-Funktionen** -- **Web-Frontend** mit modernem UI und 3 Themes (Dark, Rainbow, 420) -- **Discord-Bot** für Voice-Channel Integration -- **Sound-Management** mit Ordner-Unterstützung -- **Live-Uhrzeit** (Berlin Timezone) -- **Volume Control** pro Server -- **Favoriten-System** mit Cookie-Persistenz +- Web UI (Vite + React + TypeScript), 3 themes (Dark, Rainbow, 420) +- Discord bot (discord.js + @discordjs/voice) +- MP3 & WAV playback, ffmpeg normalization +- Favorites, search, folders view (auto counters) +- Live counters and a clean header/footer +- Admin area: bulk delete, inline rename, categories (CRUD) + bulk assign, remove custom badges +- Partymode: server‑side random playback every 30–90 seconds, globally synced via SSE; Panic stops for everyone +- Persistent state: volumes, plays, totalPlays, categories, badges in `/data/sounds/state.json` -### 🎨 **UI/UX Features** -- **3 Themes**: Dark, Rainbow, 420 (Cannabis/Trippy) -- **Responsive Design** für Desktop & Mobile -- **Glassmorphism-Effekte** mit Backdrop-Blur -- **Animierte Hintergründe** (Rainbow & 420 Theme) -- **Live-Zähler** für Sounds und Abspielungen +## 🚀 Quick start -### 🔧 **Admin-Funktionen** -- **Admin-Login** (Passwort-basiert) -- **Bulk-Delete** für mehrere Sounds -- **Sound-Umbenennen** mit Inline-Editor -- **Checkbox-Auswahl** für Massenoperationen - -### 🎵 **Audio-Features** -- **MP3 & WAV Support** für Uploads und Playback -- **Audio-Normalisierung** (Loudnorm) -- **URL-Download** für MP3/WAV Links -- **Random-Play** für zufällige Sounds -- **Panic-Button** zum sofortigen Stoppen - -### 📁 **Organisation** -- **Ordner-Unterstützung** mit Tab-Navigation -- **Favoriten-Tab** für gespeicherte Sounds -- **Neu-Tab** für die letzten 10 Uploads -- **Most Played** für Top 3 Sounds -- **Suchfunktion** für alle Sounds - -## 🚀 Quick Start - -### 1. Voraussetzungen -- **Docker & Docker Compose** -- **Discord Bot Token** mit folgenden Intents: - - `Guilds` - - `GuildVoiceStates` - - `DirectMessages` - - `MessageContent` +### 1. Requirements +- Docker & Docker Compose +- Discord bot token with intents: `Guilds`, `GuildVoiceStates`, `DirectMessages` ### 2. Setup ```bash -# Repository klonen +# Clone repository git clone https://github.com/flex420/jukebox-vibe.git cd jukebox-vibe -# .env Datei erstellen +# Create .env cp .env.example .env ``` -### 3. Konfiguration +### 3. Configuration ```env -# .env Datei bearbeiten -DISCORD_TOKEN=dein_discord_bot_token_hier +# Edit the .env file +DISCORD_TOKEN=your_discord_bot_token_here +ADMIN_PWD=choose-a-strong-password PORT=8080 SOUNDS_DIR=/data/sounds -# Optional: Bestimmte Server erlauben +# Optionally restrict allowed guilds ALLOWED_GUILD_IDS=GUILD_ID_1,GUILD_ID_2 - -# Optional: Audio-Normalisierung -NORMALIZE_AUDIO=true -NORMALIZE_TARGET=-14 -NORMALIZE_THRESHOLD=-70 ``` ### 4. Deployment ```bash -# Container starten +# Start container docker compose up --build -d -# Logs anzeigen +# Logs docker compose logs -f -# Status prüfen +# Status docker compose ps ``` @@ -204,6 +170,12 @@ docker pull flex420/jukebox-vibe:latest docker run -d --name jukebox-420 -p 8199:8080 --env-file .env -v $(pwd)/data/sounds:/data/sounds flex420/jukebox-vibe:latest ``` +## 🔒 SSL/HTTPS Hinweis (wichtig für Discord) + +- Das Web-Frontend MUSS hinter HTTPS (SSL) ausgeliefert werden. Empfohlen ist ein Domain‑Mapping (Reverse Proxy) mit gültigem Zertifikat (z. B. Traefik, Nginx, Caddy, Cloudflare). +- Hintergrund: Ohne TLS kann es zu Verschlüsselungs-/Encrypt‑Fehlern kommen, und Audio wird in Discord nicht korrekt wiedergegeben. +- Praxis: Richte eine Domain wie `https://soundboard.deinedomain.tld` auf das Frontend ein und aktiviere SSL (Let’s Encrypt). Danach sollten Uploads/Playback stabil funktionieren. + ## 📁 Projekt-Struktur ``` diff --git a/docker-compose.feature.yml b/docker-compose.feature.yml index e5a0560..7f242fa 100644 --- a/docker-compose.feature.yml +++ b/docker-compose.feature.yml @@ -13,7 +13,7 @@ services: - GUILD_ID=${GUILD_ID} - ADMIN_PWD=${ADMIN_PWD} - VITE_BUILD_CHANNEL=nightly - - VITE_APP_VERSION=1.0.0-nightly + - VITE_APP_VERSION=1.1.1-nightly volumes: - ./data/sounds:/data/sounds - ./data/uploads:/data/uploads diff --git a/docker-compose.yml b/docker-compose.yml index fceeca2..e412838 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: - .env environment: - VITE_BUILD_CHANNEL=stable - - VITE_APP_VERSION=1.0.0 + - VITE_APP_VERSION=1.1.1 volumes: - ./data/sounds:/data/sounds restart: unless-stopped diff --git a/package.json b/package.json index 96fd141..2f01d4b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jukebox-vibe", - "version": "1.0.0", + "version": "1.1.1", "description": "Discord Soundboard mit Web-Interface", "private": true, "scripts": { diff --git a/server/package.json b/server/package.json index 6fbe126..9066851 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "discord-soundboard-server", - "version": "0.1.0", + "version": "1.1.1", "private": true, "type": "module", "main": "dist/index.js", diff --git a/server/src/index.ts b/server/src/index.ts index 90da983..99d67ad 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -941,6 +941,8 @@ app.post('/api/volume', (req: Request, res: Response) => { // Kein aktiver Player: nur persistieren für nächste Wiedergabe persistedState.volumes[guildId] = safeVolume; writePersistedState(persistedState); + // Broadcast neue Lautstärke an alle Clients + sseBroadcast({ type: 'volume', guildId, volume: safeVolume }); return res.json({ ok: true, volume: safeVolume, persistedOnly: true }); } state.currentVolume = safeVolume; @@ -950,6 +952,8 @@ app.post('/api/volume', (req: Request, res: Response) => { } persistedState.volumes[guildId] = safeVolume; writePersistedState(persistedState); + // Broadcast neue Lautstärke an alle Clients + sseBroadcast({ type: 'volume', guildId, volume: safeVolume }); return res.json({ ok: true, volume: safeVolume }); } catch (e: any) { console.error('Volume-Fehler:', e); @@ -1075,7 +1079,7 @@ app.get('/api/events', (req: Request, res: Response) => { // Snapshot senden try { - res.write(`data: ${JSON.stringify({ type: 'snapshot', party: Array.from(partyActive), selected: persistedState.selectedChannels ?? {} })}\n\n`); + res.write(`data: ${JSON.stringify({ type: 'snapshot', party: Array.from(partyActive), selected: persistedState.selectedChannels ?? {}, volumes: persistedState.volumes ?? {} })}\n\n`); } catch {} // Ping, damit Proxies die Verbindung offen halten diff --git a/web/package.json b/web/package.json index 6b3a4ef..14fba7c 100644 --- a/web/package.json +++ b/web/package.json @@ -1,7 +1,7 @@ { "name": "discord-soundboard-web", "private": true, - "version": "0.1.0", + "version": "1.1.1", "type": "module", "scripts": { "dev": "vite", diff --git a/web/src/App.tsx b/web/src/App.tsx index b58ef7f..db5dfa7 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -106,6 +106,15 @@ export default function App() { setSelected(newVal); } } catch {} + try { + const vols = msg?.volumes || {}; + const cur = selectedRef.current || ''; + const gid = cur ? cur.split(':')[0] : ''; + if (gid && typeof vols[gid] === 'number') { + const v = vols[gid]; + setVolume(v); + } + } catch {} } else if (msg?.type === 'channel') { try { const gid = msg.guildId; @@ -116,6 +125,16 @@ export default function App() { if (curGid === gid) setSelected(`${gid}:${cid}`); } } catch {} + } else if (msg?.type === 'volume') { + try { + const gid = msg.guildId; + const v = msg.volume; + const cur = selectedRef.current || ''; + const curGid = cur ? cur.split(':')[0] : ''; + if (gid && curGid === gid && typeof v === 'number') { + setVolume(v); + } + } catch {} } }); return () => { try { unsub(); } catch {} }; @@ -327,8 +346,8 @@ export default function App() {