qBittorrent Shim and Automation - Kheopsian/Hydranos GitHub Wiki

🇬🇧 English · 🇫🇷 Français

qBittorrent Shim and Automation

Applies to Hydranos 4.4.

For anyone connecting Sonarr, Radarr, Lidarr, autobrr, cross-seed or a script to Hydranos as if it were qBittorrent: what each call really does, what is constant or ignored, and the settings that work per application (Application recipes below). Moving an existing qBittorrent setup? Follow Migrating from qBittorrent first.

What the shim is

The qBittorrent shim is the set of routes under /api/v2/* on the same port as the web UI, port 8199 by default ([daemon] api_port). It imitates the qBittorrent WebUI API closely enough for the common automation tools:

  • GET /api/v2/app/version answers v4.6.0 (plain text).
  • GET /api/v2/app/webapiVersion answers 2.9.3.

Both are fixed on purpose: tools pick their calls from them. Adds follow the normal placement rule (category → engine and save path, see Categories and Routing). The shim lists every engine (extra engines included), each torrent once, but adds only into race or hoard (by category): it has no field to name an engine.

While Hydranos is still loading its torrents at startup, every /api/v2/* route, login included, answers 503 with a JSON body and Retry-After: 5; clients retry.

Logging in

POST /api/v2/auth/login takes a form body (application/x-www-form-urlencoded) with username and password. Two kinds of credentials are accepted:

Username Password Accepted when
the admin account name ([auth] username, default admin) the admin password the bcrypt hash in [auth] password_hash matches
anything the API key ([daemon] api_key) the key matches exactly

The answer is always HTTP 200: Ok. with a Set-Cookie: SID=… header, or Fails. (same answer for any wrong credential). A JSON body is not read: send a form.

The SID session expires after 1 hour without a request (each authenticated request renews it), at most 256 exist at once (the oldest is dropped), and all are lost when Hydranos restarts, so clients log in again. The cookie is Path=/; HttpOnly; SameSite=Lax, without Secure, so it works over plain HTTP. It also opens the whole native REST API: treat it like the API key.

Every other shim route requires authentication; a script can instead send the API key as an X-Api-Key header or an apikey query parameter. An unauthenticated shim call gets 403 Forbidden. (plain text) like real qBittorrent (the native REST API answers 401). POST /api/v2/auth/logout ends the session and needs no credentials.

Account, API key and exposure rules are on Security and Access.

# Log in (admin account, or any username + YOUR_API_KEY as password), keep the cookie
curl -i -c jar.txt \
  --data-urlencode 'username=admin' --data-urlencode 'password=YOUR_PASSWORD' \
  http://hydranos.example.org:8199/api/v2/auth/login

# Or skip the login and send the key
curl -H 'X-Api-Key: YOUR_API_KEY' http://hydranos.example.org:8199/api/v2/app/version

Supported endpoints

full = as qBittorrent; partial = works, differences listed; constant = fixed values; refused = answers 409 with the reason as plain text and changes nothing.

Endpoint Verbs Fidelity What Hydranos does
auth/login POST full See Logging in.
auth/logout POST full Revokes the session and expires the cookie.
app/version any constant v4.6.0.
app/webapiVersion any constant 2.9.3.
app/buildInfo any constant A real qBittorrent 4.6.0's library versions (qt 6.5.3, libtorrent 2.0.9.0…), none used by Hydranos.
app/preferences any partial Real: dht, pex, listen_port, max_connec, max_uploads_per_torrent, queueing_enabled, max_active_downloads, the slow-torrent keys (dont_count_slow_torrents, slow_torrent_*) (all from [race]); max_active_uploads/max_active_torrents (from [race] when queueing is on, else 50/100); lsd; up_limit/dl_limit (client-wide caps, bytes/s, 0 = none); the share-limit keys (max_ratio_enabled, max_ratio, max_seeding_time*, max_inactive_seeding_time*, max_ratio_act) of the race engine; save_path (empty until a client sets it with setPreferences); web_ui_port (= api_port); create_subfolder_enabled (= [daemon] create_torrent_folder). Constants: encryption 1, locale en, *_enabled extras false.
app/setPreferences POST partial Applies share limits, speed caps, dht/pex/lsd, active counts, the slow-torrent rule and save_path; other keys answer 200 and do nothing. Each of these is written (on every local engine) only when it differs from what app/preferences shows, so posting back the page unchanged changes nothing, [hoard] values included. See Limits.
app/defaultSavePath any full The save_path set through setPreferences, empty otherwise.
transfer/info any partial dl_info_data/up_info_data = bytes moved this session; speeds = sum of all engines; dht_nodes real; *_rate_limit = the client-wide caps. connection_status always connected.
transfer/uploadLimit, transfer/downloadLimit any full The client-wide cap, bytes/s, 0 = none.
transfer/setUploadLimit, transfer/setDownloadLimit POST full limit in bytes/s, 0 or negative = none; one cap over every engine of this host, kept across restarts. 400 without limit.
sync/maindata any partial Always full_update: true (never a delta): torrents (the torrents/info rows keyed by hash), categories, tags, server_state; trackers is {}; rid grows for the whole process.
torrents/info any partial See The torrent list as *arr sees it below.
torrents/count any full How many rows the unfiltered torrents/info lists.
torrents/properties any partial Real: transfer totals, share_ratio, seeding_time, eta, session totals, average speeds, peers (connected), peers_total/seeds_total (tracker), creation_date, created_by, comment (read from the stored .torrent, creation_date -1 if absent), up_limit/dl_limit, share-limit keys. seeds and total_wasted are 0. Full 40-character hash; 404 if unknown.
torrents/files any partial Real: names (multi-file names start with the torrent's folder), sizes, piece_range, per-file progress, priority (1, 6 or 7, never 0), is_seed. availability is always 1.
torrents/trackers any partial ** [DHT] **, ** [PeX] ** (status 2, counts 0), ** [LSD] ** (status 0 with This torrent is private or LSD is off for this engine, else 2 with the LAN peers found), then the real trackers with their tier. status is one value for the whole torrent: 1 not contacted yet, 2 working, 4 last announce failed (with msg); num_peers and num_downloaded 0. 404 for an unknown hash.
torrents/export any full The stored .torrent (application/x-bittorrent); 404 if none.
torrents/add POST partial See Adding torrents through the shim.
torrents/delete POST full hashes, deleteFiles=true|1. Removes every copy of the torrent, in every engine. Files shared with another loaded torrent are kept. Always 200.
torrents/pause, torrents/stop POST full Stop (persisted user intent) on every copy. pause and stop are the qBittorrent 4 and 5 names of the same call.
torrents/resume, torrents/start POST full Start every copy.
torrents/recheck POST full Hash-checks every copy, guarded like Recheck in the right-click menu: if a file is also named by another torrent with other content, the copy is stopped and those files are hashed first; it is rechecked (and restarted if it was running) only if they verify, otherwise it stays stopped in error with the reason. Always 200; the log line qbit bulk recheck counts the copies checked and the ones refused (a copy removed in the meantime); a magnet still resolving has no copy yet and is skipped.
torrents/reannounce POST full Asks the announce scheduler of every copy for an announce now. Always 200; the counts go to the log.
torrents/setLocation POST partial hashes, location: one move job per copy, as Set location… (Jobs tab). 400 without location; 409 with the reason when nothing could be queued.
torrents/setShareLimits POST partial ratioLimit and seedingTimeLimit (minutes) required (400 otherwise), inactiveSeedingTimeLimit optional; -2 = follow the engine, -1 = no limit. See Limits.
torrents/setForceStart POST partial value=true marks every copy forced (as Force download) and starts it: the queue runs it past any ceiling without counting it. value=false lifts the mark. Rows still report force_start: false.
torrents/uploadLimit, torrents/downloadLimit any full {hash: bytes/s}, 0 = none.
torrents/setUploadLimit, torrents/setDownloadLimit POST full hashes, limit (bytes/s, 0 or negative = none), on every copy. 400 without limit.
torrents/filePrio POST partial hash, id (|-separated), priority 1, 6 or 7: the order files are fetched in. Priority 0 is refused: every file is always downloaded. 400 for a missing or invalid priority, 409 for a file id out of range.
torrents/toggleSequentialDownload, torrents/toggleFirstLastPiecePrio POST full Flips the flag; every copy takes the new value of the first.
torrents/rename POST refused The name is the .torrent's. 404 for an unknown hash.
torrents/topPrio, bottomPrio, increasePrio, decreasePrio POST refused Torrent queueing is not enabled when no engine holding the torrents runs a queue; otherwise a reason saying Hydranos orders its queue itself and that force start runs a torrent past it.
torrents/categories any partial {name: {"name", "savePath"}}. The category's mode is not shown.
torrents/createCategory POST partial category, savePath. Always creates mode hoard; an existing name answers 409 Category already exists.
torrents/editCategory POST partial Changes the save path only; creates a hoard category if the name is unknown.
torrents/removeCategories POST full categories, separated by newlines or commas. The torrents lose the label.
torrents/setCategory POST partial hashes, category (empty = clear). Label only: no file move, no engine change, no check that the category exists.
torrents/tags any full The registered tags.
torrents/createTags POST full Registers tags.
torrents/deleteTags POST full Removes the tags from the list and from every torrent.
torrents/addTags, torrents/removeTags POST full hashes, tags (comma-separated). Applied to every copy.
torrents/addTrackers, torrents/removeTrackers POST partial Form field hash (singular, full hash) and urls (newline- or |-separated). Each added URL becomes its own tier at the end, and the copies announce to it straight away. 400 if a field is empty or if the torrent was added seconds ago and its .torrent is not stored yet (retry shortly); 404 for an unknown torrent.
rss/* (13 routes) POST; items, rules, matchingArticles any full qBittorrent's RSS API: addFolder, addFeed, setFeedURL, removeItem, moveItem, refreshItem, markAsRead, items, setRule, renameRule, removeRule, rules, matchingArticles. 400 Missing parameter: X or a malformed value, 409 for a refusal. See RSS and Automatic Downloads.

Notes:

  • hashes is split on | or ,; all means every torrent of every engine. Write endpoints taking hashes accept a hash prefix (the first stored torrent that matches wins) and answer an empty 200 like qBittorrent, even when no hash matched: check with torrents/info, not the status code. Exceptions: the refused and 400 cases above, addTrackers/removeTrackers (hash, no all), createCategory (400 on an empty name, 409 on an existing one), torrents/add (Ok./Fails.). Calls taking a single hash (properties, files, filePrio, rename) need the full hash.
  • Where parameters are read: the read calls (torrents/info, properties, files, trackers, export) and the calls added in 4.4 (setLocation, setShareLimits, setForceStart, the limit calls, filePrio, the toggles, rss/*) take them from the query string or a form body (cross-seed sends everything as a POST form). The older write calls (stop, start, delete, recheck, reannounce, tags, categories, trackers) read the form body only.
  • Actions by hash reach every copy, extra engines included. To target one copy, use ?engine= on the REST API.

Endpoints that do not exist

These routes are not registered. They answer HTTP 404 (a wrong verb on an existing route answers 405):

torrents/ setSuperSeeding, setAutoManagement, renameFile, renameFolder, editTracker, pieceStates, pieceHashes, webseeds; app/shutdown; transfer/ banPeers, toggleSpeedLimitsMode, speedLimitsMode; sync/torrentPeers; log/*, search/*.

The shim still reports WebAPI 2.9.3, so a tool may try them. For search, keep Prowlarr or autobrr.

The torrent list as *arr sees it

torrents/info is the call Sonarr, Radarr, autobrr and cross-seed poll. It accepts, from the query string or a form body:

Parameter Behaviour
category Exact match on the category a row is reported under (see category below).
filter all, downloading, seeding, completed, paused = stopped, active, inactive, stalled, stalled_uploading, stalled_downloading, errored, resumed = running. An unknown value lists everything.
tag One tag, exact match.
hashes Full hashes separated by | or ,. all means no filter.
sort, reverse Any row field; default added_on. reverse=true inverts.
limit, offset Paging; 0 or absent = no limit.

Every engine is listed, and each torrent once: the first engine holding it answers, in the order race, hoard, then the extra engines. A torrent held by both race and hoard is therefore reported as its race copy (race's save_path and content_path, and race as the fallback category). torrents/count and sync/maindata list the same rows.

Row fields

Field Value
hash, name, size/total_size, progress, dlspeed, upspeed, added_on, completion_on, tags Real.
num_seeds/num_complete, num_incomplete The tracker's seeders and leechers (last announce or scrape).
num_leechs Peers connected now.
category The torrent's category; an uncategorised torrent is reported under its engine name (race, hoard or the extra engine's id).
save_path The folder the engine holds the data in.
content_path save_path + / + name. This is the path *arr imports from and cross-seed links from.
state See the next table.
uploaded, downloaded, ratio The torrent's lifetime counters; ratio = uploaded / downloaded, two decimals. A complete torrent whose download counter is 0 (added in seed mode) reports downloaded = size.
amount_left, completed Complete: 0 and the size. Incomplete: size minus the bytes downloaded, and the bytes downloaded.
eta Bytes left divided by the current download rate; 8640000 (qBittorrent's "infinite") when nothing is received.
seeding_time Seconds of seeding.
tracker The first URL of the torrent's tracker list (the list it announces to); empty for a torrent without trackers.
up_limit, dl_limit The torrent's own speed caps, bytes/s, -1 = none.
seq_dl, f_l_piece_prio Sequential download and first/last piece first, as set.
ratio_limit, seeding_time_limit, inactive_seeding_time_limit The torrent's own share limits (-2 = follow the engine).
max_ratio, max_seeding_time, max_inactive_seeding_time The limits in force for it (-1 = none).
time_active Now minus added_on.
availability, seen_complete, priority, auto_tmm, super_seeding, force_start, magnet_uri 0, false or empty.

Absent: infohash_v1, private, trackers_count, last_activity.

Since 4.4 uploaded and ratio are the real figures (4.3 kept them at 0). A seed goal set in Sonarr, Radarr, Lidarr or an autobrr rule now acts on them, and can remove torrents: see Application recipes.

States

Hydranos situation state
You stopped it (persisted, survives restarts) stoppedUP (complete) / stoppedDL
Held by the engine without a stop from you (for example waiting for a download slot, or a seeding slot under queueing); moves on by itself queuedUP / queuedDL
Seeding, uploading now / not uploading now uploading / stalledUP
Downloading, receiving now / not receiving downloading / stalledDL
Hash check running checkingDL (also for complete torrents)
Error error
Anything else stalledUP / stalledDL

Never returned: pausedUP/pausedDL, forcedUP/forcedDL, metaDL, missingFiles, checkingUP, checkingResumeData, moving, allocating (a torrent being moved keeps its state). A magnet still waiting for metadata is not listed at all. The paused/stopped filter matches stopped* rows only.

Adding torrents through the shim

POST /api/v2/torrents/add is a multipart form:

Field Read? Meaning
torrents, file, fileselect yes .torrent file parts; several allowed.
urls yes One per line. magnet:? links are resolved in the background; http(s) links are downloaded (30 s timeout, 15 MiB max, no cookies).
category yes Picks the engine (category mode) and the save path.
savepath yes Overrides the category's save path.
autoTMM yes true: when the category has a save path, savepath is ignored.
tags yes Comma-separated.
paused, stopped yes true or 1: add stopped.
stopCondition yes MetadataReceived or FilesChecked: add stopped.
skip_checking yes true or 1: seed mode, no hash check of data already on disk. Magnets too (applied when the metadata arrives).
upLimit, dlLimit yes The torrent's speed caps, bytes/s; 0 or negative = none.
ratioLimit, seedingTimeLimit, inactiveSeedingTimeLimit yes The torrent's own share limits, as setShareLimits (minutes; -2 follow the engine, -1 none). See Limits.
contentLayout yes Original, Subfolder (a single file gets a folder) or NoSubfolder; wins over root_folder. NoSubfolder on a multi-file torrent is refused: the engine always writes it under its folder.
root_folder yes Older form: true = Subfolder, false = NoSubfolder. With neither field, [daemon] create_torrent_folder decides.
sequentialDownload, firstLastPiecePrio yes Download order (Adding Torrents and Existing Data).
any other field no Ignored (callout below).

Accepted but ignored in 4.4: the add fields rename and cookie (and any other unknown field) look like per-torrent options — Hydranos ignores them and logs qbit add: these fields have no effect in Hydranos — the torrent keeps the name from its .torrent; a .torrent URL needing a cookie must be fetched by the tool and sent as a file.

What decides the answer:

  • Placement. A known category gives the engine (hoard mode → hoard, anything else → race) and its save path; an unknown category goes to race. With no folder from savepath or the category, the folder a client set with setPreferences save_path is used; if there is none either, the add is refused (log: no save path: category "X" is unknown and no savepath was given). The shim cannot name an engine.
  • Already added (same torrent already in that engine) counts as success.
  • Answer: Ok. (200) if at least one item was accepted; Fails. (HTTP 400) if every item was refused; Bad request (400) if there was neither a file nor a URL. Exception: an http(s) .torrent URL that downloads but whose add is then refused (for example no save path) still gets Ok.; check torrents/info or the log.
  • Magnets: Ok. means resolution has started. The torrent enters the engine, and torrents/info, only when its metadata arrives; until then it sits in the Magnets card of the + Add Torrent tab (retried a few times, then kept there with the reason). The add options (caps, share limits, download order, layout, skip_checking) are kept with the request and applied once it resolves; a NoSubfolder magnet that turns out multi-file fails there with that reason.
  • Data already on disk is hash-checked unless skip_checking is set. "On add" workflows run (for magnets, once resolved). The request body is limited to 2 MB.

Magnets, seed mode, .torrent URLs and dedup are explained on Adding Torrents and Existing Data.

H=http://hydranos.example.org:8199

# A .torrent file into the category "tv"
curl -b jar.txt -F '[email protected]' -F 'category=tv' $H/api/v2/torrents/add

# A magnet (use --form-string so curl does not interpret ; or @)
curl -b jar.txt \
  --form-string 'urls=magnet:?xt=urn:btih:0123456789abcdef0123456789abcdef01234567&tr=https://tracker.example.org/announce' \
  -F 'category=tv' $H/api/v2/torrents/add

# Seed mode on data already in place, explicit folder
curl -b jar.txt -F '[email protected]' -F 'savepath=/data/movies' -F 'skip_checking=true' $H/api/v2/torrents/add

# List a category, remove a torrent with its files
curl -b jar.txt "$H/api/v2/torrents/info?category=tv&filter=downloading"
curl -b jar.txt -d 'hashes=0123456789abcdef0123456789abcdef01234567&deleteFiles=true' $H/api/v2/torrents/delete

This is what Hydranos receives from autobrr when it sends a magnet:

sequenceDiagram
    participant AB as autobrr
    participant SH as Hydranos qBittorrent shim
    participant MR as Magnet resolver BEP 9
    participant EN as Engine race or hoard
    AB->>SH: POST auth/login (username, password)
    SH-->>AB: 200 Ok. and SID cookie
    AB->>SH: POST torrents/add (urls = magnet link, category)
    alt no savepath, no category save path, no preferences save_path
        SH-->>AB: 400 Fails.
    else placement found
        SH->>MR: store the magnet request and start resolving
        SH-->>AB: 200 Ok.
        MR->>MR: fetch metadata from peers and check it against the info hash
        MR->>EN: add the torrent at its save path (savepath, category or setPreferences), started unless added stopped
    end
    AB->>SH: POST torrents/reannounce (hashes)
    Note over SH,EN: a magnet still resolving has no copy yet, nothing is announced
    SH->>EN: announce now, every copy
    SH-->>AB: 200 (empty body)
Loading

Categories and tags through the shim

Create your categories in Hydranos (tab Categories, + New: Name, Mode Race/Hoard, Save Path) before you point a tool at them, and use the same names in the tool. The shim's category calls cannot set a mode:

  • createCategory always stores mode hoard. On a name that already exists it answers 409 Category already exists and leaves the category alone (mode, Graduate to and transit settings kept).
  • A category created by a tool with an empty savePath is stored without a save path, and every later add into it is refused unless the tool sends savepath (or has set a default folder with setPreferences save_path).
  • setCategory changes the label only; data and engine stay put. To move the data, use Change category + move files › in the web UI (see Categories and Routing).

Tags are labels with no effect on placement (Categories and Routing). deleteTags removes a tag from the list and from every torrent; removeCategories also clears that label from the torrents.

Application recipes

Each application uses its qBittorrent download-client type; unlisted settings stay at their defaults. Below, hydranos stands for the host, which depends on where Hydranos runs:

  • same Docker network as the application: the service name, hydranos;
  • behind a gluetun container (network_mode: "service:gluetun"): gluetun, because Hydranos has no network of its own and the name hydranos resolves to nothing (VPN and Egress);
  • different networks, or not sure (for example Unraid's default bridge): the host machine's LAN address, e.g. 192.0.2.10, with port 8199 published.

Paths. The shim reports save_path and content_path as Hydranos sees them. Mount the same host folder at the same container path in both containers (Docker), or add a remote path mapping in the application (host = the host above, remote = Hydranos path, local = its own path).

Mode per category. If unsure, file your categories as Hoard. Race is for racing fresh uploads, and the race drain can delete race torrents with their data or move them (Race Drain and Graduation).

Sonarr / Radarr / Lidarr

Settings › Download Clients › + › qBittorrent:

Setting Value
Host hydranos
Port 8199
Use SSL off (on only behind a TLS reverse proxy, with its port)
URL Base empty
Username / Password the admin account, or any username + the API key as password
Category an existing Hydranos category, e.g. tv (Sonarr), movies (Radarr), music (Lidarr)
Post-Import Category empty, or an existing category: it only relabels the torrent (no move)
Recent / Older Priority Leave at the default, Last: the queue-position calls answer 409 (as qBittorrent with queueing off)
Initial State Start or Stop. Force Start starts the torrent and runs it past the engine's queue (active_downloads, 10 in hoard as shipped)
Sequential Order, First and Last First Applied (download order)
Content Layout Applied; No subfolder is refused for a multi-file torrent, keep Original

Seed ratio and seed time (indexer settings) now work both ways:

  • they arrive with the add as ratioLimit / seedingTimeLimit and become the torrent's own share limits in Hydranos;
  • Sonarr/Radarr read the real ratio and seeding_time, so their own seed-goal check can now be met (and remove the torrent if removal of completed downloads is enabled in the application; not tested by the maintainer).

Hydranos's own share limit, however, is held (log share limit reached, held) until the tracker's declared minimum seeding time is served, and forever for a tracker with no announce_min_seed_hours declared (a torrent with no tracker at all is not held); when it acts, it applies the engine's share_limit_action (stop by default), not a per-torrent action. See Queue, Share and Speed Limits. A workflow remains the other way to clean up after seeding.

If Test fails, check the host, port and credentials. Create the category in Hydranos first: Sonarr and Radarr usually call createCategory only for a category missing from torrents/categories, so an existing one is left alone, but one they create has no save path and every add into it is refused (not tested by the maintainer).

autobrr

Settings › Clients › Add new: type qBittorrent, host http://hydranos:8199, username and password as above (or the API key as password). In a filter's action, choose this client and set:

Action setting Effect in Hydranos
Category Must exist in Hydranos with a save path, or set Save Path.
Save Path Sent as savepath; overrides the category's folder.
Tags Applied.
Add paused (label may vary by version) Applied (added stopped).
Skip hash check Applied, magnets included (once resolved).
Reannounce (interval, attempts) Works (torrents/reannounce).
Upload/download limits Applied (the torrent's own caps).
Ratio limit, seed time limit Stored as the torrent's share limits; same tracker-minimum hold as above.
Content layout Applied; NoSubfolder refused for a multi-file torrent.

autobrr sends magnets through urls (supported). Its client rules on speed, ratio or uploaded amount see the real values (transfer/info, torrents/info).

cross-seed

Point cross-seed at the shim with a URL that carries the credentials, then use injection:

// cross-seed config.js (v6 syntax; v5 uses qbittorrentUrl: "http://…" instead)
torrentClients: ["qbittorrent:http://admin:YOUR_PASSWORD@hydranos:8199"],
// or, with the API key: "qbittorrent:http://cross-seed:YOUR_API_KEY@hydranos:8199"
action: "inject",
skipRecheck: true,
  • cross-seed injects with an explicit savepath and, for full matches, skip_checking=true: Hydranos adds the torrent in seed mode at that folder. Partial matches are sent for a recheck (not tested by the maintainer).
  • The category cross-seed sends decides the engine. A category unknown to Hydranos still works because cross-seed sends a save path, but the torrent then lands in the race engine, where the drain can remove it. Create the categories cross-seed uses in Hydranos with mode hoard and a save path; with duplicateCategories it sends <category>.cross-seed, so create those too.
  • Every engine is listed, so cross-seed also matches torrents held by extra engines (it injects into race or hoard, by category). A torrent held by race and hoard is seen once, as its race copy.
  • cross-seed sends its calls as POST forms: torrents/files, properties, trackers, export and info read the hash from the body. torrents/files gives names under the torrent's folder and real piece ranges, so its matching sees the true layout.

Prowlarr

No direct role: Prowlarr feeds indexers to Sonarr, Radarr and Lidarr. To grab from its search page, add Hydranos as a download client with the Sonarr settings above.

Limits

  • Share limits (setShareLimits, ratioLimit/seedingTimeLimit at add, setPreferences max_ratio*): stored and shown, but they act only once the tracker's declared minimum seeding time (announce_min_seed_hours) is served, and never for a tracker without one (a torrent with no tracker at all is not held); the action is the engine's share_limit_action. Details: Queue, Share and Speed Limits.
  • app/setPreferences needs a json field or a JSON body (400 without; a relative save_path is 400 before anything is written). Applied, to every local engine: max_ratio*, max_seeding_time*, max_inactive_seeding_time* (each value only with its *_enabled), max_ratio_act (2, super seeding, is logged and leaves the action unchanged), up_limit/dl_limit (live), max_active_downloads (live), max_active_uploads/max_active_torrents (only if queueing is already on), dont_count_slow_torrents and the slow_torrent_* keys, save_path, and dht, pex, lsd (written to the file, used at the next start). queueing itself cannot be switched through the shim.

Accepted but ignored in 4.4: other setPreferences keys (listen port, encryption, alternative speed limits…) look saved — they answer 200 and change nothing, logged as setPreferences: these keys have no effect in Hydranos — use the Config tab or default.toml.

Not implemented in 4.4: selective download — filePrio 0 (do not download) is refused with 409 and every file is always downloaded — priorities 1/6/7 only change the order. Also missing: a delta from sync/maindata (always a full update), per-tracker status and peer counts in torrents/trackers, seeds/total_wasted in properties, availability anywhere.

Other missing qBittorrent features: Migrating from qBittorrent.

See also

Migrating from qBittorrent (step-by-step switch, Sonarr add sequence) · Categories and Routing · Adding Torrents and Existing Data · Security and Access · Trackers and Announces · Queue, Share and Speed Limits · RSS and Automatic Downloads · REST API

⚠️ **GitHub.com Fallback** ⚠️