diff --git a/docs/Configuration.md b/docs/Configuration.md index 348407476..f8aed5acb 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -209,7 +209,13 @@ The separate `Settings -> Download Client` page only appears once Radarr or Sona When media is removed through Radarr or Sonarr, Maintainerr can remove the matching completed download (and optionally its data) from your download client. Downloads are matched using the Radarr/Sonarr download history, so media removed without Radarr/Sonarr is left untouched. -qBittorrent is the only supported client. +Maintainerr supports qBittorrent and Transmission. Pick the client first, then enter the URL and credentials for that same instance. + +| Setting | Description | +| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Client | Choose `qBittorrent` or `Transmission`. Nothing is selected until you choose. An install that already had a download client when it upgraded keeps `qBittorrent`, the only client that existed before. Changing the client clears the URL field because qBittorrent uses a WebUI base URL while Transmission uses the full RPC endpoint. | +| Delete downloaded data | When enabled, removing a download also deletes its files from disk. Turn this off if you cross-seed, so other torrents that share the data keep working. | +| Fallback seeding ratio | Whether a download has finished seeding is decided by the client's own ratio or time limits first. This fallback ratio only applies when the client enforces no limit, and then only after 23 hours. | ### qBittorrent @@ -217,24 +223,34 @@ qBittorrent is the only supported client. Maintainerr matches downloads by the hash recorded in the Radarr/Sonarr download history, so point it at the **same qBittorrent instance Radarr/Sonarr use as their download client**, with the Web UI enabled (qBittorrent 4.3.4 or newer). Media grabbed through a different qBittorrent, or through a Usenet or other download client, won't be found and is left untouched. ::: -| Setting | Description | -| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| URL | The base URL of your qBittorrent WebUI, such as `http://localhost:8080` or `https://qbittorrent.example.com` | -| Username | The qBittorrent WebUI username. Leave blank if the WebUI bypasses authentication (e.g. _Bypass authentication for clients on localhost_). | -| Password | The qBittorrent WebUI password. Leave blank if authentication is bypassed. | -| Delete downloaded data | When enabled, removing a download also deletes its files from disk. Turn this off if you cross-seed, so other torrents that share the data keep working. | -| Fallback seeding ratio | Whether a download has finished seeding is decided by qBittorrent's own ratio / seed-time limits. This fallback ratio only applies to downloads qBittorrent isn't limiting, and can't be below 0.5 (default 0.5). | +| Setting | Description | +| -------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| URL | The base URL of your qBittorrent WebUI, such as `http://localhost:8080` or `https://qbittorrent.example.com` | +| Username | The qBittorrent WebUI username. Leave blank if the WebUI bypasses authentication (e.g. _Bypass authentication for clients on localhost_). | +| Password | The qBittorrent WebUI password. Leave blank if authentication is bypassed. | + +### Transmission + +:::note +Point Maintainerr at the **same Transmission instance Radarr/Sonarr use as their download client**, with Transmission's RPC interface enabled. Use the full RPC endpoint, usually `http://localhost:9091/transmission/rpc`. Media grabbed through a different Transmission, or through a Usenet or other download client, won't be found and is left untouched. +::: + +| Setting | Description | +| -------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| URL | The full Transmission RPC endpoint, such as `http://localhost:9091/transmission/rpc` or `https://transmission.example.com/transmission/rpc` | +| Username | The Transmission RPC username. Leave blank if RPC authentication is disabled. | +| Password | The Transmission RPC password. Leave blank if RPC authentication is disabled. | How it works: -- Cleanup runs only for media that Radarr or Sonarr deletes. Maintainerr looks up the download that produced the files in the Radarr/Sonarr download history and removes that download from qBittorrent. Media removed directly from the media server (without Radarr/Sonarr), manually imported items, or items whose download history has been cleared are left untouched. +- Cleanup runs only for media that Radarr or Sonarr deletes. Maintainerr looks up the download that produced the files in the Radarr/Sonarr download history and removes that download from the selected client. Media removed directly from the media server (without Radarr/Sonarr), manually imported items, or items whose download history has been cleared are left untouched. - Only collection actions that delete files trigger cleanup (**Delete**, **Unmonitor and delete files**). **Unmonitor and keep files** and **Change quality profile** never remove a download. -- **Seeding is decided by qBittorrent.** A download is only removed once it has met qBittorrent's own ratio or seed-time limit; one still below its limit keeps seeding. The **Fallback seeding ratio** applies only to downloads qBittorrent enforces no limit on. -- **Separate download and library folders are handled automatically.** qBittorrent deletes its own downloaded files (in its download directory) while Radarr/Sonarr delete the imported library copy, so the common "downloads separate from the library" (hardlink/copy) setup is fully cleaned without Maintainerr needing to know any paths. +- **Seeding is decided by the selected client.** A download is only removed once the selected client says its own seeding goal is met. If the selected client enforces no seeding goal at all, Maintainerr waits until the download has both reached the **Fallback seeding ratio** and kept seeding for at least 23 hours. +- **Separate download and library folders are handled automatically.** The download client deletes its own downloaded files while Radarr/Sonarr delete the imported library copy, so the common "downloads separate from the library" (hardlink/copy) setup is fully cleaned without Maintainerr needing to know any paths. - For **Sonarr**, cleanup runs only on whole-show deletions. Season- and episode-level deletions are skipped on purpose, because a season-pack download can contain episodes you still want. -- If a download is cross-seeded (another torrent shares the same files), Maintainerr removes only the torrent entry and keeps the data so the other torrent keeps working. This follows the same general approach as [qbit_manage](https://github.com/StuffAnThings/qbit_manage), rather than trying to replace a dedicated torrent-management workflow. +- For the supported torrent clients, if **Delete downloaded data** is on and another torrent shares the same downloaded files, Maintainerr removes only the torrent entry and keeps the data so the other torrent keeps working. - Removal is best-effort: a failure to reach the download client never blocks the Radarr/Sonarr deletion itself, so treat it as cleanup assistance rather than guaranteed download-client reconciliation. For more advanced usage; look elsewhere. -- `Test Connection` verifies the URL and credentials against the qBittorrent Web UI before saving. +- `Test Connection` verifies the URL and credentials against the selected client before saving. :::note Troubleshooting: "403 Forbidden" after a successful login A `403 Forbidden` on the connection test (or in the logs) means qBittorrent accepted the credentials but its Web UI security then blocked the request; it is **not** a wrong username/password. The usual cause is that Maintainerr and qBittorrent run on different IPs (e.g. separate Docker containers). In qBittorrent go to **Options → Web UI → Security** and add Maintainerr's IP or subnet to **"Bypass authentication for clients in whitelisted IP subnets"**. A reverse proxy or host-header validation can also cause it. diff --git a/docs/Migration.md b/docs/Migration.md index 1e2c18f14..6b1ce05ab 100644 --- a/docs/Migration.md +++ b/docs/Migration.md @@ -33,7 +33,7 @@ The database schema includes support for overlays. - overlay template, overlay settings, and overlay item state tables - collection fields for `overlayEnabled`, `overlayTemplateId`, and `mediaServerSort` - a `streamystats_url` setting for the Jellyfin-only Streamystats integration -- download-client settings for the qBittorrent cleanup integration: URL, optional username/password, whether download data should be deleted, and the fallback seeding ratio +- download-client settings for the cleanup integration: client type (`qbittorrent` on upgrade when a download client URL was already configured, otherwise unset), URL, optional username/password, whether download data should be deleted, and the fallback seeding ratio - a `collection_media.ruleEvaluationFailed` state so upgrades can preserve which rule-managed items should be skipped by automatic handling after a rule-evaluation failure; manual collection entries are still handled normally - a direction on pending collection membership changes so an unanswered add or remove can be reconciled without being mistaken for a manual membership; existing rows default to `remove` - a `NormalizeRuleSectionOperators` migration that backfills legacy null operators without changing existing matches: the first rule of a group stays unset, the first rule of a later section becomes `AND`, and later rules in that section become `OR`. This migration is behavior-preserving and its `down()` is a no-op. diff --git a/docs/api/settings.md b/docs/api/settings.md index 77e59bf7a..75ea7a967 100644 --- a/docs/api/settings.md +++ b/docs/api/settings.md @@ -1111,7 +1111,7 @@ If no media server is configured the sweep returns immediately and silently, eve | `200` | The settings, **with the password in cleartext** | | `200` with `status: "NOK"` | The read failed | -An unconfigured client reads as empty strings with `download_client_delete_data` true and `download_client_fallback_ratio` `0.5`, which is indistinguishable from a deliberately blank configuration. +An unconfigured client reads as `download_client_type: null`, empty strings, `download_client_delete_data: true`, and `download_client_fallback_ratio: 0.5`. ### `POST /api/settings/download-client` @@ -1121,6 +1121,7 @@ Request body: ```json { + "download_client_type": "qbittorrent", "download_client_url": "http://qbittorrent:8080", "download_client_username": "user", "download_client_password": "...", @@ -1129,7 +1130,7 @@ Request body: } ``` -`download_client_delete_data` and `download_client_fallback_ratio` are **required**, so a partial update is not possible. To change only the URL you must send the other fields too. +`download_client_type`, `download_client_delete_data` and `download_client_fallback_ratio` are **required**, so a partial update is not possible. To change only the URL you must send the other fields too. | Status | Cause | | -------------------------- | ------------------------------------------------ | @@ -1137,10 +1138,14 @@ Request body: | `201` with `status: "NOK"` | The write failed | | `400` | Validation failed, including a ratio below `0.5` | -The username and password are deliberately **not** trimmed, so a credential with real leading or trailing whitespace survives. An empty username and password are a valid configuration, since qBittorrent can bypass authentication for whitelisted subnets. +Use `qbittorrent` with a WebUI URL like `http://qbittorrent:8080`, or `transmission` with the full RPC endpoint like `http://transmission:9091/transmission/rpc`. + +The username and password are deliberately **not** trimmed, so a credential with real leading or trailing whitespace survives. Empty credentials are valid when the selected client allows unauthenticated access. The connection is stored unverified. +The fallback ratio applies only when the selected client enforces no seeding goal of its own. In that case Maintainerr also waits for at least 23 hours of seeding before removing the download. + :::caution download_client_delete_data has real destructive reach With it on, removing a download also **deletes its data on disk** during cleanup, though data shared with another download is kept. This takes effect the moment you save, changing what the file-deleting `*arr` actions do. ::: @@ -1155,7 +1160,7 @@ With it on, removing a download also **deletes its data on disk** during cleanup | `200` with `status: "NOK"` | The write failed | :::warning Destructive, and it resets more than the connection -Clears the URL, username and password, with no copy kept, **and resets `download_client_delete_data` to true and `download_client_fallback_ratio` to 0.5**. +Clears the URL, username and password, with no copy kept, **and resets `download_client_type` to `null`, `download_client_delete_data` to true, and `download_client_fallback_ratio` to 0.5**. That reset is the non-obvious part: if you had turned data deletion off, removing and re-adding the client silently gives you the on-by-default behaviour back. @@ -1166,11 +1171,11 @@ No torrents are touched. Afterwards the file-deleting `*arr` actions stop attemp **Probe a download client URL and credentials, without saving.** -| Status | Cause | -| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `201` with `status: "OK"` | Connected. `message` is the qBittorrent version | -| `201` with `status: "NOK"` | `Invalid username or password`, a message about the Web UI IP whitelist on a `403`, `Unexpected response from the download client. Verify the URL points to a qBittorrent WebUI.`, or a connection failure | -| `400` | Validation failed | +| Status | Cause | +| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `201` with `status: "OK"` | Connected. `message` is the selected client's version | +| `201` with `status: "NOK"` | `Invalid username or password`, the qBittorrent Web UI IP-whitelist message, the Transmission `rpc-whitelist` or `rpc-host-whitelist` message, `Unexpected response from the download client. Verify the URL points to the selected client API.`, or a connection failure | +| `400` | Validation failed | :::caution The body is the whole settings schema `download_client_delete_data` and `download_client_fallback_ratio` are required even for a pure connection test. Omitting them is a `400`.