feat: download client cleanup for Radarr/Sonarr deletions (qBittorrent)#3054
Merged
Conversation
44085fe to
63b516e
Compare
63b516e to
cc7d4f6
Compare
Collaborator
Author
|
Reason for dismissing alerts Requests intentionally target an administrator-configured download-client URL, exactly like Maintainerr's existing Plex/Jellyfin/Emby/Radarr/Sonarr/Seerr/Tautulli/Streamystats integrations. Maintainerr is self-hosted and by design connects to user-configured services on private networks (localhost/RFC1918); blocking those is not viable (see serviceUrlSchema), and settings endpoints are protected at the network level. Not an exploitable SSRF in this threat model. |
When Radarr/Sonarr delete media, Maintainerr can remove the matching completed download (and optionally its data) from the configured download client, cleaning up the orphaned, still-seeding torrent left behind after the library copy is removed. - Matched via the Radarr/Sonarr download history (downloadId), so it only runs for media removed through Radarr/Sonarr. Season/episode deletes remove only the torrents the delete fully covers (every backed episode is being deleted), so a season-pack / complete-series pack that still backs wanted episodes is left intact. Removal runs only after the *arr delete is confirmed. - Whether a download has finished seeding is decided by qBittorrent's own ratio / seed-time limits; a fallback ratio (default 0.5, min 0.5) applies only to downloads qBittorrent doesn't limit. - qBittorrent deletes its own downloaded files, so the common downloads-separate- from-library (hardlink/copy) setup is cleaned without Maintainerr needing any paths. Cross-seed-safe: a shared content path is removed entry-only. - Settings tab shown only when Radarr/Sonarr is configured; handles qBittorrent's auth-bypass and surfaces an actionable message on a 403. - Backend sits behind a DownloadClient interface + factory so additional clients can be added later. Includes a TypeORM migration for the new settings columns plus unit and UI tests.
cc7d4f6 to
15723f9
Compare
maintainerr-automation Bot
added a commit
that referenced
this pull request
Jun 8, 2026
* feat: download client cleanup for Radarr/Sonarr deletions (qBittorrent) (#3054) * fix(metadata): keep media-server ids unless corroborated; accept on provider year agreement (#3011) * fix(overlay): uniform style scaling, rotation offset, and font register logging (fixes #3025) (#3057) * build(deps): bump @types/react in the react group (#3060) Bumps the react group with 1 update: [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react). Updates `@types/react` from 19.2.16 to 19.2.17 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react) --- updated-dependencies: - dependency-name: "@types/react" dependency-version: 19.2.17 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: react ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump the nestjs group with 5 updates (#3059) Bumps the nestjs group with 5 updates: | Package | From | To | | --- | --- | --- | | [@nestjs/common](https://github.com/nestjs/nest/tree/HEAD/packages/common) | `11.1.24` | `11.1.26` | | [@nestjs/core](https://github.com/nestjs/nest/tree/HEAD/packages/core) | `11.1.24` | `11.1.26` | | [@nestjs/platform-express](https://github.com/nestjs/nest/tree/HEAD/packages/platform-express) | `11.1.24` | `11.1.26` | | [@nestjs/cli](https://github.com/nestjs/nest-cli) | `11.0.21` | `11.0.22` | | [@nestjs/testing](https://github.com/nestjs/nest/tree/HEAD/packages/testing) | `11.1.24` | `11.1.26` | Updates `@nestjs/common` from 11.1.24 to 11.1.26 - [Release notes](https://github.com/nestjs/nest/releases) - [Commits](https://github.com/nestjs/nest/commits/v11.1.26/packages/common) Updates `@nestjs/core` from 11.1.24 to 11.1.26 - [Release notes](https://github.com/nestjs/nest/releases) - [Commits](https://github.com/nestjs/nest/commits/v11.1.26/packages/core) Updates `@nestjs/platform-express` from 11.1.24 to 11.1.26 - [Release notes](https://github.com/nestjs/nest/releases) - [Commits](https://github.com/nestjs/nest/commits/v11.1.26/packages/platform-express) Updates `@nestjs/cli` from 11.0.21 to 11.0.22 - [Release notes](https://github.com/nestjs/nest-cli/releases) - [Commits](nestjs/nest-cli@11.0.21...11.0.22) Updates `@nestjs/testing` from 11.1.24 to 11.1.26 - [Release notes](https://github.com/nestjs/nest/releases) - [Commits](https://github.com/nestjs/nest/commits/v11.1.26/packages/testing) --- updated-dependencies: - dependency-name: "@nestjs/common" dependency-version: 11.1.26 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: nestjs - dependency-name: "@nestjs/core" dependency-version: 11.1.26 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: nestjs - dependency-name: "@nestjs/platform-express" dependency-version: 11.1.26 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: nestjs - dependency-name: "@nestjs/cli" dependency-version: 11.0.22 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: nestjs - dependency-name: "@nestjs/testing" dependency-version: 11.1.26 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: nestjs ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump react-hook-form from 7.77.0 to 7.78.0 (#3061) Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.77.0 to 7.78.0. - [Release notes](https://github.com/react-hook-form/react-hook-form/releases) - [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md) - [Commits](react-hook-form/react-hook-form@v7.77.0...v7.78.0) --- updated-dependencies: - dependency-name: react-hook-form dependency-version: 7.78.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @types/node from 22.19.19 to 22.19.20 (#3062) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.19.19 to 22.19.20. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 22.19.20 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(ui): move the beta badge from notifications to the download client (#3058) Notifications has graduated from beta; the download client is the current beta feature. Reuses the same beta.svg heading badge. * fix(plex): use /identity for the connection probe and v2 resources for server discovery (#3063) * fix(plex): probe /identity instead of / for the connection check Bare / returns 401 behind a reverse proxy (it redirects to the web UI), so getStatus()/setMachineId() failed and the Plex adapter wouldn't initialize for proxied servers. /identity returns the same machineIdentifier and version without the auth quirk and works for direct and proxied servers alike. * fix(plex): discover servers via plex.tv v2 resources The legacy v1 /api/resources omits some owned servers (and needs no client id), so the server-selection list could come back empty even when plex.tv knows about the server. Switch getDevices() to the v2 JSON /api/v2/resources, which returns those servers; it requires X-Plex-Client-Identifier, so send the instance clientId (the same id the UI authenticates with) plus X-Plex-Product. * fix(ui): drop the flickering "Validating Plex token" banner Stored-token validation is fast, so the info banner only flashes. Remove it; a failed validation is still surfaced by the stored-token result alert, and the "configuration required" prompt stays suppressed while a stored token is being validated (so it doesn't flash in its place). * fix(plex): keep dnsRebindingProtection/natLoopbackSupported in v2 device mapping The v2 /api/v2/resources rewrite stopped populating these two fields that the legacy v1 mapping set. v2 still returns them, so restore them for parity (they are optional and currently unread, but shouldn't silently become undefined). * refactor(plex): remove unused getWatchlist and getDiscoverDataUserState helpers (#3064) * refactor(plex): remove unused PlexTvApi.getWatchlist getWatchlist() and its WatchlistResponse/MetadataResponse/PlexWatchlistItem types have no production callers. The live Plex watchlist-rule path is plex-getter -> getWatchlistIdsForUser -> PlexCommunityApi (community.plex.tv GraphQL); this helper was superseded leftover. Pure removal, no behavior change. * refactor(plex): remove unused getDiscoverDataUserState getDiscoverDataUserState() and its PlexDiscoverUserState / PlexDiscoverUserStateResponse types were added in 2023 'for potential future usage' and never called. Drop the dormant helper to keep the API surface clean. * test(ui): stabilize external service settings spec --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: maintainerr-automation[bot] <261505141+maintainerr-automation[bot]@users.noreply.github.com> Co-authored-by: enoch85 <mailto@danielhansson.nu> Co-authored-by: Craig Linford <clinford86@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Contributor
|
🎉 This PR is included in version 3.15.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
doonga
pushed a commit
to greyrock-labs/home-ops
that referenced
this pull request
Jun 11, 2026
… ➔ 3.15.0) (#230) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/maintainerr/maintainerr](https://github.com/Maintainerr/Maintainerr) | minor | `3.14.0` → `3.15.0` | --- ### Release Notes <details> <summary>Maintainerr/Maintainerr (ghcr.io/maintainerr/maintainerr)</summary> ### [`v3.15.0`](https://github.com/Maintainerr/Maintainerr/blob/HEAD/CHANGELOG.md#3150-2026-06-09) [Compare Source](Maintainerr/Maintainerr@v3.14.0...v3.15.0) #### Highlights - Added functionality to delete items from the download client and manage collection membership within the media server. - Optional integration for qBittorrent to remove completed downloads when Radarr/Sonarr deletes media ([#​3054](Maintainerr/Maintainerr#3054)). - Plex connection fixes: updated server discovery to use v2 API and improved connection probe reliability ([#​3063](Maintainerr/Maintainerr#3063)). #### Features - Added item deletion and collection management features in the media server. - Optional download-client integration for qBittorrent to clean up completed downloads when Radarr/Sonarr removes media ([#​3054](Maintainerr/Maintainerr#3054)). #### Fixes - Fixed Plex connection probe to use `/identity` endpoint and updated server discovery to use v2 API resources ([#​3063](Maintainerr/Maintainerr#3063)). - Resolved overlay rendering issues with uniform style scaling, rotation anchoring, and improved font register logging ([#​3057](Maintainerr/Maintainerr#3057)). - Improved metadata handling to retain media-server IDs unless corroborated by provider data, with additional checks for year agreement ([#​3011](Maintainerr/Maintainerr#3011)). #### Database migrations - Added new columns to the `settings` table for download client configuration, including URL, credentials, and deletion settings. #### Internal - Removed unused Plex API helpers: `getWatchlist` and `getDiscoverDataUserState` ([#​3064](Maintainerr/Maintainerr#3064)). #### Dependencies - Updated 8 dependencies, including `typescript-eslint`, `@types/node`, and `react-hook-form`. </details> --- ### Configuration 📅 **Schedule**: (in timezone America/New_York) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yMTQuNiIsInVwZGF0ZWRJblZlciI6IjQzLjIxNC42IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL21pbm9yIl19--> Reviewed-on: https://git.greyrock.io/greyrock-labs/home-ops/pulls/230
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an optional download-client integration that removes the completed download (and optionally its data) from qBittorrent when Radarr/Sonarr deletes media — cleaning up the orphaned, still-seeding download left behind after the library copy is removed.
downloadId), so it only runs for media removed through Radarr/Sonarr. Sonarr is scoped to whole-show deletes (season-pack safety).DownloadClientinterface + factory so additional clients can be added later.Includes a TypeORM migration for the new settings columns plus unit and UI tests. Docs (a Configuration section) are prepared as a separate Maintainerr_docs change.