A Discord bot for requesting media through *arr backends, written in Rust.
Each backend you configure creates a /request <media> slash command. You can have as many backends as you want — point two Radarr configs at the same instance with different quality profiles to get /request movie and /request movie_4k, for example.
Go to the Discord Developer Portal, create a new application, then go to the Bot tab and create a bot. Copy the token — you'll need it in your config.
Under OAuth2 → URL Generator, select scopes bot and applications.commands. If you want request confirmations to be visible to everyone (not just the requester), also add the Send Messages bot permission. Use the generated URL to invite the bot to your server.
- Sonarr / Radarr: Settings → General → Security → API Key
- Seerr: Settings → API Key — must be an admin key
Seerr users must link their Discord account. In Seerr, go to Settings → Notifications → Discord and enable the Discord notification agent. Once that's on, a Discord User ID field appears on each user's profile page. Users need to enter their Discord User ID there before they can make requests. If a user hasn't done this and you haven't set
fallback_user_id, their requests will be rejected.
Create a config.toml — see the full example below — then run the bot:
# Docker (recommended)
docker run -d \
--name doplarr \
--restart unless-stopped \
-v /path/to/config.toml:/config.toml:ro \
ghcr.io/activexray/doplarr_rs:latestOr with Docker Compose:
services:
doplarr:
image: ghcr.io/activexray/doplarr_rs:latest
container_name: doplarr
restart: unless-stopped
volumes:
- ./config.toml:/config.toml:roCommands register automatically when the bot starts. If they don't show up immediately, wait a minute or restart Discord.
See config.example.toml for a complete reference.
# Required
discord_token = "YOUR_DISCORD_BOT_TOKEN"
# Optional: logging level (default: "info")
# Can be "info", "debug", "doplarr=debug,twilight_gateway=warn", etc.
log_level = "doplarr=info"
# Optional: make request confirmations visible to everyone in the channel (default: true)
# Set to false to keep all responses ephemeral. Requires "Send Messages" permission when true.
public_followup = true
# ============================================================================
# BACKENDS
# ============================================================================
# Each [[backends]] entry creates a /request <media> slash command.
# "media" is the subcommand name — must be unique across all backends.
#
# Optional settings (quality_profile, rootfolder, etc.) prompt the user at
# request time if omitted. Specify them to skip those prompts.
[[backends]]
media = "movie"
[backends.config.Radarr]
url = "http://localhost:7878"
api_key = "your_radarr_api_key"
quality_profile = "HD-1080p" # must match exactly what's in Radarr settings
rootfolder = "/movies"
monitor_type = "movieOnly" # movieOnly, movieAndCollection, none
minimum_availability = "announced" # tba, announced, inCinemas, released
# Same Radarr instance, different quality profile → separate /request movie_4k command
[[backends]]
media = "movie_4k"
[backends.config.Radarr]
url = "http://localhost:7878"
api_key = "your_radarr_api_key"
quality_profile = "Ultra-HD"
rootfolder = "/movies/4k"
[[backends]]
media = "series"
[backends.config.Sonarr]
url = "http://localhost:8989"
api_key = "your_sonarr_api_key"
quality_profile = "WEB-1080p"
rootfolder = "/tv"
season_folders = true
series_type = "standard" # standard, daily, anime — omit to auto-detect from genres
allow_specials = false # offer Season 0 in the season picker
allow_all_seasons = true # offer "All Seasons" (all current + future); default true
[[backends]]
media = "anime"
[backends.config.Sonarr]
url = "http://localhost:8990"
api_key = "your_anime_sonarr_api_key"
series_type = "anime"
rootfolder = "/anime"
# Seerr handles movies and TV in a single backend entry.
# Requires an admin API key. Users must link their Discord User ID in Seerr
# (Profile → Settings → Notifications → Discord) or requests will be rejected.
# That field only appears once the Discord notification agent is enabled in
# Seerr's global settings (Settings → Notifications → Discord).
[[backends]]
media = "media"
[backends.config.Seerr]
url = "http://localhost:5055"
api_key = "your_seerr_admin_api_key"
# fallback_user_id = 1 # attribute unlinked users' requests to this Seerr user ID; omit to reject them
# allow_4k = true # show a Standard/4K quality choice (only enable if 4K servers are configured in Seerr)Any value in the config can pull from an environment variable with ${VAR},
handy for keeping secrets out of the file:
[backends.config.Seerr]
url = "${SEERR_URL}"
api_key = "${SEERR_API_KEY}"A referenced variable that isn't set is a startup error. Substitution applies
inside quoted strings and bare values, but ${...} in a # comment is ignored.
If the config path doesn't exist on startup, Doplarr either:
- Builds a config from environment variables and starts — when it detects a Discord token plus at least one backend (see migration below). The bot runs normally; it does not require a config file on disk.
- Otherwise writes a starter template to the path and exits, so you have something to edit.
The original Doplarr's environment variables are detected automatically, so an existing env-only deployment keeps working with no config file and no mounted volume — Doplarr builds the config from the environment on each start and runs. Just set the legacy variables:
| Setting | Variable |
|---|---|
| Discord token | DISCORD__TOKEN |
| Seerr / Overseerr | OVERSEERR__URL, OVERSEERR__API, OVERSEERR__DEFAULT_ID |
| Sonarr | SONARR__URL, SONARR__API |
| Radarr | RADARR__URL, RADARR__API |
| Log level | LOG_LEVEL |
services:
doplarr:
image: ghcr.io/activexray/doplarr_rs:latest
container_name: doplarr
restart: unless-stopped
# No volume needed — config is built from these on startup
environment:
DISCORD__TOKEN: your_discord_bot_token
OVERSEERR__URL: http://localhost:5055
OVERSEERR__API: your_seerr_api_keyDoplarr also writes the generated config.toml (wired to these variables via
${...}) when it can, so mounting a volume lets you keep and customize it. With
no volume it's simply rebuilt from the environment each start.
# /etc/systemd/system/doplarr.service
[Unit]
Description=Doplarr Discord Bot
After=network.target
[Service]
Type=simple
User=doplarr
Group=doplarr
ExecStart=/opt/doplarr/doplarr /opt/doplarr/config.toml
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now doplarrWith Nix:
nix build
nix run . /path/to/config.tomlWith Cargo (requires Rust, OpenSSL dev libraries, and pkg-config on Linux):
cargo build --release
./target/release/doplarr /path/to/config.tomlBot doesn't respond to commands
- Make sure you invited the bot with both
botandapplications.commandsscopes - Commands register on startup — wait a minute or restart Discord if they're missing
- Check logs for connection errors
Backend connection errors
- Test your API keys directly in the *arr web UI
- If running in Docker, make sure the container can reach your *arr services (check network/hostname)
- Quality profile names are case-sensitive and must match exactly what's in Sonarr/Radarr settings
Seerr: "user not found" or requests rejected
- Enable the Discord notification agent in Seerr (Settings → Notifications → Discord)
- Each user goes to their Seerr profile → Settings → Notifications → Discord and enters their Discord User ID
- Or set
fallback_user_idin your config to accept requests from unlinked users
Config parse errors
- Validate your TOML syntax (e.g. jsonformatter.org/toml-validator)
discord_tokenand at least one[[backends]]entry are required- Each backend's
mediavalue must be unique
See MIGRATING.md for a full config mapping from the old EDN format to TOML, renamed options, and what's been removed.
See README_DEVELOPER.md for adding new backends, generating API bindings, and contributing.
Licensed under either of Apache License 2.0 (LICENSE-APACHE) or MIT License (LICENSE-MIT) at your option.
- Twilight for Discord API bindings
- OpenAPI Generator for *arr API clients
