Build and Test / Build and Test (push) Canceled after 1m24s
Fork of purnell569/MusicBot 0.7.1 (JMusicBot), kept here as a reliable copy with a container image built and served from this Gitea. - README retitled "$uicide Music Bot"; lineage table, Gitea image, Unraid and release instructions. Nothing under src/ changes. - Dockerfile: Maven stage on $BUILDPLATFORM (JAR is arch-neutral, so no QEMU for the build), OCI labels point at this repo and record commit and version via GIT_SHA/VERSION build args. - docker/entrypoint.sh: check the data dir is writable up front (the bot's own error for that is a misleading "another instance is running"), and on a missing config.txt run the bot's generate-config and stop with instructions instead of prompting on a console that does not exist. - deploy/unraid/musicbot.xml: Unraid template, --user 99:100 default. - .gitea/workflows/build-and-test.yml: mvn verify + docker build on push; its presence makes Gitea ignore the GitHub-only workflows in .github/. - scripts/build-and-publish-unraid.sh + docs/PUBLISHING.md: release runbook (keychain-safe registry push, release with zipped JAR). - docker-compose.example.yml points at the Gitea image. Upstream's v0.7.1 tag is preserved as upstream/v0.7.1; this repository's own release tag v0.7.1 is on this commit. Co-Authored-By: Claude Fable 5.1 <[email protected]>
345 lines
15 KiB
Markdown
345 lines
15 KiB
Markdown
<p align="center">
|
||
<img src="https://i.imgur.com/zrE80HY.png" alt="$uicide Music Bot" width="180">
|
||
</p>
|
||
|
||
<h1 align="center">$uicide Music Bot</h1>
|
||
|
||
<p align="center">
|
||
<strong>A self-hosted Discord music bot with a clean interface — built from source and served from this Gitea, ready for Unraid.</strong>
|
||
</p>
|
||
|
||
<p align="center">
|
||
<img alt="release" src="https://img.shields.io/gitea/v/release/mward4/MusicBot?gitea_url=https%3A%2F%2Fgitea.milesward.dev&sort=semver&label=release&color=4d6bfe" />
|
||
<img alt="ci" src="https://gitea.milesward.dev/mward4/MusicBot/actions/workflows/build-and-test.yml/badge.svg?branch=main" />
|
||
<img alt="java" src="https://img.shields.io/badge/java-25-007396?logo=openjdk&logoColor=white" />
|
||
<img alt="license" src="https://img.shields.io/badge/license-Apache--2.0-330f1f" />
|
||
</p>
|
||
|
||
---
|
||
|
||
> [!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/<tag>` (`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)).
|
||
|
||
[](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)
|
||
|
||

|
||
|
||
## Running directly (without Docker)
|
||
|
||
The JAR for each version is attached to its
|
||
[release](https://gitea.milesward.dev/mward4/MusicBot/releases) as `JMusicBot-<version>.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: <https://gitea.milesward.dev/mward4/-/packages/container/musicbot>
|
||
|
||
## 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.
|