# Botinator A hobby Discord bot for personal use. It's a small [JDA](https://github.com/discord-jda/JDA) bot with a few fun slash commands and music playback powered by [Lavalink](https://github.com/lavalink-devs/Lavalink). > Personal project — not intended as a polished, general-purpose bot. ## Commands | Command | What it does | | --- | --- | | `/hello` | Sanity-check greeting | | `/say ` | Bot repeats your message | | `/rolldice [sides]` | Roll a die (default 6 sides) | | `/armeter` | Measures your "AR" percentage (just for laughs) | | `/play ` | 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: ```bash 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. ```bash # 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 pass `lavalink` explicitly. 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 `. ## 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 `bot` and `applications.commands` scopes (and the **Connect** + **Speak** voice permissions) - [ ] Enable Developer Mode in Discord and copy your server's **Guild ID** - [ ] `cp .env.example .env` and fill in `BOT_TOKEN`, `LAVALINK_PASSWORD` (and `GUILD_ID`) - [ ] Start Lavalink only: `docker compose up -d lavalink` and 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 `/hello` to confirm it responds, then `/play` from 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. 1. Create your config and the files the bot reads at runtime, next to the compose file: ```bash cp .env.example .env # then fill in BOT_TOKEN and LAVALINK_PASSWORD ``` Make sure `catchphrases.txt`, `always100.txt`, and `always90.txt` exist 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. 2. Pull and start both services: ```bash 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-plugin` version in `lavalink/application.yml` and restarting the server.