Botinator
A hobby Discord bot for personal use. It's a small JDA bot with a few fun slash commands and music playback powered by Lavalink.
Personal project — not intended as a polished, general-purpose bot.
Commands
| Command | What it does |
|---|---|
/hello |
Sanity-check greeting |
/say <message> |
Bot repeats your message |
/rolldice [sides] |
Roll a die (default 6 sides) |
/armeter |
Measures your "AR" percentage (just for laughs) |
/play <query> |
Play or queue a track/playlist by URL, or search text (YouTube) |
/skip |
Skip the current track |
/queue |
Show the queue as a paginated embed (◀/▶ buttons) |
/loop [queue|song|off] |
Loop playback. Bare /loop toggles looping the whole queue; song loops just the current track; off stops looping |
/clear |
Clear the queue (keeps the current track playing) |
How it works
The bot is just a Lavalink client — actual audio is streamed by a separate
Lavalink v4 server that runs alongside it (started with Docker). YouTube support
comes from the youtube-plugin, configured in lavalink/application.yml.
- Bot: Java + Gradle (JDA 6,
lavalink-client) - Music server: Lavalink v4 via
docker-compose.yaml
Requirements
- A JDK (builds on Java 17+; CI and the Docker image use Java 25)
- Docker + Docker Compose (to run the Lavalink server)
- A Discord bot token
Configuration
Copy the example env file and fill in your values:
cp .env.example .env
| Variable | Required | Description |
|---|---|---|
BOT_TOKEN |
✅ | Discord bot token (Developer Portal → your app → Bot) |
GUILD_ID |
optional | Test server ID for instant command registration. If unset, commands register globally (can take up to an hour) |
LAVALINK_URI |
optional | Defaults to ws://localhost:2333 for local runs. In docker-compose.yaml the bot is pointed at ws://lavalink:2333 (the service name) |
LAVALINK_PASSWORD |
✅ | Shared secret between the bot and the Lavalink server. Compose passes the same value to the server as LAVALINK_SERVER_PASSWORD, so they always match. The bot exits if it's unset |
.env is gitignored, so your token stays local.
Running
./gradlew run reads real environment variables — it does not auto-load .env.
So load it into your shell first.
# 1. Start ONLY the Lavalink server — not the bot container — so it doesn't clash
# with the bot you're running from source. (First run downloads the YouTube
# plugin; wait for "ready".)
docker compose up -d lavalink
docker compose logs -f lavalink # wait for "Lavalink is ready to accept connections", then Ctrl+C
# 2. Load your .env and run the bot
set -a; source .env; set +a
./gradlew run
docker compose up -d(no service name) would start the bot container too, giving you two bots. For source development, always passlavalinkexplicitly.
When it connects you'll see Bot connected and ready as ... in the console. Then join a
voice channel in your server and try /play <song or url>.
TODO — steps to get it running
- Install a JDK (17+) and Docker
- Create a Discord application + bot, and copy the bot token
- Invite the bot to your server with the
botandapplications.commandsscopes (and the Connect + Speak voice permissions) - Enable Developer Mode in Discord and copy your server's Guild ID
cp .env.example .envand fill inBOT_TOKEN,LAVALINK_PASSWORD(andGUILD_ID)- Start Lavalink only:
docker compose up -d lavalinkand wait until the logs say it's ready - Load env vars:
set -a; source .env; set +a - Run the bot:
./gradlew run - In Discord, run
/helloto confirm it responds, then/playfrom a voice channel
Run with Docker (prebuilt image)
If you'd rather not build from source, docker-compose.yaml pulls the prebuilt
bot image and runs it alongside Lavalink. You only need Docker — no JDK.
-
Create your config and the files the bot reads at runtime, next to the compose file:
cp .env.example .env # then fill in BOT_TOKEN and LAVALINK_PASSWORDMake sure
catchphrases.txt,always100.txt, andalways90.txtexist as files here. They're mounted into the container — if any is missing, Docker creates an empty directory in its place and the mount breaks. -
Pull and start both services:
docker compose pull # fetch the bot + Lavalink images docker compose up -d # start in the background docker compose logs -f # watch logs; look for "Bot connected and ready as ..." docker compose down # stop
The bot connects to Lavalink over the internal Docker network automatically, so
you don't set LAVALINK_URI yourself here.
Notes
- Queue state is kept in memory, so it resets if the bot restarts.
- YouTube occasionally breaks playback when Google changes its player. The fix is usually
bumping the
youtube-pluginversion inlavalink/application.ymland restarting the server.