$uicide Music Bot

$uicide Music Bot

A self-hosted Discord music bot with a clean interface — built from source and served from this Gitea, ready for Unraid.

release ci java license

--- > [!NOTE] > **This is a fork of a fork of a fork.** The bot is JMusicBot and the credit belongs to the > people below. This repository exists so there is a copy of the working 0.7.1 line that > cannot disappear, with a container image built *here* rather than pulled from someone > else's registry. Nothing under `src/` is changed. > > | Author | Repository | Role | > | --- | --- | --- | > | **[jagrosh](https://github.com/jagrosh)** | [jagrosh/MusicBot](https://github.com/jagrosh/MusicBot) | Original author of JMusicBot | > | **[arif-banai](https://github.com/arif-banai)** | [arif-banai/MusicBot](https://github.com/arif-banai/MusicBot) | Revived and maintains it — dependency updates, Java 25, config migration | > | **[purnell569](https://github.com/purnell569)** | [purnell569/MusicBot](https://github.com/purnell569/MusicBot) | Fixed YouTube playback (0.7.1). **Direct parent of this repository.** | > | **mward4** | this repository | Reliable copy, image built and served from `gitea.milesward.dev`, Unraid template, Gitea CI | > > Licensed under Apache 2.0 — see [LICENSE](LICENSE) and [NOTICE](NOTICE). ## Contents - [What this copy adds](#what-this-copy-adds) - [Quick start (Docker)](#quick-start-docker) - [Unraid](#unraid) - [Versions and upgrades](#versions-and-upgrades) - [What's different in 0.7.1](#whats-different-in-071) - [Requirements](#requirements) - [Features](#features) - [Supported sources and formats](#supported-sources-and-formats) - [Running directly (without Docker)](#running-directly-without-docker) - [Docker notes](#docker-notes) - [Performance tuning](#performance-tuning) - [Proxy configuration](#proxy-configuration) - [Development and publishing](#development-and-publishing) - [Questions, bug reports, credits](#questions-bug-reports-credits) ## What this copy adds - **The image is built here.** `gitea.milesward.dev/mward4/musicbot` comes out of this repository's [Dockerfile](Dockerfile), `linux/amd64`, with OCI labels recording the commit and version it was built from. No dependency on `ghcr.io` or on anyone else's build. - **An Unraid template**, [deploy/unraid/musicbot.xml](deploy/unraid/musicbot.xml): repository, appdata mapping, JVM flags, and a `--user 99:100` default so a freshly created appdata folder works without a chown step. - **CI on Gitea Actions.** [.gitea/workflows/build-and-test.yml](.gitea/workflows/build-and-test.yml) runs the full Maven build — 676 unit and 48 integration tests — and a Docker build on every push to `main`. Upstream's GitHub workflows are kept in `.github/` but do not run here. - **Upstream tags preserved** under `upstream/` (`upstream/v0.7.1`). This repository's own release tags are `vX.Y.Z` and match the version in `pom.xml`. - **A first run that actually works headless.** Upstream's image prompts for a token on a console that does not exist and exits without writing anything. This image's [entrypoint](docker/entrypoint.sh) runs the bot's own `generate-config` when `config.txt` is missing, tells you what to edit, and stops. It also checks the data directory is writable up front — the bot's own message for that case is a misleading "Another instance is already running". - **A publishing runbook**, [docs/PUBLISHING.md](docs/PUBLISHING.md), and a one-shot [build-and-publish script](scripts/build-and-publish-unraid.sh) for cutting the next release. ## Quick start (Docker) The container runs headless and writes a default `config.txt` on first run. ```bash mkdir -p /path/to/musicbot docker run --rm -it \ --name musicbot \ --user "$(id -u):$(id -g)" \ -v "/path/to/musicbot:/musicbot" \ gitea.milesward.dev/mward4/musicbot:latest ``` 1. The first run finds no `config.txt`, writes the default one into the mounted directory, and exits. 2. Edit `/path/to/musicbot/config.txt`: in the `discord { … }` block set `token` to your Discord bot token and `owner` to your Discord user ID. 3. Run the container again. If the log says the directory is not writable, fix the ownership of the mounted directory (or change `--user`) and run again. Already have a directory with `config.txt`, `Playlists/` and `serversettings.json` from a JAR install? Mount that directory instead; nothing else changes. Docker Compose: ```yaml services: musicbot: image: gitea.milesward.dev/mward4/musicbot:latest # or :0.7.1 to pin a release container_name: musicbot user: "1000:1000" # whoever owns the mounted directory volumes: - /path/to/musicbot:/musicbot restart: unless-stopped ``` See [docker-compose.example.yml](docker-compose.example.yml) for the commented version. ## Unraid Import [deploy/unraid/musicbot.xml](deploy/unraid/musicbot.xml) — Docker tab → Add Container → Template, or drop it into `/boot/config/plugins/dockerMan/templates-user/` — and apply. The template maps `/musicbot` to `/mnt/user/appdata/musicbot`, publishes no ports (the bot only makes outbound connections), and runs as `99:100` so the appdata folder Unraid creates is writable straight away. Two things to know: - **First start writes the config and stops.** Open `/mnt/user/appdata/musicbot/config.txt`, set `token` and `owner` in the `discord { … }` block, start the container again. If the log instead says `/musicbot is not writable by uid 99`, the folder was created with different ownership: `chown -R 99:100 /mnt/user/appdata/musicbot` from the Unraid terminal and start again. - **The Discord side needs one switch.** In the [Developer Portal](https://discord.com/developers/applications), under your application → Bot → Privileged Gateway Intents, turn **on** *Message Content Intent*. Without it the bot never sees a command. To run as the image's own non-root user (UID 10001) instead, clear *Extra Parameters* and `chown -R 10001:10001 /mnt/user/appdata/musicbot` once. ## Versions and upgrades | Tag | Meaning | | --- | --- | | `gitea.milesward.dev/mward4/musicbot:latest` | The newest release. | | `gitea.milesward.dev/mward4/musicbot:0.7.1` | That release, pinned. A version tag is never rebuilt with different code. | Each release is listed on this repository's [Releases page](https://gitea.milesward.dev/mward4/MusicBot/releases) with the pull command, what changed, and the JAR for non-Docker installs. To upgrade an Unraid container, change the tag and apply; `config.txt`, `serversettings.json` and `Playlists/` live in the appdata mount and carry over. The config format is versioned and migrates itself on start. ## What's different in 0.7.1 These are purnell569's notes for the release this copy is built from. YouTube changed how it serves streams, which broke playback for everyone on the upstream 0.7.0 release. This version fixes that: - **Signature cipher is no longer tied to OAuth.** Deciphering and authentication are unrelated concerns, but the cipher was only applied when OAuth was on — so the default install fell back to the bundled extractor and died with `Must find sig function from script: /s/player/…`. It is now always applied and configurable via `playback.youtube.remoteCipher.url`. - **Added the ANDROID client and reordered the client list by reliability.** ANDROID is currently the only client YouTube reliably streams to anonymously; WEB now sits last because YouTube answers it with SABR-only responses that contain no playable format. - **Sign-in failures are now reported usefully.** The existing hint could never fire: it matched on the aggregate exception message rather than the per-client reasons, and compared against an ASCII apostrophe while YouTube sends `’` (U+2019). - **youtube-source pinned past 1.18.2**, which predates the fixes for the TV client User-Agent and for formats that omit `contentLength`. Measured on the tracks that were failing: **5/5 playing, stable across repeat runs** (previously 1/5). No OAuth or Google account required. ## Requirements Inside the container all of this is already handled. It matters when running the JAR directly. - **Java 25 or newer.** - **glibc 2.38 or newer** for the JDave/udpqueue native libraries. Ubuntu 24.04 "Noble" and Debian 13 "Trixie" qualify; check with `ldd --version`. On Debian/Ubuntu you may also need `libopus0` and `libsodium23`. - **Message Content Intent** enabled in the Discord Developer Portal (see [Unraid](#unraid)). [![Setup](http://i.imgur.com/VvXYp5j.png)](https://jmusicbot.com/setup) ## Features - Easy to run (just make sure Java is installed, and run!) - Fast loading of songs - No external keys needed (besides a Discord Bot token) - Smooth playback - Server-specific setup for the "DJ" role that can moderate the music - Clean and beautiful menus - Supports many sites, including YouTube, SoundCloud, and more - Supports many online radio/streams - Supports local files - Playlist support (both web/youtube, and local) ## Supported sources and formats Everything [lavaplayer](https://github.com/lavalink-devs/lavaplayer#supported-formats) supports: - **Sources:** YouTube, SoundCloud, Bandcamp, Vimeo, Twitch streams, local files, HTTP URLs - **Formats:** MP3, FLAC, WAV, Matroska/WebM (AAC, Opus or Vorbis), MP4/M4A (AAC), OGG streams (Opus, Vorbis and FLAC), AAC streams, stream playlists (M3U and PLS) ![Loading Example...](https://i.imgur.com/kVtTKvS.gif) ## Running directly (without Docker) The JAR for each version is attached to its [release](https://gitea.milesward.dev/mward4/MusicBot/releases) as `JMusicBot-.zip` (Gitea does not allow `.jar` attachments; unzip it) with a `SHA256SUMS.txt` beside it. Then, with Java 25 on the path: **Linux / macOS / Windows (CMD):** ```bash java -Dfile.encoding=UTF-8 -Dnogui=true --enable-native-access=ALL-UNNAMED -jar JMusicBot-0.7.1.jar ``` **Windows (PowerShell):** PowerShell treats `-D` as its own parameter, so quote each option: ```powershell java "-Dfile.encoding=UTF-8" "-Dnogui=true" "--enable-native-access=ALL-UNNAMED" "-jar" ".\JMusicBot-0.7.1.jar" ``` `-Dfile.encoding=UTF-8` keeps non-English characters (Cyrillic, Japanese, …) intact in Discord. See the [Setup Page](https://jmusicbot.com/setup) and [Config reference](https://jmusicbot.com/config) for `config.txt`. ## Docker notes - **Config persistence.** `/musicbot` is the container's working directory and **must** be mounted; `config.txt`, `serversettings.json` and `Playlists/` are read and written there. - **User.** The image's own user is `jmusicbot` (UID 10001). Either make the mounted directory writable by 10001 or pass `--user` (the Unraid template does the latter with `99:100`). - **JAVA_OPTS.** The entrypoint starts the JVM with `-XX:+UseZGC -XX:+AlwaysPreTouch`. Set `JAVA_OPTS` to replace that, e.g. `-Xms256m -Xmx512m -XX:+UseZGC -XX:+AlwaysPreTouch` to cap the heap. - **Image contents.** A jlink-trimmed Java 25 runtime on `bitnami/minideb:trixie` (glibc 2.41) and the shaded JAR built with the `docker` Maven profile, which drops the Windows and macOS natives. Labels: `org.opencontainers.image.revision` (commit) and `.version`. Published images: ## Performance tuning For optimal audio quality with minimal stuttering, the following JVM and configuration options are recommended. ### JVM flags The bot works best with ZGC (Z Garbage Collector), which provides sub-millisecond pause times: ```bash java -Dfile.encoding=UTF-8 \ -XX:+UseZGC \ -XX:+AlwaysPreTouch \ -Dnogui=true \ --enable-native-access=ALL-UNNAMED \ -jar JMusicBot-0.7.1.jar ``` - `-XX:+UseZGC`: sub-millisecond GC pauses (generational mode is default in JDK 24+) - `-XX:+AlwaysPreTouch`: pre-allocates memory at startup to avoid page faults - `-Xms` / `-Xmx`: optional; fix or cap the heap (e.g. `-Xms256m -Xmx512m`) The Docker image uses ZGC and AlwaysPreTouch by default; `JAVA_OPTS` overrides. ### Audio buffers Configurable buffers in `config.txt` protect against GC pauses. Higher values add latency; the defaults suit most setups. ```hocon performance { # NAS buffer duration in ms (protects against JVM pauses up to this duration) nasBufferMs = 800 # Lavaplayer frame buffer duration in ms (amount of decoded audio to buffer) frameBufferMs = 2000 } ``` ## Proxy configuration Specific components can be routed through an HTTP proxy while others connect directly — useful for proxying audio traffic without touching Discord API traffic. Add to `config.txt`: ```hocon proxy { host = "127.0.0.1" port = 8080 lavaplayer = true # Audio source requests (YouTube, SoundCloud, etc.) jda = false # Discord API traffic github = false # Version check requests } ``` Leave `host` empty or `port` at 0 to disable. SOCKS proxies are not supported. ## Development and publishing There is no Java toolchain requirement on the workstation; the build runs in a container: ```bash docker run --rm -v "$PWD":/build -w /build -v musicbot-m2:/root/.m2 maven:3.9.12-eclipse-temurin-25-alpine mvn -B -ntp verify ``` That is what CI runs on every push to `main`. Cutting a release — tag, image build, registry push, Gitea release with the JAR attached — is documented step by step in [docs/PUBLISHING.md](docs/PUBLISHING.md); `scripts/build-and-publish-unraid.sh` does the image part in one pass. Keeping up with upstream: ```bash git fetch upstream --tags git merge upstream/main ``` `upstream` is `purnell569/MusicBot` on GitHub. Their [DEVELOPMENT_WORKFLOW.md](docs/DEVELOPMENT_WORKFLOW.md) and [ARCHITECTURE.md](docs/ARCHITECTURE.md) are kept as-is for reference; the GitHub Actions and `ghcr.io` specifics in the former do not apply to this repository. ## Questions, bug reports, credits Problems with the bot itself — playback, commands, config — are almost always upstream's to fix and are best raised at [arif-banai/MusicBot](https://github.com/arif-banai/MusicBot/issues) or [purnell569/MusicBot](https://github.com/purnell569/MusicBot/issues). Anything specific to this copy (the image, the Unraid template, CI, publishing) belongs in [this repository's issues](https://gitea.milesward.dev/mward4/MusicBot/issues). The libraries that make the bot possible deserve the stars: - [**JDA**](https://github.com/discord-jda/JDA) - [**lavaplayer**](https://github.com/lavalink-devs/lavaplayer) - [**youtube-source**](https://github.com/lavalink-devs/youtube-source) ### Editing This bot (and the source code here) might not be easy to edit for inexperienced programmers. The main purpose of having the source public is to show the capabilities of the libraries, to allow others to understand how the bot works, and to allow those knowledgeable about Java, JDA, and Discord bot development to contribute. If you choose to make edits, please do so in accordance with the Apache 2.0 License.