Open-source project
umutxyp/MusicBot avatar
umutxyp/MusicBot

umutxyp/MusicBot: the Discord music bot that installs its own download tooling

Advanced Discord v14.27 Music Bot with YouTube, Spotify, SoundCloud, and Direct Link support.

1,291 stars1,233 forksJavaScriptMIT

At a glance

What is it?
MusicBot is a Discord v14 music bot built on discord.js and DisTube that plays YouTube, Spotify, SoundCloud and direct links. Its distinguishing choice is that it downloads yt-dlp and ffmpeg itself and refuses to start until a self-check passes, so a server owner needs a bot token and nothing else.
Who is it for?
Adopt MusicBot if you run a Discord server and want a music bot without assembling yt-dlp, ffmpeg and voice libraries by hand, since the startup check handles the binaries and refuses to run in a broken state. Do not adopt it if you need versioned releases, because the repository publishes none, or if your listeners depend on full Spotify playlists, since the missing API keys cap those at the first 100 songs.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 8 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A music bot that ships its own yt-dlp and ffmpeg

MusicBot is a Discord music bot written in JavaScript for servers that want a shared queue, a button panel and playback from several sources. The dependency list in `package.json` names `discord.js` at version `^14.27.0` and `distube` at `^5.2.3`, with `@distube/spotify`, `@distube/soundcloud` and `@distube/direct-link` bolted on as extra extractors, and `@discordjs/voice` for the voice layer. The `engines` field requires `node` at `>=22.12.0`.

The design decision worth noticing is not the library choice, it is the packaging. The README states that the only prerequisites are Node.js and a bot token, and that Python, ffmpeg and yt-dlp do not need to be installed by hand because the bot downloads the right versions for the computer it runs on. That is unusual for a Discord music bot, where the usual complaint is a broken voice connection because a system library is missing or too old.

The scope is still a community bot rather than a service. It is MIT licensed, the default branch is `main`, the README labels it the public version of the Beatra bot, and the last push was on 2026-10-09. The repository has no GitHub releases, so the version history lives in the `package.json` version field, which reads `17.0.0`.

The startup check decides whether the bot goes online at all

Every launch begins with a checklist that fixes what it can and halts on everything else. The README frames the intent clearly: the bot should never run half broken. The printed output looks like this.

bash
Beatra startup check

  [ OK ] Node.js 22.12.0
  [ OK ] npm packages
  [ OK ] Discord token  Beatra (application 123456789012345678)
  [ OK ] yt-dlp  2026.09.01
  [ OK ] ffmpeg  ffmpeg version 7.1
  [ OK ] Voice libraries  opus, encryption, DAVE
  [INFO] Spotify API keys not set  optional: large Spotify playlists load only their first 100 songs

The repair table in the README is more informative than the happy path. Missing npm packages trigger an `npm install`, and the same runs automatically after a pull. A missing `.env` is created from `.env.example`, and `CLIENT_ID` is derived from the token rather than asked for. yt-dlp is fetched without a Python install and refreshed once a day. ffmpeg is fetched the same way. When something cannot be repaired, the process stops and prints the fix, as in the token failure case.

bash
  [FAIL] Discord rejected DISCORD_TOKEN (wrong or reset token)
         1. Open https://discord.com/developers/applications and select your bot
         2. Go to "Bot" and press "Reset Token", then copy the token
         3. Paste it into the .env file in the bot folder:  DISCORD_TOKEN=your_token

The bot was not started: 1 problem(s) above must be fixed first.

One asymmetry is worth knowing. The Node.js version check and the voice library check are not auto repaired, so a wrong Node.js version or a corrupted `node_modules` means a manual stop, and the README tells you to delete `node_modules` in the voice library case. The optional settings, `PROXY_URL`, `COOKIES_FILE` and `GUILD_ID`, are not silently ignored either. If a value is invalid or the referenced file does not exist, the startup stops.

From a clone to a running bot in four commands

The install path is short enough to follow exactly. The README asks for the LTS build of Node.js, version 22.12 or newer, and then a clone of the repository, or a ZIP download from the Code menu on GitHub.

bash
git clone https://github.com/umutxyp/musicbot.git
cd musicbot

The bot token comes from the Discord developer portal: create a new application, open the Bot page, press Reset Token and copy the result. The OAuth2 URL Generator is used to add the bot to a server with the `bot` and `applications.commands` scopes and the View Channels, Send Messages, Embed Links, Read Message History, Connect and Speak permissions. The README states that no privileged gateway intents are needed.

The token goes into a `.env` file in the bot folder, and the bot creates that file from `.env.example` on first start if it is missing.

bash
DISCORD_TOKEN=paste_your_token_here

Then start it. On Windows there is `start.bat` and `start-shard.bat`, on any system `npm start`, `node .` or `node index.js` all work, and `npm run shard` is the same as `npm start`.

bash
npm start

The first start takes longer because it installs the npm packages and downloads yt-dlp and ffmpeg. When the console reports `1 shard(s) running` the bot is online, and the README points you at the `/play` slash command. Pressing Ctrl + C stops it, and the README states that the queue is saved and continues on the next start.

The YouTube bot check, cookies, and the SoundCloud fallback

Playing from YouTube is the hard part of any music bot, and this repository treats it as a first class configuration surface rather than a footnote. The README carries a section titled YouTube: Sign in to confirm you're not a bot, and `.env.example` groups three mutually exclusive remedies under it.

bash
# Fix "Sign in to confirm you're not a bot": use ONE of these
COOKIES_FILE=
COOKIES_FROM_BROWSER=
YOUTUBE_PO_TOKEN=

Cookies can come from a file or be read out of a local browser, and a PO token is accepted as the third route. There is also an escape hatch for advanced cases, `YTDLP_EXTRACTOR_ARGS`, with the example `youtube:player_client=web_safari` in the file, and a knob for how many yt-dlp processes may run at once per shard, `YTDLP_CONCURRENCY`, defaulting to 4.

The cleverest setting is the fallback. When a track fails on YouTube because it is blocked, returns 403 or has been removed, the bot can play it from SoundCloud instead.

bash
# When YouTube fails for a song (blocked, 403, removed), play it from SoundCloud instead.
# Set to "off" to show the YouTube error instead.
YOUTUBE_FALLBACK=soundcloud

That is a real trade-off rather than a free win. A listener asking for one track may get a different recording of it, and a server owner who prefers to see the error can turn the behaviour off. The `.env` file also accepts `YTDLP_PATH` and `FFMPEG_PATH` if you want to pin your own binaries, and `PROXY_URL` for YouTube and audio downloads, where `http(s)://` and `socks5://` proxies both work and several can be separated by commas, with each guild sticking to one of them.

Sharding, the persisted queue, and the jump from v16 to v17

The bot always runs with sharding, according to the README: one shard for small bots and as many as Discord recommends for large ones, and a crashed shard restarts by itself. `shard.js` sits at the top of the repository, and `TOTAL_SHARDS=auto` is the default in `.env.example`, so the shard count follows the Discord recommendation instead of being pinned by hand.

The queue is persisted across restarts, which matters for a server that leaves playback running overnight. A few other runtime defaults sit in the same file.

bash
DEFAULT_VOLUME=100
MAX_QUEUE_SIZE=500
MAX_PLAYLIST_SIZE=200
LEAVE_ON_EMPTY=60
LEAVE_ON_FINISH=120
PANEL_REFRESH=20

`LEAVE_ON_EMPTY` and `LEAVE_ON_FINISH` are expressed in seconds and 0 means never leave, so the bot can be set to sit in a channel indefinitely or to vacate it quickly. `PANEL_REFRESH` controls how often the now playing panel redraws its progress bar, with 0 meaning the panel updates only when something changes.

Upgrading from the pre-rewrite version needs one deliberate step. v16 kept `.env` inside the repository; v17 does not, precisely so a token cannot be committed by accident. A plain pull therefore fails with a message about local changes to `.env` being overwritten, and the README gives the recovery sequence.

bash
cp .env .env.backup && git checkout -- .env && git pull && cp .env.backup .env

The Windows equivalent is a `copy` chain ending in `copy /Y .env.backup .env`. One setting does not survive the move: server languages from v16, which lived in `database/languages.json`, have to be picked again with the `/language` command. Everything else carries over, including the old `.env` names, the unchanged 0 to 100 volume range with a default of 100, and the removal of the old `audio_cache` folder, since v17 streams music rather than downloading songs.

The Spotify keys decide how much of a playlist you get

The one clearly optional block in `.env.example` is the Spotify pair.

bash
SPOTIFY_CLIENT_ID=
SPOTIFY_CLIENT_SECRET=

The comment in the file is blunt about the consequence: without the keys, only public metadata scraping is used. The startup checklist repeats it, printing an INFO line that large Spotify playlists load only their first 100 songs. So a server owner can add a Spotify playlist link and hear a hundred tracks, then find out that tracks 101 onward need credentials that the project will never supply on its own.

The other optional settings follow the same pattern of a sane default plus a knob. `STATUS` sets the text shown after Listening to, defaulting to `/play`. `EMBED_COLOR` sets the panel colour, defaulting to `#5865F2`, the Discord blurple. `DEFAULT_LANGUAGE` is `en`, and `GUILD_ID` restricts slash command registration to a single server, which the file describes as useful for instant updates while developing.

The `package.json` scripts round out the tooling picture: `npm run deploy` calls `scripts/deploy-commands.js` to register commands, `npm test` runs the files under `test/` with the Node test runner, `npm run check` calls `scripts/check-syntax.js`, and a `postinstall` hook runs `scripts/install-binaries.js`, which is the piece that fetches yt-dlp and ffmpeg. `ffmpeg-static` is listed as an optional dependency, so a failed download of that package does not by itself break the install.

Run it yourself, or invite the hosted Beatra bot

There is a second path that the README itself points at. The header of the project links an invite for the public Beatra bot, a Beatra web dashboard at `beatra.app`, and a codeshare link, alongside the repository. The repository is labelled the public version, which suggests it is one tier of a broader product rather than the whole thing.

The two approaches differ in what you own. Inviting the hosted bot gives you a managed process where the Discord token, the binaries and the YouTube credentials are someone else's problem, and the trade is that the playback configuration lives in that dashboard rather than in your own `.env`. Self hosting gives you the `.env` file, the `GUILD_ID` scope restriction, your own proxy list and your own cookie file, and the trade is that every dependency has to be kept working on the host you chose. The README mentions hosting panels such as Pterodactyl and Railway by name, where `DISCORD_TOKEN` can be set as an environment variable instead of through a file.

Two limitations deserve a clear statement. First, there are no GitHub releases, so an upgrade is a `git pull` or a fresh ZIP rather than a versioned artifact, and the README instructs ZIP users to carry the `.env` file and the `data` folder over by hand to keep server settings. Second, the README does not document a rollback path, an upgrade script or a way to pin a known good version, so the only safe rollback available from what is written down is restoring the files you copied yourself. For a bot whose whole job is to be there every evening, those two facts matter more than the feature list.

Editorial conclusion

Adopt MusicBot if you run a Discord server and want a music bot without assembling yt-dlp, ffmpeg and voice libraries by hand, since the startup check handles the binaries and refuses to run in a broken state. Do not adopt it if you need versioned releases, because the repository publishes none, or if your listeners depend on full Spotify playlists, since the missing API keys cap those at the first 100 songs. Before deploying, check that Node.js 22.12 or newer is on the host, decide how you will supply the YouTube credentials through `COOKIES_FILE`, `COOKIES_FROM_BROWSER` or `YOUTUBE_PO_TOKEN`, and confirm the `YOUTUBE_FALLBACK=soundcloud` default does not silently substitute a different track.

Frequently asked questions

What do I need to install before running umutxyp/MusicBot?

Node.js version 22.12 or newer, and nothing else. The README states that Python, ffmpeg and yt-dlp are not needed because the bot downloads the right versions for your computer by itself, and the startup check confirms each of them before the bot comes online.

Why does MusicBot stop at startup instead of running with a broken setup?

The startup check repairs what it can, including running `npm install` for missing packages, creating `.env` from `.env.example` and downloading yt-dlp and ffmpeg, and it halts with printed instructions for anything it cannot fix, such as a rejected Discord token or a voice library problem.

How do I fix the YouTube sign in to confirm you are not a bot error?

The `.env.example` file offers three alternatives for that case: set `COOKIES_FILE`, set `COOKIES_FROM_BROWSER`, or provide a `YOUTUBE_PO_TOKEN`, and the file says to use one of them. If a track still fails, the default `YOUTUBE_FALLBACK=soundcloud` plays it from SoundCloud instead, which you can switch off with the value `off`.

Does the MusicBot queue survive a restart?

Yes. The README says that pressing Ctrl + C stops the bot, the queue is saved, and playback continues when the bot starts again. The repository also ships `shard.js`, and the bot always runs with sharding, so a crashed shard restarts by itself.

What happens when I upgrade from v16 to v17?

v17 keeps `.env` outside the repository so a token cannot be committed by accident, so a plain `git pull` reports that local changes to `.env` would be overwritten and you need the backup and checkout sequence the README gives. Server languages from v16 are not carried over and must be set again with the `/language` command, while the old `.env` names, the volume range and the rest do carry over.

Official sources

  1. Issues
  2. License: MIT
  3. Project website
  4. README
  5. umutxyp/MusicBot on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/umutxyp-musicbot.svg)](https://hysenlabs.com/projects/umutxyp-musicbot)

Was this useful?