Skip to content

mcbisken/discodj

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

14 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

discodj ๐ŸŽถ

discodj is a self-hosted Discord music bot built with discord.js v14 and @discordjs/voice, powered by yt-dlp, ffmpeg, and Node.js. It plays audio from YouTube, SoundCloud, and Spotify, manages paginated queues with ETAs, supports saved playlists, audio filters, and runs cleanly in Docker.


โœจ Features

๐ŸŽต Audio Sources

  • YouTube โ€” search by keyword or paste any YouTube URL (videos, playlists, Shorts, embeds, youtu.be links)
  • SoundCloud โ€” paste any SoundCloud track, set, or artist URL
  • Spotify โ€” paste track, album, or playlist URLs; the bot maps each item to YouTube and queues lazily (albums/playlists appear instantly without waiting for all lookups to complete)

๐ŸŽ› Audio Filters

Apply FFmpeg filters with /filter:

Filter Effect
Bass Boost Boosts low-end EQ around 40 Hz
Nightcore Speeds up + raises pitch by 1.25ร—
Vaporwave Slows down + lowers pitch to 0.8ร—
8D Audio Rotating stereo panning
Echo Classic echo/delay
Karaoke Attempts to cancel centred vocals
Treble Boost Boosts high frequencies

Changing a filter while a track is playing immediately restarts it from the same timestamp with the new filter applied. The active filter is displayed in the Now Playing embed.

๐Ÿ“‹ Queue

  • Paginated "Up next" embed โ€” 8 tracks per page with โ—€ Prev / Next โ–ถ buttons
  • Estimated wait time shown per track (e.g. in 4:32)
  • Total queue size displayed as an inline field
  • Autocomplete on /jump, /remove, and /move โ€” type a number or part of a song title

๐Ÿ’พ Saved Playlists

  • /playlist save <name> โ€” snapshot the current queue (including now-playing) as a named playlist
  • /playlist load <name> โ€” append a saved playlist to the queue; starts playing if idle
  • /playlist delete <name> โ€” remove a saved playlist
  • /playlist list โ€” show all saved playlists with track count and save date
  • Load/delete have autocomplete โ€” your saved playlists appear as you type

๐Ÿ’ฌ Now Playing Panel

  • Thumbnail, track title, progress bar (12 slots), elapsed/total time
  • Inline fields: Requested by, Duration, Volume (with active filter label), Loop, Autoplay, Queue count
  • Button controls: โฎ Prev ยท โธ Pause/โ–ถ Resume ยท โญ Skip ยท โน Stop
  • Panel auto-refreshes every 10 seconds while playing
  • Single panel per guild โ€” edits in place rather than spamming new messages

๐Ÿง  Smart UX

  • Deduplication warning โ€” if a track is already in the queue, you get a confirmation prompt ("Add anyway" / "Cancel") before it's queued again
  • Autocomplete on /play โ€” YouTube search results appear as you type
  • Auto-deletes transient "Queued" / "Playing" messages after 10 seconds
  • Auto-leaves voice when channel is empty (3-second debounce so mobile reconnects don't trigger it)
  • Presence shows the currently playing song title

๐Ÿ”’ DJ Mode

Enable with /djonly on. Restricts play/skip/stop/seek/volume/queue edits to:

  • Server admins, Manage Guild, or Manage Channels permission holders
  • Optionally: a specific role configured via DJ_ROLE_ID in .env

๐Ÿ”ง Reliability

  • yt-dlp auto-updates on every startup and again every 24 hours โ€” stale yt-dlp is the #1 cause of playback failures
  • YouTube CDN audio URLs cached for 90 minutes
  • Per-guild mutex prevents race conditions when commands or buttons fire simultaneously
  • Playback error recovery โ€” skips bad tracks and retries up to 5 times before stopping
  • Graceful shutdown flushes all guild state on SIGINT/SIGTERM

๐Ÿณ Docker

  • Lightweight Alpine image with ffmpeg and yt-dlp preinstalled
  • State and playlists persist across container restarts via a named volume
  • Structured JSON logs โ€” clean output for docker compose logs or any log aggregator

๐Ÿงฉ Requirements

For All Setups

  • A Discord bot token (Discord Developer Portal)
  • Bot permissions in your server:
    • Text: Send Messages, Embed Links, Read Message History
    • Voice: Connect, Speak
  • OAuth2 scopes: bot + applications.commands

For Docker (Recommended)

  • Docker Engine and Docker Compose

For Local (Node.js)

  • Node.js v22.12.0 or higher
  • ffmpeg and yt-dlp installed and available in PATH
  • Python 3 + build tools (for compiling native Opus bindings)

โš™๏ธ Configuration

Copy .env.example to .env and fill in your values:

DISCORD_TOKEN=your_bot_token_here
GUILD_ID=your_guild_id_here
DJ_ROLE_ID=optional_role_id_for_dj_mode
Variable Required Description
DISCORD_TOKEN โœ… Your bot token from the Discord Developer Portal
GUILD_ID Optional Guild ID for instant slash command registration. If omitted, commands register globally (up to 1 hour delay)
DJ_ROLE_ID Optional Role ID that grants DJ access when /djonly on is active

๐Ÿš€ Running with Docker (Recommended)

# 1. Copy and fill in your .env
cp .env.example .env

# 2. Build the image
docker compose build --no-cache

# 3. Start the bot
docker compose up -d

# 4. Follow logs
docker compose logs -f

The bot will come online, register slash commands, and check for a yt-dlp update automatically.


๐Ÿ’ป Running Locally (Node.js)

# 1. Install dependencies
npm install

# 2. Create .env
cp .env.example .env

# 3. Start
npm start

Verify your dependencies are available:

ffmpeg -version
yt-dlp --version

๐Ÿ•น๏ธ Commands

Playback

Command Description
/play <query> [position] Play from YouTube, SoundCloud, Spotify, or a search term. position: end (default), next, top
/skip Skip the current track
/prev Play the previous track
/pause Pause playback
/resume Resume playback
/stop Stop playback and clear the queue
/seek <time> Seek to a timestamp โ€” 1:23 or 83 (seconds)
/nowplaying Show a detailed Now Playing embed
/join Join your current voice channel
/leave Leave the voice channel and clear the queue

Queue

Command Description
/queue Refresh/show the Now Playing panel
/remove <track> Remove a track โ€” autocomplete by number or title
/move <from> <to> Move a track to a new position โ€” autocomplete the source track
/jump <track> Jump to a track immediately โ€” autocomplete by number or title
/shuffle Shuffle the upcoming queue
/clear Clear the queue without leaving the channel

Playlists

Command Description
/playlist save <name> Save the current queue (+ now-playing) as a named playlist
/playlist load <name> Load a saved playlist into the queue
/playlist delete <name> Delete a saved playlist
/playlist list Show all saved playlists

Settings

Command Description
/volume <0โ€“200> Set playback volume (100 = normal)
/loop <off|one|all> Loop mode: off, repeat one, or repeat all
/autoplay <true|false> Toggle autoplay when the queue ends
/filter <name> Apply an audio filter (bassboost, nightcore, vaporwave, 8d, echo, karaoke, treble, off)
/djonly <true|false> Restrict controls to admins or the configured DJ role

๐Ÿ” Troubleshooting

Problem Solution
Slash commands not appearing Ensure applications.commands scope is granted. With GUILD_ID set, commands register instantly. Without it, global propagation takes up to 1 hour.
Bot doesn't play audio Confirm Connect & Speak permissions. Run ffmpeg -version and yt-dlp --version to verify both are installed.
"yt-dlp failed" errors The bot auto-updates yt-dlp on startup and every 24h, but you can also trigger it manually: docker compose exec discodj yt-dlp -U
Spotify tracks show wrong song Spotify โ†’ YouTube mapping is done by title search. Results for remixes or obscure tracks may not be exact โ€” this is a known limitation of not using Spotify's audio API.
SoundCloud track won't play Some SoundCloud tracks require authentication or are behind SoundCloud Go+. Try a different track or confirm the URL is public.
Progress bar missing Occurs for live streams (no fixed duration) or Spotify placeholder tracks that haven't been resolved yet.
DJ-only message on buttons /djonly on is active. Use /djonly off or ensure the user has the DJ_ROLE_ID role or admin permissions.
Bot leaves voice immediately The channel was empty. The bot waits 3 seconds before leaving to survive mobile reconnects.
Crash / unhandled error Check docker compose logs for structured JSON error output. Add restart: unless-stopped to docker-compose.yml for automatic recovery.

๐Ÿ—‚๏ธ Project Structure

discodj/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ bot.js           # Entrypoint โ€” commands, interactions, playback engine
โ”‚   โ”œโ”€โ”€ state.js         # Per-guild in-memory state + JSON persistence
โ”‚   โ”œโ”€โ”€ playlists.js     # Saved playlist read/write helpers
โ”‚   โ”œโ”€โ”€ locks.js         # Per-guild async mutex
โ”‚   โ”œโ”€โ”€ logger.js        # Structured JSON logger
โ”‚   โ””โ”€โ”€ utils/
โ”‚       โ””โ”€โ”€ ytdlp.js     # yt-dlp spawn helpers (info fetch, playlist expand, retries)
โ”œโ”€โ”€ data/                # Auto-created at runtime โ€” guild state + playlist JSON files
โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ docker-compose.yml
โ”œโ”€โ”€ package.json
โ””โ”€โ”€ .env.example

๐Ÿ“ฆ Keeping Dependencies Up to Date

# Check for outdated packages
npm outdated

# Apply non-breaking updates
npm update

# Bump all deps including major versions (review changelogs first)
npx npm-check-updates -u
npm install

After updating, re-test: /play, voice join, skip/prev, panel controls, and filter.


๐Ÿ“„ License

MIT License ยฉ 2025 discodj Developers


โค๏ธ Contributions

Pull requests and feature ideas are welcome! Open an issue or submit a PR.

About

Run your own discord music bot with docker

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors