A self-hosted Discord music bot powered by yt-dlp with slash commands and Docker support.
- Multi-Platform — YouTube, SoundCloud, Bandcamp, Twitch, Vimeo and all yt-dlp sites
- Search & Select —
/play <query>shows 10 results,/select <nr>picks one - Playlist Support — YouTube playlists with background downloading and progress display
- Now Playing UI — Interactive embed with ⏮️⏯️⏭️🔉🔊 buttons
- Audio Cache — LRU file cache with configurable size, persisted to disk
- Repeat & Shuffle — Song loop, queue loop, shuffle mode
- Rate Limiting — 10 downloads/user/minute
- Graceful Shutdown — Clean voice disconnects on container stop
- Go to Discord Developer Portal → New Application
- Create a Bot → copy the token
- OAuth2 → URL Generator: Scopes
bot+applications.commands, Permissions:Connect,Speak,Send Messages - Invite the bot to your server
cp .env.example .envEdit .env — at minimum set TOKEN:
TOKEN=your_bot_token
MAX_CACHE=200
DOWNLOAD_TIMEOUT_SEC=120
LOG_LEVEL=info
DOWNLOAD_HOST_PATH=./downloadsdocker compose up -d --buildView logs:
docker compose logs -f musicbotyt-dlp is automatically updated on every container start and checked every 6 hours.
| Command | Description |
|---|---|
/play <query/url> |
Play a song, playlist or start a search |
/select <1-10> |
Pick a search result |
/pause |
Pause playback |
/resume |
Resume playback |
/skip |
Skip current song |
/stop |
Stop playback and clear queue |
/queue |
Show current queue |
/volume <0-100> |
Set volume |
/shuffle |
Toggle shuffle mode |
/repeatsingle |
Repeat current song |
/repeat |
Repeat entire queue |
/playcache |
Play all cached songs |
/leave |
Disconnect bot from voice |
/debug |
Show debug info |
/clearcache |
Clear audio cache (Admin) |
/refresh |
Re-register slash commands (Admin) |
src/
├── index.js # Entry point, slash commands, events
├── commands/
│ └── commandHandlers.js # All command handlers
├── queue/
│ └── QueueManager.js # Queue & playback (ffmpeg PCM buffering)
├── download/
│ ├── ytdlp.js # yt-dlp wrapper
│ ├── BackgroundDownloader.js
│ ├── ProgressManager.js
│ └── RateLimiter.js
├── cache/
│ ├── AudioCache.js # LRU file cache
│ └── SearchCache.js
├── voice/
│ └── VoiceManager.js # Voice join with retry
├── utils/
│ ├── validation.js # URL/input security
│ ├── urlCleaner.js # YouTube URL parsing
│ ├── formatting.js
│ └── logger.js # Winston logger
└── config/
└── constants.js # All configuration values
- URL validation against SSRF (localhost, private IPs,
file://) - Shell injection prevented (
shell: falseon all spawns) - Input sanitization for all user inputs
- Per-user rate limiting
- yt-dlp runs with
nice -n 19(low CPU priority)
| Variable | Default | Description |
|---|---|---|
TOKEN |
— | Discord bot token (required) |
MAX_CACHE |
200 |
Max number of cached audio files |
DOWNLOAD_TIMEOUT_SEC |
120 |
Download timeout in seconds |
SEARCH_TIMEOUT_SEC |
30 |
Search timeout in seconds |
LOG_LEVEL |
info |
Log level (debug, info, warn, error) |
DOWNLOAD_HOST_PATH |
./downloads |
Host path for audio cache |
LOGS_HOST_PATH |
./logs |
Host path for log files |
MIT