diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
new file mode 100644
index 000000000..759818b0d
--- /dev/null
+++ b/.github/workflows/docker.yml
@@ -0,0 +1,73 @@
+name: Docker
+
+on:
+ push:
+ branches:
+ - "master"
+ - "feature/docker"
+ - "translation/chinese"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Get repo name
+ id: repo_name
+ run: |
+ echo ::set-output name=name::"ghcr.io/${{ github.repository }}" | tr '[:upper:]' '[:lower:]'
+
+ - name: Docker Setup Qemu
+ uses: docker/setup-qemu-action@v3
+
+ - name: Docker Setup Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Docker Login
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.repository_owner }}
+ password: ${{ secrets.CR_PAT }}
+
+ - name: Docker Cache
+ uses: actions/cache@v4
+ with:
+ path: /tmp/.buildx-cache
+ key: ${{ runner.os }}-buildx-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.os }}-buildx-
+
+ - name: Docker Metadata
+ id: meta
+ uses: docker/metadata-action@v5
+ with:
+ images: ${{ steps.repo_name.outputs.name }}
+ tags: |
+ type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }}
+ type=raw,value=${
+ startsWith(github.ref, 'refs/heads/') && contains(github.ref, '/')
+ && format('{0}', github.ref.split('/')[-1]) || github.ref
+ },enable=${{ startsWith(github.ref, 'refs/heads/') }}
+ type=sha
+
+ - name: Docker Build and Push
+ uses: docker/build-push-action@v6
+ with:
+ context: .
+ file: ./Dockerfile
+ push: true
+ tags: ${{ steps.meta.outputs.tags }}
+ labels: ${{ steps.meta.outputs.labels }}
+ platforms: |
+ linux/amd64,
+ linux/arm64
+
+ cache-from: |
+ type=local,src=/tmp/.buildx-cache
+
+ cache-to: |
+ type=local,dest=/tmp/.buildx-cache
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 000000000..b3bbb57d3
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,43 @@
+# ---------------------------------------------
+# Build JDA-Utilities
+FROM maven:3.8.6-openjdk-11 AS jda-builder
+
+WORKDIR /app
+
+RUN git clone https://github.com/JDA-Applications/JDA-Utilities ./ \
+ && git checkout c16a4b264b7dc492b35e65cb295aec9980d186b2 \
+ && chmod +x ./gradlew \
+ && ./gradlew clean \
+ && ./gradlew build \
+ && ./gradlew publishToMavenLocal
+
+# ---------------------------------------------
+# Build JMusicBot
+FROM maven:3.8.5-openjdk-17 AS builder
+
+WORKDIR /app
+ADD . .
+
+COPY --from=jda-builder /root/.m2/repository /root/.m2/repository
+COPY --from=jda-builder /app/build/libs /root/.m2/repository/com/jagrosh/jda-utilities/3.1.0
+
+RUN mvn clean
+RUN mvn install
+
+# ---------------------------------------------
+# Create final image with only runtime dependencies
+FROM debian:12.7-slim
+
+WORKDIR /app
+
+COPY --from=builder /app/target/JMusicBot-Snapshot-All.jar /app/JMusicBot.jar
+
+RUN apt-get update \
+ && apt-get install -y openjdk-17-jre-headless \
+ && apt-get install -y locales \
+ && rm -rf /var/lib/apt/lists/* \
+ && localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8
+
+ENV LANG en_US.utf8
+
+CMD [ "/usr/bin/java", "-Dnogui=true", "-Dconfig.override_with_env_vars=true", "-jar", "/app/JMusicBot.jar" ]
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 000000000..4046b7de2
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,12 @@
+services:
+ jagrosh-musicbot:
+ image: ghcr.io/lynbean/jagrosh-musicbot:latest
+ container_name: jmusicbot
+ restart: always
+ volumes:
+ - ./data:/app/data
+ environment:
+ # https://github.com/jagrosh/MusicBot/wiki/Getting-a-Bot-Token
+ CONFIG_FORCE_token: BOT_TOKEN_HERE
+ # https://github.com/jagrosh/MusicBot/wiki/Finding-Your-User-ID
+ CONFIG_FORCE_owner: 0
diff --git a/pom.xml b/pom.xml
index b8b350654..d447c1266 100644
--- a/pom.xml
+++ b/pom.xml
@@ -47,8 +47,7 @@
com.jagrosh
jda-utilities
- 3.0.5
- pom
+ 3.1.0
@@ -60,7 +59,7 @@
dev.lavalink.youtube
common
- 1.5.2
+ 1.7.2
com.github.jagrosh
@@ -82,7 +81,7 @@
com.typesafe
config
- 1.3.2
+ 1.4.2
org.jsoup
@@ -149,7 +148,7 @@
UTF-8
- 11
- 11
+ 17
+ 17
diff --git a/src/main/java/com/jagrosh/jmusicbot/BotConfig.java b/src/main/java/com/jagrosh/jmusicbot/BotConfig.java
index f6a8757ac..24409c015 100644
--- a/src/main/java/com/jagrosh/jmusicbot/BotConfig.java
+++ b/src/main/java/com/jagrosh/jmusicbot/BotConfig.java
@@ -106,6 +106,13 @@ public void load()
// validate bot token
if(token==null || token.isEmpty() || token.equalsIgnoreCase("BOT_TOKEN_HERE"))
{
+ if(OtherUtil.inDockerContainer())
+ {
+ prompt.alert(Prompt.Level.WARNING, CONTEXT,
+ "No token provided! Exiting.\n\nPlease set the token in an environment variable named `CONFIG_FORCE_token`"
+ );
+ return;
+ }
token = prompt.prompt("Please provide a bot token."
+ "\nInstructions for obtaining a token can be found here:"
+ "\nhttps://github.com/jagrosh/MusicBot/wiki/Getting-a-Bot-Token."
@@ -126,6 +133,13 @@ public void load()
{
try
{
+ if(OtherUtil.inDockerContainer())
+ {
+ prompt.alert(Prompt.Level.ERROR, CONTEXT,
+ "Invalid User ID! Exiting.\n\nPlease set the Owner ID in an environment variable named `CONFIG_FORCE_owner`"
+ );
+ return;
+ }
owner = Long.parseLong(prompt.prompt("Owner ID was missing, or the provided owner ID is not valid."
+ "\nPlease provide the User ID of the bot's owner."
+ "\nInstructions for obtaining your User ID can be found here:"
@@ -146,8 +160,8 @@ public void load()
write = true;
}
}
-
- if(write)
+
+ if(write || !path.toFile().exists())
writeToFile();
// if we get through the whole config, it's good to go
diff --git a/src/main/java/com/jagrosh/jmusicbot/utils/OtherUtil.java b/src/main/java/com/jagrosh/jmusicbot/utils/OtherUtil.java
index c0dd5b357..1c53dba1f 100644
--- a/src/main/java/com/jagrosh/jmusicbot/utils/OtherUtil.java
+++ b/src/main/java/com/jagrosh/jmusicbot/utils/OtherUtil.java
@@ -57,6 +57,11 @@ public class OtherUtil
public static Path getPath(String path)
{
Path result = Paths.get(path);
+ if(inDockerContainer())
+ {
+ // for docker mounting, the saved folder has to be separated from the jar file
+ result = Paths.get("data", path);
+ }
// special logic to prevent trying to access system32
if(result.toAbsolutePath().toString().toLowerCase().startsWith(WINDOWS_INVALID_PATH))
{
@@ -230,4 +235,14 @@ public static String getUnsupportedBotReason(JDA jda)
return null;
}
+
+ /**
+ * Check if the program is running inside a docker container
+ * @return Boolean
+ */
+ public static Boolean inDockerContainer()
+ {
+ File dockerenv = new File("/.dockerenv");
+ return dockerenv.exists();
+ }
}