Integrates Radarr & Sonarr with Discord
(commands like !addmovie, !downloads) and transcodes downloads with ffmpeg.
It is a uv workspace of five packages — two shared libraries and three independently deployable services (each with its own config file and Docker image):
| Package | Import | What it is |
|---|---|---|
common |
wi1_bot.common |
shared logging + pushover helpers (library) |
arr |
wi1_bot.arr |
Radarr/Sonarr (pyarr) wrapper (library) |
wi1-bot |
wi1_bot.bot |
the Discord bot → image wthueb/wi1-bot |
webhook |
wi1_bot.webhook |
Arr download and Autobrr proxy API; owns the transcode queue and dispatches jobs → image wthueb/wi1-bot-webhook |
transcoder |
wi1_bot.transcoder |
replicable ffmpeg worker that pulls jobs from the webhook → image wthueb/wi1-bot-transcoder |
The three services all share one top-level wi1_bot namespace but ship as separate
distributions, so each image only contains the code (and dependencies) it needs.
Transcode workers claim leased jobs from the webhook over HTTP and can be scaled out
(docker compose up -d --scale wi1-bot-transcoder=3).
- Copy each service's
config.yaml.templateto its own config directory and fill it in:bot/config.yaml.template→bot/config.yamlwebhook/config.yaml.template→webhook/config.yamltranscoder/config.yaml.template→transcoder/config.yaml
- Point Radarr/Sonarr's connect webhook at the webhook service (
http://<host>:9000/). docker compose up -d(editcompose.yamlfor the media mount and GPU as needed).
git clone https://github.com/wthueb/wi1-bot.gitcd wi1-bot/uv syncuv run pre-commit install
Run a service locally with its config: WB_CONFIG_PATH=… uv run wi1-bot-webhook
(likewise wi1-bot, wi1-bot-transcoder). Tests/type-check: uv run pytest,
uv run ty check. Requires Python >=3.12.
End-to-end tests drive the whole transcoding pipeline (seeded Radarr/Sonarr → the
webhook → a transcoder worker) through real containers. They need Docker and are excluded
from the default uv run pytest; run them with uv run pytest -m e2e. See
tests/e2e/seed/README.md for the *arr fixtures and how to
regenerate them.
CI runs the Python checks before building containers. Container builds are distributed across native amd64 and arm64 runners; pull requests and manual runs exercise the exact amd64 webhook/transcoder images in the end-to-end suite. Successful branch, internal-PR, and version-tag runs assemble those immutable platform results into multi-platform images on Docker Hub and GHCR without rebuilding them.
- use seerr for search/requests
- !link discord user to seerr user
- fix ty errors, avoiding ignore comments where possible
- figure out qsv codecs
- also maybe software encoders?
- maybe check languages and things on new downloads via webhook
- notify on manual import required?
- transcode avis
- web dashboard? django i guess?
- transcode queue, transcode progress, quotas
- reactivity would be nice, maybe htmx/alpinejs?
- ffmpeg filters for deinterlacing, scaling
- have config.discord.users be a dict with 'quotas' and 'name' for *arr tags
- Better pushover notifications
- Failures for pretty much everything
- Notifications for grabs/downloads of personal watchlist
- Use Discord slash commands instead of normal text commands
- This is difficult/impossible currently, can't have "conversation" with slash commands
- Enforce quotas
- !linktmdb
- !rate / !ratings (https://developers.themoviedb.org/3/movies/rate-movie)
- !movierec based off of ratings and similar-to-user ratings?
- https://towardsdatascience.com/the-4-recommendation-engines-that-can-predict-your-movie-tastes-109dc4e10c52
- or just use TMDB's API to get recommendations (if that's possible?)
- User leaderboard
- movies/shows added, Tautulli watch counts