Play your local music files in Discord voice channels — no YouTube, no Spotify, no external APIs. SpinLocal is a self-hosted Discord bot that streams your own MP3, FLAC, WAV, and more directly from your machine. Your music, your server, your control.
Supports playlists, queue management, category folders, looping, shuffle-looping, and an interactive playlist editor with Discord buttons. Built for streamers and communities that want full control over their music.
- Stream local MP3, WAV, OGG, FLAC, and M4A files directly in Discord voice channels
- Organize music into category subfolders — queue or loop entire folders
- Full queue control — skip, remove, reorder, shuffle
- Named playlists with an interactive button-based editor
- Loop a single track, a playlist, or an entire category
- Continuous shuffle-loop (re-shuffles every pass)
- Role-based access control via a configurable Discord "DJ" role
- 100% self-hosted — zero external music APIs, just Python and FFmpeg
- Python 3.10 or higher
- FFmpeg installed and available on your system PATH
- A Discord bot token
Windows:
- Download from ffmpeg.org/download.html
- Extract to a folder (e.g.
C:\ffmpeg) - Add
C:\ffmpeg\binto your system PATH - Verify: open a terminal and run
ffmpeg -version
Mac:
brew install ffmpegLinux (Debian/Ubuntu):
sudo apt install ffmpeggit clone https://github.com/hoovnick/SpinLocal.git
cd SpinLocalpip install -r requirements.txtCopy the example env file and fill in your values:
cp .env.example .envOpen .env in any text editor:
DISCORD_TOKEN=your_discord_bot_token_here
MUSIC_ROOT=C:/Users/YourName/MusicAll other settings are optional — the defaults work out of the box.
Point MUSIC_ROOT at a folder containing your audio files. You can organize them into subfolders — each subfolder becomes a "category" you can queue or loop as a group:
music/
rock/
song1.mp3
song2.mp3
jazz/
track1.flac
ambient/
...
Supported formats: .mp3 .wav .ogg .flac .m4a
- Go to discord.com/developers/applications
- Click New Application → name it SpinLocal
- Go to Bot → click Add Bot
- Under Privileged Gateway Intents, enable:
Server Members IntentMessage Content Intent
- Copy your bot token and paste it into
.envasDISCORD_TOKEN
Go to OAuth2 → URL Generator, select:
- Scopes:
bot - Bot Permissions:
Connect,Speak,Send Messages,Read Message History
Open the generated URL and invite the bot to your server.
In your Discord server:
- Go to Server Settings → Roles → Create Role
- Name it exactly
DJ(or whatever you setDJ_ROLE_NAMEto in.env) - Assign this role to anyone you want to control the bot
Windows — double-click run.bat, or from a terminal:
python bot.pyMac/Linux:
chmod +x run.sh
./run.shThe bot will print SpinLocal online as ... when it's ready.
| Command | Description |
|---|---|
!join |
Join your current voice channel |
!leave |
Disconnect and clear queue |
!play <song> |
Search all music, queue first match |
!playnext <song> |
Insert a song at position 1 (plays right after current) |
!playcat <category> |
Queue every song in a category folder |
!skip |
Skip the current track |
!stop |
Stop playback and clear everything |
!pause |
Pause playback |
!resume |
Resume paused playback |
!volume <0–100> |
Set playback volume |
!loop |
Toggle looping the current track |
!loopcat <category> |
Play and loop a category continuously in order |
!shuffleloop <category> |
Play and shuffle-loop a category (re-shuffles each pass) |
!loopoff |
Disable queue loop after current queue finishes |
!shuffle |
Shuffle the current queue |
!clear |
Clear the queue without stopping current track |
!remove <#> |
Remove a track from the queue by position number |
| Command | Description |
|---|---|
!nowplaying / !np |
Show current track, category, and queue count |
!queue / !q |
Show the current queue (up to 15 tracks) |
!search <term> |
List all songs matching a search term |
!list |
Show all music category folders |
!list <category> |
Show all songs in a category |
!ping |
Check bot latency |
| Command | Description |
|---|---|
!playlist list |
Show all saved playlists with track counts |
!playlist create <name> |
Create a new empty playlist |
!playlist edit <name> |
Open the interactive editor (buttons for add/remove/move/rename) |
!playlist show <name> |
Display all tracks in a playlist |
!playlist play <name> |
Queue all tracks from a playlist |
!playlist shuffle <name> |
Queue all tracks in random order |
!playlist loop <name> |
Loop a playlist continuously in order |
!playlist loopshuffle <name> |
Shuffle-loop a playlist (re-shuffles each pass) |
!playlist delete <name> |
Permanently delete a playlist |
!playlist rename <old> <new> |
Rename a playlist |
!playlist add <name> <song> |
Add a song to a playlist |
!playlist remove <name> <song> |
Remove a song from a playlist by name |
!playlist move <name> <pos> <newpos> |
Reorder a track within a playlist |
Note: All playback and DJ commands require the DJ role.
!search,!list,!nowplaying,!queue, and!pingare open to everyone.
All settings live in .env. Copy .env.example to get started.
| Variable | Default | Description |
|---|---|---|
DISCORD_TOKEN |
(required) | Your Discord bot token |
MUSIC_ROOT |
./music |
Path to your local music folder |
DJ_ROLE_NAME |
DJ |
Discord role name that grants bot control |
DEFAULT_VOLUME |
0.5 |
Starting volume (0.0–1.0) |
COMMAND_PREFIX |
! |
Bot command prefix |
DB_PATH |
./data/playlists.db |
Where playlist data is stored |
Bot joins voice but plays nothing / immediately says "Queue finished"
- FFmpeg is not installed or not on your PATH. Run
ffmpeg -versionin a terminal to check. If it fails, install FFmpeg and add it to PATH.
RuntimeError: PyNaCl library needed
- Run
pip install "discord.py[voice]"— the[voice]extra includes PyNaCl which is required for voice connections.
Bot doesn't respond to commands
- Make sure
Message Content Intentis enabled in the Discord Developer Portal under your bot's settings. - Confirm the command prefix matches what's in your
.env.
Songs not found with !play
- Check that
MUSIC_ROOTin.envpoints to the correct folder. - Song search matches against filenames (without extension). Use
!listto browse what's available.
MIT — see LICENSE