- MP3/WAV per Drag & Drop ablegen öffnet jetzt ein Rename-Modal
- Jede Datei einzeln benennen vor dem Upload (sequentiell bei mehreren)
- Server-Upload-Endpoint unterstützt optionalen customName Parameter
- Reuse der bestehenden dl-modal CSS-Klassen für konsistentes Design
- Überspringen-Option bei mehreren Dateien
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Every step now logged with timestamps, exit codes, stdout/stderr
streaming in real-time. yt-dlp runs with --verbose flag. Routes log
URL type detection, download progress, normalization, play status.
Error messages include HTTP status codes and specific yt-dlp errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
yt-dlp extracts audio as MP3 from YouTube and Instagram links.
Direct MP3 links continue to work as before. URL input field now shows
a type indicator (YT/IG/MP3) and validates all three formats.
Backend: downloadWithYtDlp() spawns yt-dlp with --extract-audio,
saves to SOUNDS_DIR, normalizes if enabled. New /download-url route
for save-only without auto-play. play-url route extended for all types.
Frontend: isSupportedUrl() validates YouTube/Instagram/MP3, dynamic
icon changes per URL type, disabled state when URL is unsupported.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add voice channel member count (non-bot users) to soundboard
channel API response and display it in the dropdown, matching
the radio plugin's existing behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each plugin now uses its own @discordjs/voice group:
- Radio: group='radio'
- Soundboard: group='soundboard'
This prevents joinVoiceChannel from one bot overwriting the
other bot's connection. Both bots can now play simultaneously
in the same voice channel. Removed claimVoice system (not needed
with separate bots).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Plugins now claim voice per guild via claimVoice(). When soundboard
plays a sound, radio's cleanup runs automatically (kills ffmpeg,
broadcasts SSE stop event). Fixes stale "now playing" UI on tab switch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Listen for state transitions and errors immediately after joinVoiceChannel,
not just after ensureConnectionReady succeeds. This will show if the
connection transitions at all internally or stays stuck at signalling.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previous wrapper intercepted wrong methods (library→adapter vs adapter→library).
Now correctly wraps:
- sendPayload (adapter→gateway): logs op code and return value
- onVoiceServerUpdate/onVoiceStateUpdate (gateway→library): logs incoming events
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Logs sendPayload calls (op code, result), onVoiceServerUpdate
and onVoiceStateUpdate to identify why connection stays at signalling.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Log voice state transitions (Signalling → Connecting → Ready etc.)
- Log play requests with sound name, guild, channel, file path
- Log connection creation, rejoin attempts, and failures
- Log AudioPlayer state changes and errors
- All prefixed with [Soundboard] for easy filtering
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- await sodium.ready + nacl preload (same as original jukebox)
- Add generateDependencyReport() for debugging
- Add type declarations for libsodium-wrappers and tweetnacl
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>