No description
  • C# 66.2%
  • TypeScript 25.9%
  • JavaScript 5.3%
  • CSS 2%
  • HTML 0.2%
  • Other 0.3%
Find a file
Theoriarr Bot 61fb988378 nix run: attach to logs in foreground and stop on Ctrl+C
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.
2026-09-20 16:42:57 +00:00
Logo Theoriarr: combine Radarr and Sonarr into one repo 2026-09-20 15:26:15 +00:00
portal Unified Theoriarr shell: single-origin gateway hosting both UIs 2026-09-20 15:43:03 +00:00
src Add Theoriarr.Web unified UI (native SPA) and serve it at /app 2026-09-20 16:15:25 +00:00
.gitignore Add Nix flake: dev shell, build and run 2026-09-20 15:53:42 +00:00
build.sh Add Theoriarr.Web unified UI (native SPA) and serve it at /app 2026-09-20 16:15:25 +00:00
flake.lock Add Nix flake: dev shell, build and run 2026-09-20 15:53:42 +00:00
flake.nix nix run: attach to logs in foreground and stop on Ctrl+C 2026-09-20 16:42:57 +00:00
gateway.js gateway: drop legacy portal fallback; 503 with build hint when UI missing 2026-09-20 16:34:38 +00:00
PROGRESS.md nix run: attach to logs in foreground and stop on Ctrl+C 2026-09-20 16:42:57 +00:00
README.md nix run: attach to logs in foreground and stop on Ctrl+C 2026-09-20 16:42:57 +00:00
test.sh Theoriarr: combine Radarr and Sonarr into one repo 2026-09-20 15:26:15 +00:00
theoriarr-stop.sh Unified Theoriarr shell: single-origin gateway hosting both UIs 2026-09-20 15:43:03 +00:00
theoriarr.sh nix run: attach to logs in foreground and stop on Ctrl+C 2026-09-20 16:42:57 +00:00

Theoriarr

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

  1. Start Theoriarr (./theoriarr.sh).
  2. 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).
  3. Add a Sonarr server:
    • URL: http://<theoriarr-host>:8989/series
    • API key: printed by ./theoriarr.sh (or in _run/data/Series/config.xml).

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/Movies and _run/data/Series (override with THEORIARR_DATA=/some/dir).
  • Ports default to Radarr/Sonarr defaults (7878 / 8989); change them in each service's config.xml under its data dir.
  • The gateway port defaults to 6868 (override with THEORIARR_PORTAL_PORT).
  • theoriarr.sh launches each service with a URL base (/movies, /series) via the Radarr__Server__UrlBase / Sonarr__Server__UrlBase environment 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.