- C# 66.2%
- TypeScript 25.9%
- JavaScript 5.3%
- CSS 2%
- HTML 0.2%
- Other 0.3%
Add --attach to theoriarr.sh: start services, tail -F all three logs, and run theoriarr-stop.sh on SIGINT/SIGTERM. The flake's run app passes --attach so 'nix run' behaves as a foreground dev session. Plain ./theoriarr.sh still backgrounds. Add coreutils/util-linux to the flake toolchain for tail/setsid. |
||
|---|---|---|
| Logo | ||
| portal | ||
| src | ||
| .gitignore | ||
| build.sh | ||
| flake.lock | ||
| flake.nix | ||
| gateway.js | ||
| PROGRESS.md | ||
| README.md | ||
| test.sh | ||
| theoriarr-stop.sh | ||
| theoriarr.sh | ||
Theoriarr
Movies and TV, together in one place.
Theoriarr combines Radarr and Sonarr into a single product repository. It manages movies, TV series, and anime, and keeps the unmodified Sonarr and Radarr HTTP APIs so existing integrations — in particular Jellyseerr / Overseerr — keep working.
What this is today
Theoriarr ships two self-contained services from one repo:
| Service | Derived from | Manages | UI port | API |
|---|---|---|---|---|
Theoriarr.Movies |
Radarr develop |
Movies, collections | 7878 |
/api/v3 (Radarr) |
Theoriarr.Series |
Sonarr v5-develop |
Series, seasons, episodes, anime | 8989 |
/api/v3, /api/v5 (Sonarr) |
A small gateway (:6868) serves a unified Theoriarr shell and mounts each
service under a path prefix on a single origin: /movies and /series. The shell
provides one entry point with a Movies/Series switcher and service status while
each engine keeps its own UI underneath. A fully native single-tree UI is the next
milestone.
Why two services?
Radarr and Sonarr are large, independently-evolved codebases that share a common
ancestor but define the same internal types (NzbDrone.Core.*). Running each as
its own process:
- guarantees byte-for-byte API compatibility (Jellyseerr does not need changes), and
- lets both APIs keep their native identity (
appName=Radarr/Sonarr), which Jellyseerr uses for auto-detection, and - keeps maintenance aligned with upstream.
A single-process backend and a single merged UI are planned follow-ups.
Quick start
Prerequisites
The sandbox bootstrap script installs everything into persistent /root locations:
bash /root/setup-toolchain.sh # .NET SDK 8 + 10, Node 24, Yarn 1.22
Build
./build.sh # backends + frontends for both services
SKIP_FRONTEND=1 ./build.sh # backends only
Run
./theoriarr.sh # starts Movies (:7878), Series (:8989) and the unified shell (:6868)
./theoriarr-stop.sh # stops everything
Open http://localhost:6868 for the unified UI. Each service also listens
directly (:7878, :8989) and redirects to its own prefix (/movies, /series).
theoriarr.sh prints the two API keys it discovers from each service's config —
use these when adding the services to Jellyseerr.
Test
./test.sh # unit tests (integration/automation excluded) for both trees
Nix
A flake.nix provides the whole toolchain (.NET SDK 8 + 10, Node 24,
Yarn 1.22, Python, curl, git) so you don't need setup-toolchain.sh:
nix develop # dev shell (build/test/run tools on PATH)
nix run .#build # build both backends and both frontends in place
nix build # build + install to ./result (backend, frontend, gateway, shell)
nix run # start everything in the foreground; streams logs, Ctrl+C stops
nix run .#test # run both unit-test suites
nix run .#stop # stop everything
Each tree pins its own SDK (src/Theoriarr.Movies/global.json → .NET 8,
src/Theoriarr.Series/global.json → .NET 10); the flake's dotnet wrapper picks the
right one from the nearest global.json, so nix develop + dotnet build works in
either tree.
nix build needs network (NuGet + the npm registry), so Nix must be configured with
the sandbox disabled (e.g. sandbox = false in nix.conf, the default for
single-user installs in containers).
Jellyseerr setup
- Start Theoriarr (
./theoriarr.sh). - In Jellyseerr, add a Radarr server:
- URL:
http://<theoriarr-host>:7878/movies - API key: printed by
./theoriarr.sh(or in_run/data/Movies/config.xml).
- URL:
- Add a Sonarr server:
- URL:
http://<theoriarr-host>:8989/series - API key: printed by
./theoriarr.sh(or in_run/data/Series/config.xml).
- URL:
Each service is served with a URL base (/movies, /series) so the unified shell
can host both on one origin. Requests to the bare origins (:7878 / :8989)
redirect to the prefixed path, so outdated clients generally keep working, but the
prefixed URLs above are the canonical ones.
Both services respond to /api/v3/system/status with their native appName, so
Jellyseerr detects them correctly. Anime requests are routed through the Sonarr
service, which has first-class anime support.
Repository layout
Theoriarr/
├── build.sh # build both services (backend + frontend)
├── test.sh # run both unit-test suites
├── theoriarr.sh # launcher (both services + unified shell)
├── theoriarr-stop.sh
├── flake.nix, flake.lock # Nix dev shell, build, and run
├── gateway.js # zero-dep gateway: serves the shell, proxies /movies + /series
├── portal/ # unified Theoriarr shell (index.html + shell.css + shell.js)
├── Logo/theoriarr.svg
├── PROGRESS.md # resumable engineering log
└── src/
├── Theoriarr.Movies/ # Radarr-derived service
└── Theoriarr.Series/ # Sonarr-derived service
Data and ports
- Data dirs default to
_run/data/Moviesand_run/data/Series(override withTHEORIARR_DATA=/some/dir). - Ports default to Radarr/Sonarr defaults (
7878/8989); change them in each service'sconfig.xmlunder its data dir. - The gateway port defaults to
6868(override withTHEORIARR_PORTAL_PORT). theoriarr.shlaunches each service with a URL base (/movies,/series) via theRadarr__Server__UrlBase/Sonarr__Server__UrlBaseenvironment variables, so the gateway can host both on one origin. Direct access at the prefixed paths always works.
Roadmap
- Combine both codebases into one repository and build/test them together.
- Preserve Sonarr + Radarr APIs for Jellyseerr.
- Unified Theoriarr shell: one origin, Movies/Series switcher, service status.
- Native single-tree frontend (merge the two React apps page by page).
- Single-process backend exposing both API surfaces.
Credits and license
Theoriarr contains code from Radarr (Team Radarr, GPL-3.0) and Sonarr
(Team Sonarr, GPL-3.0). Both are licensed under the GNU General Public License
v3; Theoriarr is distributed under the same terms. See src/Theoriarr.Movies/LICENSE
and src/Theoriarr.Series/LICENSE.md. All credit for the underlying applications
belongs to their respective teams and contributors.