Architecture¶
Gadarr starts as a TypeScript workspace:
apps/api: server, integrations, automation workflows.apps/web: browser UI.packages/core: shared domain models and validation schemas.
Bounded Contexts¶
Game Library¶
Owns root folders, scan entries, games, aliases, platforms, install paths, current version, desired channel, tags, and monitor state.
Sources And Indexers¶
Owns search/RSS source configuration for built-in Prowlarr, Prowlarr-synced Torznab/Newznab proxy sources, direct Torznab, direct Newznab, plain RSS feeds, RSS-compatible Sonarr named indexers such as Fanzub, IP Torrents, Nyaa, and TorrentLeech, and API-backed named trackers such as BroadcastheNet, FileList, and HDBits. It tracks enablement, categories, priority, min seeders, manual-search/automatic-search/RSS mode flags, last RSS sync state, and source failures. It must never expose raw API keys or tracker passkeys to the browser.
Prowlarr is optional. When PROWLARR_URL and PROWLARR_API_KEY are configured, Gadarr presents Prowlarr as a virtual source and Settings -> Indexers can sync enabled, search-capable, game-category Prowlarr indexers into saved Torznab/Newznab sources that point at Prowlarr's per-indexer proxy endpoints. The sync preserves Prowlarr RSS/search flags, priority, tags, and only matching game categories, so indexers that advertise only TV/movie categories are not imported. When Prowlarr is absent, saved Torznab/Newznab/RSS, named RSS-compatible sources, and named tracker API sources still power manual search, monitored search, and RSS sync.
Release Decisions¶
Owns matching a normalized indexed release to a game using title/alias terms, profiles, release-profile terms, seeder thresholds, source metadata, candidate scoring, and accept/reject reasons.
The release classifier normalizes each indexed title into game automation metadata:
releaseType: base game, patch, hotfix, DLC, mod, DRM-free build, repack, tool, soundtrack, or unknown.parsedVersionandpatchKey: used to group game updates into the Patches view.releasePlatformandreleaseChannel: Steam, GOG, Epic, PC, beta, preview, stable, and unknown.trustLevelandriskFlags: trusted, known-source, unknown, or untrusted with explicit flags such as repack, trainer, scene, keygen, or crack.- Boolean intent flags for update-only, DLC-only, DRM-free, repack, and crack/DRM-bypass detection.
Crack/DRM-bypass signals are rejected by default, shown as safety metadata when included by explicit filter settings, and blocked from download-client grabs.
The UI defaults keep game-native rows prominent: base-game, bundle, DRM-free, and repack release types are the first preset, unversioned/unknown rows are hidden until explicitly included, and repack/crack exclusion toggles are available without being pre-enabled. That keeps random non-game feed rows out of the first view while still letting a user audit flagged releases.
Import Lists¶
Owns game-library and watchlist discovery before a title becomes a monitored game. Import-list support covers local Steam Library, the Servarr-compatible Steam Owned Games provider, Steam Wishlist, GOG Library, the Servarr-compatible GOG Owned Games provider, Epic Library, the Servarr-compatible Epic Owned Games provider, the Servarr-compatible Legendary/Heroic Cache provider, Itch.io Library, Lutris Library, Amazon Games Library, EA App Library, Ubisoft Connect Library, Battle.net Library, manual URL, custom JSON, and RSS feeds. Local store-library scans preserve Steam App IDs, GOG game IDs, Epic catalog/app IDs, Itch.io game/upload/build IDs, Lutris IDs/slugs, Amazon product IDs, EA content IDs, Ubisoft/Uplay IDs, Battle.net internal/product/API IDs, install paths, platforms, and build/version hints when launcher manifests or cache databases are present. Steam Owned Games uses a SteamID64 plus Steam Web API key and preserves Steam App IDs; GOG Owned Games reads account filtered-product pages through a configured session cookie or access token and preserves GOG product IDs, PC/GOG platform hints, and build/version hints; Epic Owned Games uses a configured Epic access token to read the launcher-backed library items endpoint, enrich records through Epic catalog metadata, preserve Epic catalog/app/namespace IDs, and skip DLC/add-ons, mods, private sandboxes, and Unreal Marketplace records by default. Legendary/Heroic Cache reads local Legendary metadata trees or Heroic store_cache/legendary_library.json files without storing Epic tokens, preserves Epic app names/namespaces/catalog IDs when present, carries install paths and versions from cache metadata, and keeps the same base-game filters for DLC/add-ons, mods, mobile-only records, and Unreal Marketplace records. Itch.io Library reads official .itch/receipt.json.gz install receipts from local install-location folders, preserves Itch.io game, upload, and build IDs, and fails closed when a library path has no readable receipts. Lutris Library reads the local pga.db SQLite game table from a direct database path or Lutris data folder, imports installed games by default, preserves Lutris IDs/slugs plus Steam/GOG/Epic/Itch service IDs when present, and skips child/add-on rows by default via parent_slug. Amazon Games Library reads the local GameInstallInfo.sqlite cache from a direct database path or Amazon Games data folder, imports installed rows by default, preserves Amazon product IDs, carries install paths and versions, and skips rows with explicit parent/add-on markers by default. EA App Library reads local EA Desktop __Installer/installerdata.xml files or older Origin/EA Play .mfst LocalContent manifests from a direct file, game folder, or library path, imports installed games by default, preserves EA content IDs, carries install paths and versions, and skips rows with explicit parent/add-on markers by default. Ubisoft Connect Library reads local Ubisoft registry exports, Ubisoft Connect cache/export records, or game folders with uplay_install.* state files, imports installed games by default, preserves Ubisoft/Uplay IDs and install IDs, carries install paths and versions, and skips ULC/add-on rows by default. Battle.net Library reads local Battle.net uninstall-registry exports, product.db/product JSON exports, protobuf product.db files, or game folders with Battle.net build markers, imports installed games by default, preserves Battle.net internal/product/API IDs, carries install paths and versions, skips Test/Beta rows, and skips explicit add-on rows by default. The account-backed, cache-backed, receipt-backed, and local database-backed providers flow through the same tags, exclusions, cleanup modes, and search-on-add behavior as other import lists, and cleanup stays fail-closed when a provider read fails. Servarr-compatible providers accept familiar list payloads for external tooling, and Radarr-family TMDb List, TMDb Popular, and TMDb User providers map movie/list records into Gadarr import-list items with preserved TMDb IDs, tags, exclusions, cleanup modes, and search-on-add settings. Steam, GOG, Epic, and TMDb credentials stay server-side and are redacted from native and compatibility responses.
Compatibility Watcher¶
Compatibility sources are separate from indexers. They represent official patch feeds, store feeds, RSS/Atom feeds, custom JSON feeds, or manual entries that describe update availability and compatibility. Syncing a compatibility source stores signals with title, installed version, available version, minimum compatible version, platform, channel, status, notes, source URL, and matched game ID when Gadarr can map the signal to a monitored library item.
Compatibility signals can be wanted, blocked, ignored, or applied. They are awareness and review records only; they do not create release grabs or download-client activity.
Profiles¶
Owns game quality profiles and release profiles: platform/channel preferences, minimum seeders, allowed protocols, required terms, preferred terms, ignored terms, and tag scoping.
Queue¶
Owns queue state, release grabs, protocol-aware download-client selection, live download progress, manual ready/failed/blocklist/retry actions, blocked queue reasons, failed-download blocklist entries, and completed-download staging/import transitions.
Download-client integrations run server-side. Gadarr chooses an eligible torrent or Usenet client for each release, keeps provider credentials in SQLite, translates remote paths before import, and keeps blackhole handoffs in the queue for manual or external completed-folder review.
qBittorrent integration uses the Web API server-side. Gadarr stores credentials only in SQLite, tests saved clients with /api/v2/auth/login and /api/v2/app/version, reads Web API compatibility from /api/v2/app/webapiVersion, reads transfer state from /api/v2/transfer/info, and lists Gadarr-category torrents from /api/v2/torrents/info.
Transmission integration uses the JSON-RPC endpoint server-side. Gadarr negotiates X-Transmission-Session-Id, supports optional basic auth, tests with session-get, adds releases with torrent-add, labels Gadarr-owned downloads by category when supported, lists torrents with torrent-get, and removes completed downloads with torrent-remove.
Deluge integration uses the Web JSON-RPC endpoint server-side. Gadarr authenticates with auth.login, connects the web session to the configured daemon host, tests daemon.get_version, sends magnets through core.add_torrent_magnet, sends downloaded torrent files through core.add_torrent_file, applies Deluge labels for Gadarr categories, maps web.update_ui torrent records into queue-compatible status, and removes torrents with core.remove_torrent.
rTorrent integration uses XML-RPC over the configured RPC endpoint. Gadarr tests system.client_version, sends magnet URLs through load.start or stopped load.normal, sends downloaded torrent files through load.raw_start or stopped load.raw, sets Gadarr categories through d.custom1.set, applies the configured destination with d.directory.set, maps d.multicall2 torrent rows into queue-compatible status, and removes torrents with d.erase.
Aria2 integration uses JSON-RPC over the configured RPC endpoint. Gadarr sends the saved password as Aria2's token:<secret> parameter, tests aria2.getVersion, sends magnets through aria2.addUri, uploads fetched torrent files through aria2.addTorrent, maps tellActive, tellWaiting, and tellStopped records into queue-compatible status, and removes active downloads with aria2.forceRemove or completed result records with aria2.removeDownloadResult. Aria2 does not expose labels/categories through RPC, so Gadarr narrows queue listings by the configured destination path when one is set.
uTorrent integration uses the classic WebUI API server-side. Gadarr authenticates through /gui/token.html with basic auth, calls /gui/ actions with the returned token/cookie, tests getsettings, sends magnets through add-url, uploads fetched torrent files through add-file, applies Gadarr categories through the label property, maps list=1 torrent arrays into queue-compatible status, and removes torrents through remove or removedata.
Hadouken integration uses the JSON-RPC /api endpoint server-side. Gadarr authenticates with basic auth, tests core.getSystemInfo, sends magnets or base64 torrent files through webui.addTorrent, applies Gadarr categories through Hadouken labels, maps webui.list rows into queue-compatible status, and removes torrents through webui.perform.
Vuze integration uses Transmission RPC compatibility mode server-side. Gadarr requires RPC protocol version 14 or newer, sends downloads without labels because Vuze does not support Transmission labels, lists all Vuze torrents, and removes torrents through Transmission RPC.
Flood integration uses Flood's HTTP API server-side. Gadarr authenticates through /api/auth/authenticate, verifies the saved session with /api/auth/verify, sends magnets through /api/torrents/add-urls, sends fetched torrent files as base64 payloads through /api/torrents/add-files, maps Flood torrent records and completed content paths into queue-compatible status/output paths, and removes torrents through /api/torrents/delete.
Freebox Download integration uses the Freebox OS download API server-side. Gadarr obtains a challenge from /login, signs it with the saved App Token to create a session through /login/session, sends magnets or torrent-file uploads to /downloads/add with the target directory base64-encoded, maps BT download tasks into queue-compatible status/progress/output paths, and removes tasks through /downloads/{id} or /downloads/{id}/erase.
Synology Download Station integration uses DSM's Web API server-side. Gadarr discovers available APIs through SYNO.API.Info, authenticates with SYNO.API.Auth using the DownloadStation session, prefers SYNO.DownloadStation2.Task when available, creates magnet, torrent-file, or NZB-file tasks, maps BT and NZB task detail/transfer records into queue-compatible status, and removes tasks through the task delete API. Native configuration keeps separate download-station and usenet-download-station types so Servarr-compatible schemas can mirror Sonarr's TorrentDownloadStation and UsenetDownloadStation providers.
SABnzbd integration uses the HTTP API server-side for Usenet releases. Gadarr can authenticate with an API key or username/password, tests mode=version, sends NZB URLs through mode=addurl, maps mode=queue and mode=history records into queue-compatible status, and removes active or historical jobs through the matching queue/history delete API.
NZBGet integration uses JSON-RPC over the configured host URL. Gadarr can authenticate with basic auth, tests version, sends NZB URLs through append with a Gadarr tracking parameter, maps status, listgroups, and history records into queue-compatible status, and removes queue or history records through editqueue.
NZBVortex integration uses the HTTPS API under the configured host URL. Gadarr authenticates through NZBVortex's nonce plus SHA-256 session flow, tests app/API versions, uploads fetched NZB files as multipart application/x-nzb payloads to nzb/add with group and priority parameters, maps queue rows and completed file lookups into queue-compatible status and output paths, and removes queue entries through cancel or cancelDelete.
Pneumatic integration mirrors Sonarr's local Kodi/XBMC usenet handoff. Gadarr treats the saved host URL as the NZB drop folder, treats the destination as the STRM folder, writes fetched .nzb files plus plugin.program.pneumatic .strm control files, and maps generated STRM files into queue-compatible completed items.
Usenet Blackhole integration mirrors Sonarr's local-folder handoff for NZB processors. Gadarr treats the saved host URL as the NZB drop folder, treats the destination as the completed-download watch folder, validates both folders during provider tests, and writes fetched .nzb files for Usenet release candidates without assigning them to torrent-only queue refresh logic.
Torrent Blackhole integration writes .magnet, .torrent, or fallback .url handoff files to a configured watch folder. Blackhole queue items stay queued for manual import or external completed-folder review instead of being reconciled through a torrent client's live API.
Queue refresh reconciles refreshable download-client state back into Gadarr. When a known download disappears or reports a terminal error, Gadarr marks the queue item failed, blocklists that release, and queues the next safe candidate for the same game when one is available.
Import Policy¶
Owns the completed-download handoff into the game library root. The default target is /games unless the game has a root folder or absolute install path under a configured root. Import policy controls dry-run/manual review/apply/reject, hardlink/copy strategy, minimum-size validation, SHA-256 checksum computation for trusted-checksum or signed-manifest gates, optional target backup before replacement, applied-import rollback from recorded backups, and optional completed-download cleanup.
Naming And Custom Filters¶
Owns import path templates and saved list filters. Naming settings map Arr-style folder format concepts onto Gadarr game folders, release folders, and manual import folders, then feed the import manager before a completed download is staged. Custom filters persist reusable UI filter payloads by surface so release-search, library, calendar, queue, wanted, and activity views can grow toward Sonarr/Radarr's saved-filter behavior without hard-coding browser-only state.
History¶
Owns audit trails across searches, grabs, ignored releases, failed downloads, commands, health events, and future imports.
API Shape¶
Representative Gadarr endpoints include the routes below. This list is meant for orientation, not as an exhaustive route manifest; the source in apps/api/src/routes and the Servarr parity scripts are the authoritative checks before publishing endpoint-level claims.
GET /api/healthGET /api/gamesPOST /api/gamesPATCH /api/games/:id/monitorPOST /api/games/:id/aliasesGET /api/games/:id/releasesGET /api/games/:id/detailGET /api/games/:id/patchesPOST /api/games/:id/searchPOST /api/games/:id/patches/searchGET /api/rootfoldersPOST /api/rootfoldersPOST /api/rootfolders/:id/scanGET /api/scanGET /api/historyGET /api/queueGET /api/queue/statusPOST /api/queue/refreshPOST /api/queue/grab/:candidateIdDELETE /api/queue/badDELETE /api/queue/:idPOST /api/queue/:id/mark-readyPOST /api/queue/:id/mark-failedPOST /api/queue/:id/blocklistPOST /api/queue/:id/retryGET /api/importqueuePOST /api/importqueue/processPOST /api/importqueue/:id/applyPOST /api/importqueue/:id/rollbackPOST /api/importqueue/:id/rejectGET /api/manualimportGET /api/manualimport/reviewPOST /api/manualimportGET /api/releasePOST /api/release/grabGET /api/wanted/missingGET /api/wanted/cutoffPOST /api/wanted/searchGET /api/profilesPOST /api/profilesPATCH /api/profiles/:idDELETE /api/profiles/:idGET /api/releaseprofilesPOST /api/releaseprofilesPATCH /api/releaseprofiles/:idDELETE /api/releaseprofiles/:idGET /api/qualitydefinitionsPATCH /api/qualitydefinitions/:idGET /api/parseGET /api/downloadclientsGET /api/downloadclients/:id/statusGET /api/downloadclients/:id/torrentsDELETE /api/downloadclients/:id/torrents/:hashPOST /api/downloadclientsPATCH /api/downloadclients/:idDELETE /api/downloadclients/:idPOST /api/downloadclients/testGET /api/eventsGET /api/blocklistDELETE /api/blocklist/:idGET /api/sourcesPOST /api/sourcesPATCH /api/sources/:idDELETE /api/sources/:idPOST /api/sources/testPOST /api/sources/:id/testPOST /api/sources/:id/searchGET /api/importlistPOST /api/importlistPATCH /api/importlist/:idDELETE /api/importlist/:idPOST /api/importlist/testallPOST /api/importlist/:id/testPOST /api/importlist/:id/syncPOST /api/rss/syncGET /api/system/taskGET /api/system/statusGET /api/system/backupPOST /api/system/backupPOST /api/system/backup/:id/restorePOST /api/system/backup/restore/uploadDELETE /api/system/backup/:idGET /api/commandPOST /api/commandGET /api/settings/importPATCH /api/settings/importGET /api/settings/namingGET /api/settings/naming/examplesPATCH /api/settings/namingGET /api/customfilterPOST /api/customfilterPATCH /api/customfilter/:idDELETE /api/customfilter/:idPOST /api/security/api-key/rotatePOST /api/security/calendar-key/rotatePOST /api/security/sessions/revokeGET /api/prowlarr/statusGET /api/prowlarr/indexersGET /api/prowlarr/categoriesGET /api/prowlarr/searchPOST /api/sources/prowlarr/sync
Additional native and compatibility surfaces include calendar and iCal feed routes, Crackwatch status, connect providers, metadata providers, tags and tag detail, compatibility sources/signals, remote path mappings, log files, backup settings/prune/download/upload restore, filesystem/manual-import aliases, static UI/browser-session aliases, and broad /api/v3 and /api/v1 Servarr-compatible provider/config/system routes.
The Servarr compatibility layer exposes familiar /api/v3 aliases for external tooling. Provider parity includes /api/v3/downloadclient, /api/v3/indexer, /api/v3/importlist, /api/v3/metadata, /api/v3/notification, and /api/v3/remotepathmapping list/create/read/update/delete routes, plus provider test, testall, bulk, and action/:name routes where those surfaces exist in Sonarr's OpenAPI. Settings and catalog parity maps /api/v3/config/*, language/localization catalogs, release profiles, auto-tagging, import-list exclusions, tag details, wanted details, and indexer flags onto Gadarr's native models. Sonarr's series, episode, episode-file, season pass, rename, release push, and media-cover paths map to Gadarr games, virtual single-release episodes, import items, release candidates, and metadata artwork. Method parity also includes HEAD /ping, command/root-folder deletion, tag read/update, delay-profile reorder via PUT, custom-format bulk deletion, episode-file single/bulk updates, static UI path aliases, and Sonarr-style /login and /logout browser-session routes.
Connect delivery is intentionally narrow and server-side: webhook-like providers receive JSON payloads, Discord and Slack receive their native text bodies, Gotify uses X-Gotify-Key, Telegram uses bot-token sendMessage, Pushover uses its message API with an application token/user key pair, Ntfy publishes to a topic name or URL, Pushbullet creates note pushes, Email sends direct SMTP mail with optional STARTTLS, SendGrid and Mailgun send text mail, Notifiarr receives passthrough payloads, Join, Prowl, Pushcut, Simplepush, and Signal use their native HTTP push APIs, Custom Script executes a configured script path without a shell and with Gadarr plus Sonarr-style environment variables, Synology Indexer runs /usr/syno/bin/synoindex without a shell using --help, -R <path>, -D <path>, or -R video, Trakt sends authenticated collection sync requests, Twitter signs OAuth 1.0a status/direct-message requests, Plex refreshes configured library sections, and Kodi runs VideoLibrary.Scan over JSON-RPC. All provider secrets stay out of list/read responses.
Metadata refresh adapters can be provider-specific or template-based. Steam uses Store appdetails, custom JSON uses a configured URL template, PCGamingWiki uses the public MediaWiki Cargo API for Infobox_game records, SteamGridDB uses bearer-token API v2 lookups plus grid/hero artwork endpoints, and IGDB posts Apicalypse game queries with Client-ID/access-token auth. Game metadata stores poster, background, screenshot galleries, trailer links, release date, descriptions, external IDs, people, and genres so API resources and the detail UI can expose richer media without requerying providers. The game detail UI keeps that media game-native with a compact screenshots/trailers strip above patch and release-filter work. Provider secrets stay server-side and are only used for provider tests and refreshes.
Data Strategy¶
The API stores local state in SQLite at data/gadarr.db by default. The schema tracks root folders, scanned entries, games, aliases, profiles, release profiles, indexer sources, search history, release candidates, queue items, import items with target/backup rollback paths, import policy, download clients, remote path mappings, blocklist items, compatibility sources/signals, events, and command history.
Release candidates persist their classifier metadata next to normalized indexer fields so filtering and grouping are stable after search history reloads.
Security Rules¶
- API keys stay in server config or server-side SQLite.
- Logs and UI responses must redact API keys.
- Reverse proxy base paths are handled natively through
GADARR_BASE_URL: the static UI, native API, Servarr-compatible/api/v3aliases, calendar feed, artwork proxy, and browser session aliases are also mounted under the configured subpath. - Downloaded patch artifacts must be treated as untrusted until hash/signature and source policy checks pass. Current import policy enforces minimum-size validation, can compute and require an allowlisted SHA-256 checksum, and can require a
.gadarr.sigEd25519 manifest signed by a configured trusted public key.