
Presented by Señor Mega. Powered by Go, FFmpeg, and several questionable engineering decisions.
Self-hosted music player written in Go that can run either as:
Melodix supports YouTube, SoundCloud and internet radio, using multiple parsers with automatic fallback for resilience.
Limitations
Try the bot in The Megabyte Order Discord server:
enter a voice channel and use slash commands in #bot-music-spam.
Download pre-built binaries:
https://github.com/keshon/melodix/releases
Each archive contains:
melodix-discord — Discord botmelodix-cli — terminal playerExample usage:
/music play Never Gonna Give You Up
/music play https://www.youtube.com/watch?v=dQw4w9WgXcQ
/music play http://stream-uk1.radioparadise.com/aac-320
You must be in a voice channel to use /music play.
YOUR_APPLICATION_ID with your app ID, open the URL, choose your server, and authorize. Then use slash commands. To self-host the bot, see Running Melodix yourself./music play with a link or search term (e.g., /music play Never Gonna Give You Up).DISCORD_TOKEN in .env, and run the Discord binary. Full steps: Discord bot — Step 2.go build -o melodix-cli ./cmd/cli or use the melodix-cli binary from releases. No Discord token needed. Commands: play, next, stop, queue, status, quit. See CLI player.You can run the Discord bot (voice channels) or the CLI player (local playback). Both use the same sources and queue logic.
For the Discord bot you also need a Discord bot token from the Discord Developer Portal.
Open the Discord Developer Portal and create a new application. Note the Application ID.
Go to the Bot section and create a bot. Copy the token (you will use it as DISCORD_TOKEN).
Under Privileged Gateway Intents, enable:
Invite the bot to your server using this URL (replace YOUR_APPLICATION_ID with your Application ID from step 1):
https://discord.com/oauth2/authorize?client_id=YOUR_APPLICATION_ID&scope=bot&permissions=3238912
Open the URL in your browser, choose your server, and authorize. Grant the requested permissions when asked.
Create a .env file in the folder where you run the bot (or set the same variables in your environment):
# Required for the Discord bot
DISCORD_TOKEN=your-discord-bot-token
Optional variables (you can add these to .env if needed):
| Variable | Description | Default |
|---|---|---|
STORAGE_PATH |
Path for bot data (e.g. command state). | ./data/datastore.json |
INIT_SLASH_COMMANDS |
Set to true to register slash commands on every startup. |
false |
DEVELOPER_ID |
Your Discord user ID for developer-only commands. | (none) |
DISCORD_GUILD_BLACKLIST |
Comma-separated guild IDs the bot will leave. | (none) |
Run the Discord bot:
go build -o melodix-discord ./cmd/discord then run the binary. Ensure DISCORD_TOKEN is set (e.g., in .env).melodix-discord binary from the releases archive.After the bot is running and invited to your server, use slash commands in any channel. For music, be in a voice channel and use /music play with a link or search term.
The CLI player uses the same playback engine but runs in your terminal and plays through your speakers. No Discord token or server setup required.
Run the CLI player:
go build -o melodix-cli ./cmd/cli then run the binary.melodix-cli binary from the releases archive.CLI commands (at the > prompt):
| Command | Description |
|---|---|
play <url or query> [source] [parser] |
Add and play a track. |
next |
Skip to the next track. |
stop |
Stop playback and clear the queue. |
queue |
Show now playing and the queue. |
status |
Show current track and queue length. |
quit |
Exit. |
Example:
> play Never Gonna Give You Up
> queue
> next
> quit
High level flow:
flowchart TB
User["User"]
DiscordBot["Discord bot"]
CLI["CLI"]
MusicPlayer["Player (pkg/music)"]
Resolver["Resolver"]
Sink["Sink (Discord VC or speaker)"]
User -->|"slash / play"| DiscordBot
User -->|"play command"| CLI
DiscordBot --> MusicPlayer
CLI --> MusicPlayer
MusicPlayer --> Resolver
MusicPlayer --> Sink
The pkg/music package is the core of the bot. It implements the entire playback pipeline: resolving tracks, managing the queue, opening audio streams, and delivering PCM audio to different sinks (Discord voice or local playback).
The playback pipeline works as follows:
Resolve — User input (URL or search) goes to the resolver. Sources (YouTube, SoundCloud, radio) match the input and return track metadata (URL, title, list of available parsers). No streaming yet.
Enqueue — The player enqueues one or more tracks (metadata only). If nothing is playing, the caller typically calls PlayNext.
PlayNext — The player pops the next track and calls startTrack: opens a RecoveryStream (which wraps TrackStream) and starts a playback goroutine that will obtain a sink and stream PCM.
Open stream — RecoveryStream opens a TrackStream by trying the track’s parsers in order (ytdlp-link, kkdai-link, ffmpeg-link). Each parser produces PCM (48 kHz, stereo, 16-bit). If the stream dies early, RecoveryStream can retry with the same or next parser (up to a limit).
Stream to sink — The player feeds the PCM ReadCloser into AudioSink.Stream. The sink runs until the stream ends or a stop signal is received.
PlayNext) or stop. Calling Stop(true) clears the queue and releases the sink.Subpackages: player, resolver, sink, sources, parsers, stream. See also pkg/music/README.md for using the library standalone.
I needed a self-hosted music bot that could reliably run for long DnD sessions without interruptions. I also wanted to achieve:
For help or questions, use the The Megabyte Order — official Melodix Discord server.
Why does play sometimes take a few seconds?
The bot resolves the input (URL or search) and opens an audio stream using one of the parsers (yt-dlp, kkdai, ffmpeg). The first request for a track may take a moment; playback starts once the stream is ready.
Can I use only the music library without the bot?
Yes. The pkg/music library is a standalone Go package. You can use the speaker sink and resolver for a CLI or custom app. See pkg/music/README.md and the example in pkg/music/examples/cli_speaker.
Why is FFmpeg required?
Parsers use FFmpeg to decode various audio formats (YouTube, radio streams, etc.) into PCM, which the bot can send to Discord or play locally.
Why can’t the bot join the voice channel?
The bot needs Connect and Speak permissions in that channel. Check the channel or server permissions for the bot role.
Why is there no audio or the track never starts?
Ensure FFmpeg (and optionally yt-dlp) is available in your PATH. Check parser logs for stream open errors. Some region-locked or live YouTube streams may not be supported.
The bot does not start or cannot connect to Discord
In some regions Discord may be blocked. If the server running the bot cannot reach Discord, the bot will fail to connect. Run it on a server with open access to Discord, or configure a proxy/VPN if necessary.
Contributions are welcome. Open an issue or pull request on GitHub. For larger changes, discuss in the Melodix Discord server first.
Melodix is licensed under the MIT License.