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>
- Radio: Move controls from bottom bar to topbar above globe
(guild/channel selectors, now playing, volume, connection, stop)
- Radio: Theme selector moved inline into topbar-right
- Radio: Globe now fills remaining space below topbar
- Soundboard: Fix connection modal not opening when voiceStats is null
(modal now renders with '---' values when no voice data available)
- Both: Modal condition changed from `showConnModal && voiceStats` to
just `showConnModal`, handling null voiceStats gracefully
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>