208 lines
9.4 KiB
Markdown
208 lines
9.4 KiB
Markdown
<div align="center">
|
||
<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>
|
||
|
||
---
|
||
|
||
## Features
|
||
|
||
- Music playback from YouTube via slash commands
|
||
- Dice rolling with D&D notation (e.g. `/roll 2d6+3`)
|
||
- Session scheduling
|
||
- REST API with OAuth2 authentication
|
||
|
||
---
|
||
|
||
## Prerequisites
|
||
|
||
### Running with Docker (recommended)
|
||
|
||
| Tool | Notes |
|
||
|-----------------------------------|---------------------------------------------|
|
||
| [Docker](https://www.docker.com/) | Required |
|
||
| [Task](https://taskfile.dev/) | Optional — used to run convenience commands |
|
||
|
||
### Running locally (development)
|
||
|
||
| 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 |
|
||
|
||
> **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` | | PostgreSQL port (default `5432`) |
|
||
| `VALKEY_HOST` | | Valkey host (`localhost` for local dev, `siren-valkey` in Docker) |
|
||
| `VALKEY_PORT` | | Valkey port (default `6379`) |
|
||
| `API_BASE_URL` | Yes | Base URL of the API (e.g. `http://localhost:3000`) |
|
||
| `API_PORT` | | Port the REST API listens on (default `3000`) |
|
||
| `API_SESSION_TTL` | | OAuth2 session TTL in seconds (default `86400`) |
|
||
| `CORS_ORIGIN` | | Allowed CORS origin (`*` for dev, specific URL for production) |
|
||
| `UI_PORT` | | Port the UI dev server listens on (default `5173`) |
|
||
| `RUST_LOG` | | Log filter (e.g. `warn,siren=info`) |
|
||
| `FORCE_COMMAND_REGISTER` | | Re-register slash commands with Discord on every startup (`true`/`false`) |
|
||
| `DATA_DIR_PATH` | | Path to optional local data directory |
|
||
| `DEFAULT_API_KEY` | | Seed API key created on startup |
|
||
| `DEFAULT_GUILD_ID` | | Seed Discord guild (server) ID |
|
||
| `DEFAULT_USER_ID` | | Seed Discord 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.
|
||
|
||

|
||
|
||
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
|
||
```
|
||
|
||
---
|
||
|
||
## Running
|
||
|
||
### Docker (recommended)
|
||
|
||
Build and start all containers:
|
||
|
||
```bash
|
||
# Build the Docker image
|
||
task docker:build
|
||
# or: docker build -f Dockerfile -t siren:latest .
|
||
|
||
# Start all services (postgres, valkey, and the app)
|
||
task docker:up:all
|
||
# or: docker compose --profile app up -d
|
||
```
|
||
|
||
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 <0–100>` | Set the playback volume | Done |
|
||
| `/queue` | Display the current queue | Done |
|
||
| `/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.
|