melodix

# Header

GoDoc Go report

Melodix — Self-hosted Discord music bot & CLI player

Presented by Señor Mega.
Powered by Go, FFmpeg, and questionable engineering decisions.

Melodix is a music player you can run as a Discord bot (plays in voice channels) or as a CLI app (plays on your machine). Same playback engine for both: YouTube, SoundCloud, and internet radio with various parsers.

Table of contents


Features


Try Melodix without installing


Commands

🕯️ Information

🎵 Music

⚙️ Settings

Music examples: Play by search query or by link. You must be in a voice channel to use /music play.

/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

How-to’s


Running Melodix yourself

You can run the Discord bot (voice channels) or the CLI player (local playback). Both use the same sources and queue logic.

What you need (both modes)

For the Discord bot you also need a Discord bot token from the Discord Developer Portal.

Discord bot — Step 1: Create the bot in Discord

  1. Open the Discord Developer Portal and create a new application. Note the Application ID (in the “General Information” section).
  2. Go to the Bot section and create a bot. Copy the token (you will use it as DISCORD_TOKEN).
  3. Under Privileged Gateway Intents, enable:
    • Presence Intent
    • Server Members Intent
    • Message Content Intent
  4. 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

    This link only requests the permissions the bot needs: View Channel, Send Messages, Embed Links, Read Message History, Manage Messages, Connect to Voice Channel, Speak.

  5. Open the URL in your browser, choose your server, and authorize. Grant the requested permissions when asked.

Discord bot — Step 2: Configure and run

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:

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.

CLI player

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:

CLI commands (at the > prompt):

Command Description
play <url or query> [source] [parser] Add and play (e.g. play https://youtube.com/... or play Never Gonna Give You Up).
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

How it works

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

Music package overview

The playback pipeline in pkg/music works as follows:

  1. 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.
  2. Enqueue — The player enqueues one or more tracks (metadata only). If nothing is playing, the caller typically calls PlayNext.
  3. PlayNext — Player pops the next track, calls startTrack: opens a RecoveryStream (which wraps TrackStream), starts a playback goroutine that will get a sink and stream PCM.
  4. Get sink — The playback goroutine asks the sink provider for an AudioSink (Discord: join voice channel and return a sink that encodes PCM to Opus and sends to the VC; CLI: return the speaker sink). If getting the sink fails (e.g. timeout or no permission), playback errors and the queue does not spin.
  5. Open streamRecoveryStream opens a TrackStream by trying the track’s parsers in order (e.g. 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).
  6. Stream to sink — The player feeds the PCM ReadCloser to AudioSink.Stream. The sink runs until the stream ends or a stop signal is received (Discord: Opus encode and send; CLI: play to speaker).
  7. Next or stop — When the stream ends, the player can auto-advance to the next track (PlayNext) or stop; Stop(true) clears the queue and releases the sink (e.g. leave VC).
flowchart LR
  Resolver["Resolver"]
  Player["Player"]
  SinkProvider["SinkProvider"]
  RecoveryStream["RecoveryStream"]
  TrackStream["TrackStream"]
  AudioSink["AudioSink"]
  Resolver -->|"track metadata"| Player
  Player -->|"GetSink"| SinkProvider
  SinkProvider -->|"AudioSink"| Player
  Player -->|"open"| RecoveryStream
  RecoveryStream -->|"PCM stream"| TrackStream
  Player -->|"Stream"| AudioSink

Subpackages: player, resolver, sink, sources, parsers, stream. See also pkg/music/README.md for using the library standalone.


Support

For help or questions, use the The Megabyte Order — official Melodix Discord server.


FAQ


Troubleshooting


Contributing

Contributions are welcome. Open an issue or pull request on GitHub. For larger changes, discuss in the Melodix Discord server first.


License

Melodix is licensed under the MIT License.