A hassle-free, highly performant, host-it-yourself, cracking smoking Discord music bot
Thanks to the guys over at alwaysdata for hosting the website, web portal, email, etc for this project for free, in their Open Source program.
- Create a bot account.
- Put its token in a
.envasDISCORD_TOKEN. That is the only required variable — the bot starts and plays music with nothing else set.
Everything below is optional, and the bot degrades rather than failing without it:
| variable | what you lose without it |
|---|---|
DATABASE_URL |
play history, track reactions, playlist storage, guild settings that survive a restart, /gp games that survive one too, and the autoplay cache |
SLEEVENOTE_BASE_URL |
Spotify links in /play, /gp submit, /spotify and /playlist loadspotify |
MUSICATLAS_API_KEY |
musicatlas as autoplay's last resort, asked only when YouTube's Mix and Deezer both have nothing. It also needs DATABASE_URL, where its daily budget is counted |
OPENAI_API_KEY |
ChatGPT commands |
VIRUSTOTAL_API_KEY |
OSINT URL checking |
COMMAND_REGISTRATION decides how the slash commands reach Discord. global, the default, registers every command globally at startup. manual registers only /register globally, for members with Manage Server: a server gets the rest when one of them runs /register and presses Register in guild, and keeps them (refreshed at each startup) until Delete in guild. Before switching a bot back to global, press Delete in guild in each server that registered, while it is still manual: those servers keep their own copy of the commands, and Discord would show every command twice. TuneTitan, the beta bot, runs manual, so it only shows up in the servers testing it.
Autoplay (/autoplay) is off by default and lasts until the bot restarts. It
picks the next track from the one that just ended: YouTube's own Mix for that
video first (listed through yt-dlp, which playback already needs), then
Deezer's radio for its artist, then musicatlas when
MUSICATLAS_API_KEY and a database are both set. None of them needs Spotify,
and only musicatlas needs a key.
Spotify needs no credentials. It is served by
sleevenote rather than the Spotify
Web API — which matters, because Spotify stopped accepting new Web API app
registrations around December 2025, so SPOTIFY_CLIENT_ID and
SPOTIFY_CLIENT_SECRET are not obtainable for a new self-hoster even if the old
path were still wanted.
What it does need is somewhere to reach sleevenote. SLEEVENOTE_BASE_URL
defaults to http://127.0.0.1:3000, which is right if you run the service
beside the bot and wrong everywhere else — in Docker Compose, for instance, the
bot's own localhost is not the sleevenote container. Without it a Spotify link
says Spotify support is not set up, and the rest of the bot is unaffected:
searches and YouTube links play as normal.
Spotify is never the audio source, with or without it. sleevenote supplies the title and artists; the track itself is found on YouTube, so a Spotify link plays whatever YouTube has. Local files in a playlist cannot be resolved at all, and podcast episodes are skipped rather than guessed at.
DATABASE_URL is the only database variable the bot reads. If you run the
bundled Postgres from docker-compose-postgres.yml, POSTGRES_USER and
POSTGRES_PASSWORD configure that container — the official Postgres image
reads them, the bot does not.
Use .env.example as a starting point.
No Docker, no Rust toolchain. Each release publishes a static
x86_64-unknown-linux-gnu build with an installer script and a .sha256
alongside it:
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/cycle-five/cracktunes/releases/latest/download/cracktunes-installer.sh | shOr take the tarball directly from the
latest release if you
would rather read the script first, or check the .sha256 before running anything.
crack-testing and crack-voting ship the same way.
You still need a .env with DISCORD_TOKEN, and yt-dlp on PATH for playback.
A single image, no database of your own to run:
docker run -d --env-file .env --restart unless-stopped --name cracktunes ghcr.io/cycle-five/cracktunes:latestImages are published by CI to ghcr.io/cycle-five/cracktunes. Tagged releases get
version tags; branch builds get floating ones.
Use scripts/cracktunes.sh rather than driving docker compose directly — it pins
the project name and env file, and refuses on the failure modes that are otherwise
silent (wrong Docker context, database password divergence, missing external volumes,
missing DISCORD_TOKEN).
cp .env.example .env # then fill it in
./scripts/cracktunes.sh preflight # verify without changing anything
./scripts/cracktunes.sh upTo ship a new version, deploy (pull + recreate) rather than restart (recreate
only, picks up no new code):
./scripts/cracktunes.sh deploy
./scripts/cracktunes.sh logs cracktunes./scripts/cracktunes.sh help lists everything. See scripts/README.md
for what the other scripts in that directory are, and which of them are broken.
Make sure you've installed Rust. You can install Rust and its package manager, cargo by following the instructions on https://rustup.rs/.
After installing the requirements below, simply run cargo run.
The commands below install a C compiler, GNU autotools and FFmpeg, as well as yt-dlp through Python's package manager, pip.
apt install build-essential autoconf automake libtool ffmpeg
pip install -U yt-dlpbrew install autoconf automake libtool ffmpeg
pip install -U yt-dlpIf you are using the MSVC toolchain, a prebuilt DLL for Opus is already provided for you.
You will only need to download FFmpeg, and install yt-dlp which can be done through Python's package manager, pip.
pip install -U yt-dlpIf you are using Windows Subsystem for Linux (WSL), you should follow the Linux/MacOS guide, and, in addition to the other required packages, install pkg-config, which you may do by running:
apt install -y pkg-configTests run with cargo-nextest; doctests, which it skips, run
with cargo test --doc:
cargo nextest run --workspace
cargo test --doc --workspaceThe database tests, template databases, mutation testing and the rest are in docs/testing.md. It's recommended that you run the tests before submitting a Pull Request. Increasing the test coverage is also welcome.
Coverage is measured with cargo-llvm-cov,
weekly in CI (.github/workflows/coverage.yml). To measure locally, with a
postgres running, use the cargo llvm-cov nextest command in docs/testing.md.
cargo clippy --all --all-targets -- -D warningscargo +nightly build --profile=release --features crack-osint,crack-bf --workspace --lockedcargo dist init --hosting github
# make change `pr-run-mode = "upload"`
git add .
git commit -am "chore: cargo-dist"
cargo dist build --profile=release --features crack-bf,crack-osintgit tag vX.X.X
git push --tags
# publish to crates.io (optional)
cargo publishdocker build -t cracktunes .Note that docker-compose.yml references the published ghcr.io/cycle-five/cracktunes:master
image, not a locally built one — so building with the tag above does not change what
docker compose up runs. Retag it or edit the compose file if you want your local
build in the stack. Deploying is covered under Deployment above.
Originally forked from Parrot
