Skip to content

Latest commit

Β 

History

133 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Transpondarr

An anime-focused PVR β€” Sonarr's job, built around anime-native tooling and metadata. It monitors anime series and films, finds releases on anime indexers, drives a download client, and organizes the results into a media library.

Status: Beta. The acquisition loop runs end-to-end and unattended β€” add a series or a film from AniList, and what you monitor is searched, graded against your quality profile, grabbed via qBittorrent, and hardlinked into a Plex/Jellyfin-ready library. Automation ships off by default; flip it on in Settings, or set it to notify-only first to watch what it would grab without grabbing anything. Indexing is via Torznab/Prowlarr for now.

Why not just use Sonarr?

Anime breaks Sonarr's assumptions: messy fansub filenames, absolute vs. per-season numbering, release-group/dual-audio/sub preferences, and metadata that lives on AniList/AniDB rather than TVDB.

Features

Today:

  • AniList-native metadata β€” add series and films from AniList search, browse a seasonal discovery chart, and see upcoming episodes and film premieres on an airing calendar keyed to Japanese broadcast times.
  • Series and films, each handled as itself β€” an episode is matched by number and filed under its show; a film is matched by title and release year and filed into a movies library as Placeholder Film (2019)/Placeholder Film (2019).mkv. Plex and Jellyfin want those in different places, so Transpondarr keeps them there: each library takes its own root, and a film waits in the queue rather than landing in the wrong one until the movies root is set. Format decides and episode count never does, so a one-episode OVA is a series and files with them. A film's year is what automation matches on, so it waits for one to be published rather than guessing; searching and grabbing by hand work throughout.
  • Automated acquisition β€” recent-feed polling grabs new releases within minutes of them appearing, and a scheduled sweep backs it up for everything that already existed. Monitoring is per title and per episode β€” choose at add time whether to chase a whole back catalogue or only what airs next, and unmonitor anything you don't want chased β€” under a global off / notify-only / on switch (off until you enable it). Notify-only rehearses the whole thing β€” real searches and real decisions, reported rather than grabbed. Requests can be filtered to specific indexer categories, and a poll that misses a page puts the series that aired inside the gap back at the front of the search queue.
  • A Wanted queue that says why β€” everything still missing across the library, and everything you hold that scores below its profile's cutoff, each with the reason it hasn't been grabbed: automation off, unmonitored, waiting its turn in the search queue, blocklisted β€” or the release the last pass found and declined, and why.
  • Notifications and an activity feed β€” Discord, generic webhook, and ntfy, with per-event toggles and a test button each; an Activity page collects the in-flight queue, the grab/import history across every title, and any download left in the client that nothing is waiting on.
  • Anime-aware quality profiles β€” release group is the dominant axis, then resolution/source, dual audio, and sub preferences, with a score floor and hard excludes. A profile is chosen when you add a title and can be reassigned from its page later. A per-title pinned group can also mean wait for β€” hold new episodes for the pinned group's release before settling for another. Opt a profile into upgrades and an episode you already have is re-grabbed while what holds it scores below the cutoff, then left alone for good.
  • Failure memory β€” a failed release is blocklisted with escalating expiry instead of re-grabbed forever, an environmental-fault breaker stops one bad afternoon from blocklisting the library, and everything is visible and unblockable in the UI.
  • Manual control that's never refused β€” search and grab any release by hand, with an episode's Search opening the release list focused on that episode; profiles inform manual actions but only gate automation.
  • Seeding-safe library import β€” hardlink (or copy) into Plex/Jellyfin-ready naming, without breaking the seeding torrent. Episodes file into season folders or flat, whichever your scanner prefers. Season packs import episode by episode, so a back catalogue arrives in one grab, and anything the importer can't place by itself is fixable by hand from the Activity queue. Archived payloads aren't unpacked: a RAR-set download says so and names what to extract, and extracting it in place then retrying from Fix import completes the import.
  • Self-hosted, single binary β€” embedded web UI, login + API key auth, REST API with an OpenAPI spec, observable background jobs, and live-editable settings β€” no restarts.

Planned (tracked in the milestones):

  • Post-1.0: AniList account sync (auto-monitor your Watching list), adopting a pre-existing library and noticing when it changes on disk, more indexers and download clients with per-title routing between them, and Sonarr-API compatibility for existing dashboard/mobile apps.
  • Post-1.0: first-class handling for series whose releases aren't numbered the way AniList numbers them β€” continuously-airing long-runners, fan re-cuts, and a per-series override for when the automatic mapping is simply wrong.

Install

Transpondarr ships as a single static binary with the web UI embedded β€” no separate database or frontend to run.

Docker

Pull the published multi-arch image (or build locally with docker build -t transpondarr .):

docker pull ghcr.io/matthewdias/transpondarr:latest
docker run -p 9797:9797 -v ./config:/config ghcr.io/matthewdias/transpondarr:latest

The container starts as root only to fix ownership of the mounted config dir, then drops to PUID/PGID (default 1000:1000) before serving. To skip the root phase entirely, run with --user "$(id -u):$(id -g)" β€” the config dir must then already exist and be writable by that user.

For a real deployment alongside qBittorrent and a media server, see Docker deployment below.

Binary

Download the archive for your platform from the releases page, extract it, and run ./transpondarrd.

To build from source instead, see CONTRIBUTING.md.

First run

The server listens on :9797. The web UI uses a login (username + password): on first run you create an admin account, or set TRANSPONDARR_AUTH_USERNAME/ _PASSWORD to bootstrap one. A separate API key guards /api/* for machine clients (dashboards, scripts, a future HA integration) via the X-Api-Key header β€” it's generated and persisted on first run and shown in Settings β†’ API access (set TRANSPONDARR_API_KEY to pin one). Health check (public):

curl localhost:9797/api/v1/health

Configuration

Integrations are set through TRANSPONDARR_* environment variables or edited at runtime in the Settings UI (those DB overrides take precedence over the environment and apply live, without a restart). Unset, unconfigured integrations are simply disabled β€” the server still starts.

Variable Default Purpose
TRANSPONDARR_API_KEY (generated + persisted) Machine-client key for /api/* (X-Api-Key). Auto-generated and saved in the DB; set to override.
TRANSPONDARR_AUTH_USERNAME / _PASSWORD β€” Bootstrap the initial web-UI admin account on first run (otherwise use the setup screen).
TRANSPONDARR_AUTH_REQUIRED enabled enabled (always require login) | local (skip login for local/private addresses).
TRANSPONDARR_ADDR :9797 Listen address.
TRANSPONDARR_DATA_DIR ./data SQLite DB + state (/config in Docker).
TRANSPONDARR_DB <DATA_DIR>/transpondarr.db SQLite DB file path. Override to relocate the DB independently of the data dir.
TRANSPONDARR_QBIT_URL β€” qBittorrent WebUI root; unset β‡’ no download client.
TRANSPONDARR_QBIT_USER / _PASSWORD β€” qBittorrent credentials.
TRANSPONDARR_QBIT_CATEGORY transpondarr Category applied to grabbed torrents.
TRANSPONDARR_STALL_TIMEOUT_HOURS 6 Hours a download may sit having transferred nothing at all before its grab is failed and the release remembered; 0 waits forever. Covers a download the client reports as stalled and one still fetching a magnet's metadata. A download with any progress is never abandoned.
TRANSPONDARR_TORZNAB_URL β€” Torznab feed (Prowlarr/Jackett); unset β‡’ no indexer.
TRANSPONDARR_TORZNAB_APIKEY β€” Torznab API key.
TRANSPONDARR_TORZNAB_NAME torznab Display name for the indexer.
TRANSPONDARR_TORZNAB_CATEGORIES β€” Comma-separated Newznab category IDs sent as cat= on every search and the recent feed (anime is usually 5070); unset β‡’ no filter.
TRANSPONDARR_LIBRARY_DIR β€” Library root episodes import into; unset β‡’ episodes do not import.
TRANSPONDARR_LIBRARY_MOVIES_DIR β€” Library root films place into, separate from the root above; unset β‡’ a grabbed film waits in the Activity queue instead of importing.
TRANSPONDARR_LIBRARY_SERIES_LAYOUT season_folders Path shape inside the series root: season_folders | flat. Films are unaffected, and switching applies to future imports only.
TRANSPONDARR_IMPORT_MODE auto auto (hardlink, copy across filesystems) | hardlink | copy.
TRANSPONDARR_AUTOMATION_ENABLED false off | notify_only | on (bools also accepted). notify_only rehearses: it reports what automation would grab, without grabbing.
TRANSPONDARR_PIN_DELAY_HOURS 0 Hours automation waits for a series' pinned group before taking another; per-series overrides in the UI.
PUID / PGID 1000 / 1000 Docker only: the uid:gid the container drops to after fixing /config ownership on start.

Auth & reverse proxies. The local auth mode skips login only for requests from loopback/private addresses with no forwarding headers, so reverse-proxied requests (which set X-Forwarded-For) always require login β€” a same-host proxy can't turn local-bypass into open access. Session cookies are marked Secure automatically when the proxy sets X-Forwarded-Proto: https.

Docker deployment

For a real deployment alongside qBittorrent and a media server, use docker-compose.yml as a template. Two things matter:

  • Imports hardlink from the path qBittorrent reports. Mount your shared downloads/library volume into Transpondarr at the same path qBittorrent uses, with both on one filesystem (a hardlink can't cross filesystems). The standard single-mount layout (/data/torrents + /data/media) satisfies this. The movies root is one more directory under the same mount, not a second one.
  • Ownership. Set PUID/PGID to the UID:GID that owns your media volume β€” the container starts as root, fixes /config ownership, and drops to that user before serving, so hardlinks into the library land with the right ownership. Persist the /config volume (it holds the SQLite DB).

Verify a running deployment (the second call needs your API key):

curl -s http://localhost:9797/api/v1/health                      # {"status":"ok",...}
curl -s -X POST -H "X-Api-Key: <key>" http://localhost:9797/api/v1/download/test
#   {"status":"ok","client":"qbittorrent"}   (502 => qBit URL/creds wrong)

Contributing

See CONTRIBUTING.md for the stack, toolchain, build-from-source steps, and codebase layout.

License

Apache-2.0. Third-party dependency licenses and notices are reproduced in THIRD-PARTY-NOTICES.md (regenerate with make notices).

About

🐌 Anime-focused PVR β€” discover titles via AniList, grab releases via Torznab + qBittorrent, and organize them into a Plex/Jellyfin-ready library.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages