Major refactor

This commit is contained in:
2026-04-03 23:04:51 -04:00
parent e7f337c735
commit 35d07e8df1
124 changed files with 4929 additions and 2429 deletions

285
README.md
View File

@@ -1,130 +1,205 @@
<div align="center">
<img src="docs/siren.png" alt="drawing" width="200"/>
<img src="docs/siren.png" alt="Siren" width="200"/>
<h1 align="center">Siren</h1>
<p>A D&D-focused Discord bot written in Rust</p>
</div>
Siren is a D&D Bot built for Discord, written in Rust. Features include:
- Music commands from Youtube and locally hosted files
- Database for D&D 5e content
---
## Features
- Music playback from YouTube via slash commands
- Dice rolling with D&D notation (e.g. `/roll 2d6+3`)
- Session scheduling
- Backend API
- ChatGPT integration
- REST API with OAuth2 authentication
## Requirements
- [Docker](https://www.docker.com/)
- **Optional**: [Docker Compose](https://docs.docker.com/compose/install/)
---
## Running
1. Setup the Discord Developer Application and bot
2. Create `.env.local` and override any variables from `.env`
- At minimum, `DISCORD_TOKEN` must be set. See [instructions](#setup-discord-developer-application) for additional steps.
3. Build the Docker application with `make build`
4. Start the application with `make up`
## Prerequisites
<h3 id='setup-discord-developer-application'>Setting up the Discord Developer Application</h3>
### Running with Docker (recommended)
Visit the [Discord Developer Portal](https://discord.com/developers/applications) and create a new application. Click [here](https://discord.com/developers/docs/intro) for guides and more information.
| Tool | Notes |
|-----------------------------------|---------------------------------------------|
| [Docker](https://www.docker.com/) | Required |
| [Task](https://taskfile.dev/) | Optional — used to run convenience commands |
#### Oauth2
**Required Scopes**:
- bot
- applications.commands
### Running locally (development)
**Required Bot Permissions**:
- General Permissions
- Manage Roles
- Change Nickname
- View Channels
- Manage Events
- Create Events
- Text Permissions
- Send Messages
- Create Public Threads
- Create Private Threads
- Send Messages in Threads
- Manage Messages
- Manage Threads
- Embed Links
- Attach Files
- Read Message History
- Mention Everyone
- Use External Emojis
- Use External Stickers
- Add Reactions
- Create Polls
- Voice Permissions
- Connect
- Speak
| Tool | Notes |
|---------------------------------------------------|---------------------------------------------|
| [Rust](https://www.rust-lang.org/tools/install) | Stable toolchain |
| [yt-dlp](https://github.com/yt-dlp/yt-dlp) | Audio source extraction |
| [ffmpeg](https://github.com/yt-dlp/FFmpeg-Builds) | Audio transcoding |
| [Docker](https://www.docker.com/) | Used to run PostgreSQL and Valkey |
| [Task](https://taskfile.dev/) | Optional — used to run convenience commands |
Example Invites:
```
https://discord.com/api/oauth2/authorize?client_id=<CLIENT_ID>&permissions=40671259392832&scope=bot%20applications.commands
> **yt-dlp note:** Keep yt-dlp up to date. YouTube frequently rotates its player,
> and an outdated yt-dlp will fail to resolve stream URLs.
---
## Configuration
Copy `.env.example` to `.env` and fill in the required values:
```bash
cp .env.example .env
# or using Task:
task setup
```
### Environment variables
| Variable | Required | Description |
|-------------------------|----------|-------------------------------------------------------------------------|
| `DISCORD_BOT_TOKEN` | Yes | Bot token from the Discord Developer Portal |
| `DISCORD_CLIENT_SECRET` | Yes | OAuth2 client secret |
| `JWT_SECRET` | Yes | Secret used to sign JWT tokens — change from default |
| `POSTGRES_USER` | Yes | PostgreSQL username |
| `POSTGRES_PASSWORD` | Yes | PostgreSQL password — change from default |
| `POSTGRES_DB` | Yes | PostgreSQL database name |
| `POSTGRES_HOST` | Yes | PostgreSQL host (`localhost` for local dev, `siren-postgres` in Docker) |
| `POSTGRES_PORT` | Yes | PostgreSQL port (default `5432`) |
| `VALKEY_HOST` | Yes | Valkey host (`localhost` for local dev, `siren-valkey` in Docker) |
| `VALKEY_PORT` | Yes | Valkey port (default `6379`) |
| `API_PORT` | Yes | Port the REST API listens on (default `3000`) |
| `API_CALLBACK_URI` | Yes | OAuth2 redirect URI (e.g. `http://localhost:3000/api/oauth/callback`) |
| `API_SESSION_TTL` | | OAuth2 session TTL in seconds (default `86400`) |
| `RUST_LOG` | | Log filter (e.g. `warn,siren=info`) |
| `FORCE_REGISTER` | | Re-register slash commands on every startup (`true`/`false`) |
| `DATA_DIR_PATH` | | Path to optional local data directory |
| `DEFAULT_API_KEY` | | Seed API key created on startup |
| `DEFAULT_SERVER` | | Seed guild ID |
| `DEFAULT_USER` | | Seed user ID |
---
## Discord Application Setup
1. Visit the [Discord Developer Portal](https://discord.com/developers/applications) and create a new application.
2. Go to the **Bot** tab:
- Click **Reset Token** to generate your bot token — this is your `DISCORD_BOT_TOKEN`.
- Enable **Message Content Intent** under Privileged Gateway Intents.
![Token location](docs/discord_token_example.png)
3. Go to the **OAuth2** tab to find your **Client Secret** (`DISCORD_CLIENT_SECRET`).
### Invite the bot to your server
**Required scopes:** `bot`, `applications.commands`
**Required permissions:**
| Category | Permissions |
|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| General | Manage Roles, Change Nickname, View Channels, Manage Events, Create Events |
| Text | Send Messages, Create Public/Private Threads, Send Messages in Threads, Manage Messages, Manage Threads, Embed Links, Attach Files, Read Message History, Mention Everyone, Use External Emojis/Stickers, Add Reactions, Create Polls |
| Voice | Connect, Speak |
Use this invite URL (replace `<CLIENT_ID>` with your Application ID from the General Information tab):
```
https://discord.com/oauth2/authorize?client_id=<CLIENT_ID>&permissions=581083641408576&integration_type=0&scope=bot+applications.commands
```
The CLIENT_ID can be found in the General Information tab on the Discord Developer Portal for your application, under `Application ID`
---
The DISCORD_TOKEN (used in the `.env file`) can be found under the Bot tab on the Discord Developer Portal for your application.
## Running
![DISCORD_TOKEN Example](docs/discord_token_example.png)
### Docker (recommended)
### Commands
Siren utilizes Discord slash commands. To view the commands, run `/help` in a server where the bot is installed. The following commands are available:
Build and start all containers:
**Music Commands**
| Command | Description |
| --- | --- |
| `/play <Track>` | Play a track from Youtube or locally hosted files |
| `/pause` | Pause the current track |
| `/resume` | Resume the current track |
| `/skip` | Skip the current track |
| `/stop` | Stop the current track |
| `/mute` | Mute the current track |
| `/queue` | ***TODO*** - Display the current queue |
| `/clear` | ***TODO*** - Clear the current queue |
| `/shuffle` | ***TODO*** - Shuffle the current queue |
| `/loop` | ***TODO*** - Loop or unloop the current track |
| `/nowplaying` | ***TODO*** - Display the current track |
| `/volume <Volume>` | Set the volume of the bot |
```bash
# Build the Docker image
task docker:build
# or: docker build -f Dockerfile -t siren:latest .
**Event Commands**
| Command | Description |
| --- | --- |
| `/schedule` | ***TODO*** - Schedule a new event |
| `/events` | ***TODO*** - Display all events |
| `/event <Event ID>` | ***TODO*** - Display a specific event |
| `/deleteevent <Event ID>` | ***TODO*** - Delete a specific event |
| `/updateevent <Event ID>` | ***TODO*** - Update a specific event |
| `/remindme <Event ID>` | ***TODO*** - Set a reminder for a specific event |
**Fun Commands**
| Command | Description |
| --- | --- |
| `/coinflip` | Flip a coin |
| `/roll <Dice>` | Roll a dice |
| `/requestroll <User> <Dice>` | Request a dice roll from a user |
**Utility Commands**
| Command | Description |
| --- | --- |
| `/ping` | Display the bot's latency |
| `/poll` | ***TODO*** - Create a poll |
| `/help` | ***TODO*** - Display a list of commands |
## Contributing
- [Rust](https://www.rust-lang.org/)
- [yt-dlp](https://github.com/yt-dlp/yt-dlp)
- [ffmpeg](https://github.com/yt-dlp/FFmpeg-Builds)
### Running Locally
1. Start the backend containers with `make backend-up`
2. Run the application locally with `make run`
The application can also be tested from within a Docker container:
# Start all services (postgres, valkey, and the app)
task docker:up:all
# or: docker compose --profile app up -d
```
make docker-build
make docker-up
To stop everything:
```bash
task docker:down
# or: docker compose --profile app down
```
### Local development
Start the backing services (PostgreSQL and Valkey) in Docker, then run the bot natively:
```bash
# Start only the infrastructure containers
task docker:up
# or: docker compose up -d
# Run the bot locally with trace-level logging
task run
# or: cargo run
```
---
## Commands
Siren uses Discord slash commands.
### Music
| Command | Description | Status |
|-------------------|-------------------------------------|---------|
| `/play <track>` | Play a track from YouTube | Done |
| `/pause` | Pause the current track | Done |
| `/resume` | Resume the current track | Done |
| `/skip` | Skip to the next track | Done |
| `/stop` | Stop playback and clear the queue | Done |
| `/mute` | Mute/unmute the bot | Done |
| `/volume <0100>` | Set the playback volume | Done |
| `/queue` | Display the current queue | Planned |
| `/nowplaying` | Display the currently playing track | Planned |
| `/shuffle` | Shuffle the queue | Planned |
| `/loop` | Toggle looping the current track | Planned |
| `/clear` | Clear the queue | Planned |
### Events
| Command | Description | Status |
|-------------|------------------------------|---------|
| `/schedule` | Schedule a new event | Planned |
| `/events` | Display all scheduled events | Planned |
### Fun
| Command | Description | Status |
|------------------------------|---------------------------------------|--------|
| `/roll <dice>` | Roll dice (e.g. `2d6+3`) | Done |
| `/requestroll <user> <dice>` | Request a dice roll from another user | Done |
### Utility
| Command | Description | Status |
|---------|----------------------------|---------|
| `/ping` | Check the bot's latency | Done |
| `/help` | Display available commands | Planned |
---
## Development
| Task | Command |
|------------------------|----------------|
| Type-check (fast) | `task check` |
| Debug build | `task build` |
| Release build | `task release` |
| Run with trace logging | `task run` |
| Format code | `task format` |
| Lint (Clippy) | `task lint` |
| Clean build artifacts | `task clean` |
| Connect to database | `task psql` |
Run `task` with no arguments to list all available tasks.