Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .copilotignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docker-compose.yml
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
node_modules
data
muse
dist
dts
.env
Dockerfile
.git
.gitignore
*.md
/*.sh
14 changes: 14 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Set default behavior for all files
* text=auto

# Force LF line endings for shell scripts
*.sh text eol=lf

# Force LF for other Unix-specific files
Dockerfile text eol=lf
*.yml text eol=lf
*.yaml text eol=lf

# Force CRLF for Windows-specific files
*.bat text eol=crlf
*.cmd text eol=crlf
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,8 @@ dist

# TernJS port file
.tern-port

docker-compose.yml
/muse

.vscode
28 changes: 18 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
# syntax=docker/dockerfile:1
FROM node:22-bookworm-slim AS base

# openssl will be a required package if base is updated to 18.16+ due to node:*-slim base distro change
# https://github.com/prisma/prisma/issues/19729#issuecomment-1591270599
# Install ffmpeg
# Install ffmpeg and yt-dlp (will be updated on container start)
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
ffmpeg \
tini \
openssl \
ca-certificates \
&& apt-get autoclean \
python3 \
python3-pip \
&& pip3 install --no-cache-dir --break-system-packages yt-dlp \
&& apt-get autoremove \
&& rm -rf /var/lib/apt/lists/*

Expand All @@ -21,28 +24,27 @@ WORKDIR /usr/app
# Add Python and build tools to compile native modules
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
python3 \
python-is-python3 \
build-essential \
&& apt-get autoclean \
&& apt-get autoremove \
&& rm -rf /var/lib/apt/lists/*

COPY package.json .
COPY yarn.lock .

RUN yarn install --prod
RUN --mount=type=cache,target=/root/.yarn \
YARN_CACHE_FOLDER=/root/.yarn yarn install --prod --frozen-lockfile
RUN cp -R node_modules /usr/app/prod_node_modules

RUN yarn install
RUN --mount=type=cache,target=/root/.yarn \
YARN_CACHE_FOLDER=/root/.yarn yarn install --frozen-lockfile

FROM dependencies AS builder

COPY . .

# Run tsc build
RUN yarn prisma generate
RUN yarn build
RUN yarn prisma generate && yarn build

# Only keep what's necessary to run
FROM base AS runner
Expand All @@ -52,8 +54,14 @@ WORKDIR /usr/app
COPY --from=builder /usr/app/dist ./dist
COPY --from=dependencies /usr/app/prod_node_modules node_modules
COPY --from=builder /usr/app/node_modules/.prisma/client ./node_modules/.prisma/client
COPY --from=builder /usr/app/scripts ./scripts

COPY . .
COPY schema.prisma .
COPY migrations ./migrations
COPY package.json .

# Make the startup script executable
RUN chmod +x scripts/start-with-ytdlp-update.sh

ARG COMMIT_HASH=unknown
ARG BUILD_DATE=unknown
Expand All @@ -64,4 +72,4 @@ ENV COMMIT_HASH=$COMMIT_HASH
ENV BUILD_DATE=$BUILD_DATE
ENV ENV_FILE=/config

CMD ["tini", "--", "node", "--enable-source-maps", "dist/scripts/migrate-and-start.js"]
CMD ["tini", "--", "./scripts/start-with-ytdlp-update.sh"]
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Muse is a **highly-opinionated midwestern self-hosted** Discord music bot **that
Muse is written in TypeScript. You can either run Muse with Docker (recommended) or directly with Node.js. Both methods require API keys passed in as environment variables:

- `DISCORD_TOKEN` can be acquired [here](https://discordapp.com/developers/applications) by creating a 'New Application', then going to 'Bot'.
- `SPOTIFY_CLIENT_ID` and `SPOTIFY_CLIENT_SECRET` can be acquired [here](https://developer.spotify.com/dashboard/applications) with 'Create a Client ID' (Optional).
- `SPOTIFY_CLIENT_ID` and `SPOTIFY_CLIENT_SECRET` can be acquired [here](https://developer.spotify.com/dashboard/applications) with 'Create a Client ID' (Optional). **Requires Spotify Premium** — omit these variables if you don't have a Premium account.
- `YOUTUBE_API_KEY` can be acquired by [creating a new project](https://console.developers.google.com) in Google's Developer Console, enabling the YouTube API, and creating an API key under credentials.

Muse will log a URL when run. Open this URL in a browser to invite Muse to your server. Muse will DM the server owner after it's added with setup instructions.
Expand Down Expand Up @@ -147,3 +147,16 @@ You can configure the bot to automatically turn down the volume when people are
- `/config set-reduce-vol-when-voice false` - Disable automatic volume reduction
- `/config set-reduce-vol-when-voice-target <volume>` - Set the target volume percentage when people speak (0-100, default is 70)

### Building from Source

To build and run Muse locally using Docker Compose:

1. Copy the example configuration: `cp docker-compose.example.yml docker-compose.yml`
2. Edit `docker-compose.yml` and populate the environment variables with your API keys and tokens
3. Build and start the container:

```bash
docker-compose up --build
```

This will build the latest version from source and start Muse with your local changes.
11 changes: 11 additions & 0 deletions docker-compose.example.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
services:
muse:
image: muse-local:latest
restart: always
volumes:
- ./muse:/data
environment:
- DISCORD_TOKEN=
- YOUTUBE_API_KEY=
- SPOTIFY_CLIENT_ID=
- SPOTIFY_CLIENT_SECRET=
9 changes: 4 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"@types/node-emoji": "^1.8.1",
"@types/spotify-web-api-node": "^5.0.2",
"@types/validator": "^13.12.2",
"@types/ws": "8.5.4",
"@types/ws": "^8.18.1",
"@typescript-eslint/eslint-plugin": "^4.31.1",
"@typescript-eslint/parser": "^4.31.1",
"eslint": "^7.32.0",
Expand Down Expand Up @@ -88,15 +88,14 @@
"@discordjs/builders": "1.1.0",
"@discordjs/opus": "^0.10.0",
"@discordjs/rest": "1.0.1",
"@discordjs/voice": "0.18.0",
"@distube/ytdl-core": "^4.16.10",
"@discordjs/voice": "0.19.1",
"@distube/ytsr": "^2.0.4",
"@prisma/client": "4.16.0",
"@types/libsodium-wrappers": "^0.7.9",
"array-shuffle": "^3.0.0",
"debug": "^4.3.3",
"delay": "^5.0.0",
"discord-api-types": "0.32.1",
"discord-api-types": "0.38.41",
"discord.js": "14.11.0",
"dotenv": "^16.4.5",
"execa": "^6.1.0",
Expand Down Expand Up @@ -131,7 +130,7 @@
"ytsr": "^3.8.4"
},
"resolutions": {
"@types/ws": "8.5.4"
"@types/ws": "8.18.1"
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
12 changes: 12 additions & 0 deletions scripts/start-with-ytdlp-update.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

# Update yt-dlp to latest version on startup
echo "🔄 Updating yt-dlp to latest version..."
pip3 install --no-cache-dir --break-system-packages --upgrade yt-dlp

# Check yt-dlp version
echo "📦 yt-dlp version: $(yt-dlp --version)"

# Start the bot
echo "🚀 Starting Muse bot..."
exec node --enable-source-maps dist/scripts/migrate-and-start.js
1 change: 0 additions & 1 deletion src/services/add-query-to-queue.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable complexity */
import {ChatInputCommandInteraction, GuildMember} from 'discord.js';
import {inject, injectable} from 'inversify';
import shuffle from 'array-shuffle';
Expand Down
Loading
Loading