Organizarr watches qBittorrent and organizes torrents for you — on your terms. Every polling cycle it tracks each torrent’s state and lifecycle, and applies either your own rules or a small set of sensible, fully tunable defaults.
Out of the box, nothing is ever taken away from you: a torrent that finishes downloading is sent to a Seeding category and keeps seeding. What happens beyond that — re-categorizing, tagging, moving payloads into your library tree, pruning old seeds, deleting to the trash, or removing entries from the client — is entirely up to your configuration, including what happens to the torrent inside qBittorrent itself after its files are moved (after_move: keep_seeding | stop | remove).
This makes it a natural companion to pipelines where completed downloads are handed off to other tools (e.g. Sonarr/Radarr/Lidarr post-import categories) — the missing organizational link in the *arr ecosystem.
-
Recognizes every qBittorrent state (4.x and 5.x API spellings): downloading, queued, stalled, seeding, stopped/paused, forced, checking, moving, errored, missing files, metadata fetching, allocating, …
-
Detects state transitions between polling cycles ("finished downloading", "became errored", …) and logs every one.
-
Judges whether a download is actually complete from real transfer data (
progress,amount_left,completion_on) — so a torrent queued, stopped, or errored at 100% is treated as finished, and one stopped halfway is left alone. -
Only ever touches payloads in provably safe states; torrents qBittorrent is relocating (
moving) or re-verifying (checking) are skipped until they settle.
-
Configurable rules engine: match on state, state transition, category, tag, completeness, seed time, or ratio — then set categories, add/remove tags, stop/start/recheck, move files, remove, or delete. First matching rule wins; rules always override the built-in defaults. See Rules.
-
Exactly three default behaviors — nothing else happens without your say-so, and each can be tuned or disabled (see Default Behaviors):
-
🌱 Send to Seeding — finished torrents are re-categorized to
Seeding(created via the API if missing) and their tags cleared. They keep seeding. -
⏳ Forced-seeding limit — forced (
forcedUP) torrents active longer than 7 days (and/or over a ratio you set) are deleted. -
🗑️ Delete-to-trash — deletions go to the OS trash / recycle bin; when the trash is unavailable, the torrent is parked in a
Deletecategory and retried until it succeeds.
-
-
You decide what a "move" means (
after_move): let qBittorrent relocate the payload and keep seeding it (default), leave the stopped entry in the client, or remove the entry keeping the files. -
ignore_categories: a hard shield — listed categories are never touched by any rule or behavior.
-
Category → directory mappings move completed payloads into your library/archive tree — or set a destination to
autoand it follows the save path configured inside qBittorrent, re-read every cycle so changes made in the client always win. See Configuration Discovery. -
Uses the torrent’s
content_path, so renamed torrents are moved correctly. -
Remaps container/seedbox paths to local paths (
path_prefix/root_path) — and back again for client-side relocations. Remote path mappings you already maintain in Sonarr/Radarr/Lidarr can be imported automatically instead of duplicated. -
Stop-before-move (5.x
stop/ 4.xpause) so file handles are released; rename when possible, copy + delete across filesystems; never overwrites an existing destination. -
Every flow is retry-safe: a cycle interrupted mid-move is finished cleanly on the next one.
-
Torrents that error before completing are recovered automatically: recheck + restart with per-torrent exponential backoff (1 min doubling up to 1 h).
-
Torrents that error after completing (e.g.
missingFiles) follow your configurederrored_completed_action: keep, remove the entry, or remove with data (honoring qBittorrent’s own trash preference).
-
Purpose-built to complement the arr suite’s *Post-Import Category flow (Sonarr, Radarr, Lidarr) — see *arr Suite Integration.
-
Opt-in configuration discovery: reuse the directory configuration your ecosystem already has — qBittorrent category save paths (
autodestinations) and *arr remote path mappings — instead of maintaining it twice. Changes made in the client apps always take precedence. See Configuration Discovery. -
Documented compatibility with the wider ecosystem: unpackerr, Overseerr/Jellyseerr/Ombi, Requestrr, slskd/Nicotine+, Plex/Jellyfin/Emby — see Ecosystem Compatibility.
-
Supports multiple qBittorrent instances, WebUI auth or auth bypass, and rate-limited polling.
-
Scales to clients with thousands of torrents: paged listing (500/page) and bounded concurrency (
max_concurrent_moves). -
Prebuilt release binaries for Windows (x64, x86), macOS (arm64, x64), and Linux (x64, arm, arm64, musl-x64, musl-arm64).
-
Ships with a
Dockerfileand a fill-in-the-blanksdocker-composeexample — see Running in Docker. -
Single YAML config file; console + rolling file logging.
-
Rust (latest stable version recommended).
-
qBittorrent with Web UI enabled (qBittorrent 4.2 or newer recommended).
Grab the archive for your platform from the releases page — Windows (windows-x64, windows-x86), macOS (osx-arm64, osx-x64), and Linux (linux-x64, linux-arm, linux-arm64, linux-musl-x64, linux-musl-arm64) — extract it, and run the organizarr binary. The musl builds are fully static and run on Alpine, NAS appliances, and minimal containers.
-
Before running the tool, ensure you’ve set up the
config.yamlfile (see Example Configuration) with your qBittorrent server details and desired settings. -
Execute the binary:
$ ./target/release/organizarr
-
The tool will now monitor qBittorrent for completed torrents and move them based on your configurations.
We welcome contributions! If you find a bug or want to propose a new feature:
-
Fork the repository.
-
Create a new branch for your changes.
-
Make your changes.
-
Submit a pull request.
Special thanks to Harrison Chin, the original author of the project this repository was built from. His work laid the foundation — the core idea of a lightweight, category-driven qBittorrent companion — upon which everything here was developed. Organizarr would not exist without that basis.
If you have any questions or feedback, please open an issue on GitHub. We appreciate your input!
This is an example of what your config.yaml should look like.
Fill in the placeholders with your actual data.
If the file does not exist, a default template is created on first run.
servers:
- qbit_url: "http://localhost:8080"
username: "admin" # leave empty ("") if WebUI auth bypass is enabled
password: "adminadmin"
categories:
distros: "/path/to/distros/directory"
# or follow the save path configured inside qBittorrent for a
# category (re-read every cycle; client changes win — see
# "Configuration Discovery"):
#movies: auto
# Optional: what happens to the torrent in qBittorrent after its files
# are moved (categories mappings and move_files rule actions):
# keep_seeding (default) - qBittorrent relocates the payload itself
# (setLocation) and KEEPS SEEDING it
# stop - move host-side, leave the stopped entry
# remove - move host-side, remove the entry (files kept)
#after_move: keep_seeding
# Optional: remap paths when qBittorrent reports paths that differ from
# this machine's view of the filesystem (e.g. Docker or remote mounts).
# path_prefix is stripped from the path qBittorrent reports, and
# root_path is prepended in its place. Omit both if paths match.
#root_path: "/mnt/seedbox"
#path_prefix: "/downloads"
# Optional: import remote path mappings you already maintain in your
# *arr apps instead of duplicating them here (Sonarr/Radarr use API v3,
# Lidarr/Readarr v1 — negotiated automatically). Mappings are verified
# against this machine's filesystem and refreshed so changes made in
# the *arr app take precedence. See "Configuration Discovery".
#arr:
# - name: sonarr
# url: "http://localhost:8989"
# api_key: "YOUR_SONARR_API_KEY"
# #host: gluetun # only mappings for this download-client host
# #refresh: "60s" # re-read interval (default 60s)
# Optional: categories this tool must NEVER touch in any way.
# Protect the *active* download categories of other tools here.
#ignore_categories: ["tv-sonarr", "radarr", "lidarr"]
# Optional: tune or disable the built-in default behaviors
# (see "Default Behaviors" below). Shown here with their defaults;
# uncomment only what you want to change.
#behaviors:
# send_to_seeding:
# enabled: true # set false to disable the behavior
# category: "Seeding" # category finished torrents are moved to
# create_category: true # create it via the API if it doesn't exist
# clear_tags: true # remove all tags when re-categorizing
# forced_seeding_limit:
# enabled: true
# max_time_active: "7d" # s/m/h/d/w units; null disables the time check
# max_ratio: null # e.g. 2.0; null disables the ratio check
# delete:
# use_trash: true # host-side trash; false = qBittorrent deletes
# fallback_category: "Delete" # parking spot when the trash fails
# Optional: user-defined rules — full control over every state and
# state change (see "Rules" below). First matching rule wins and
# overrides all default behaviors for that torrent.
#rules:
# - name: "archive finished music"
# when:
# from_states: [downloading]
# states: [uploading, stalledUP]
# categories: [music]
# then:
# - action: set_category
# with: "music-archive"
# - action: add_tags
# with: ["processed"]
rate_limit_delay: 5 # seconds between polling cycles
log_file: "organizarr.log"
max_log_file_size: "10M" # accepts K/M/G with optional B suffix, e.g. "10MB"
max_concurrent_moves: 2 # max simultaneous file operations per server
errored_completed_action: remove # keep | remove | remove_with_dataNotes:
-
Torrents whose category appears in
categoriesfollow the move flow below. Other torrents are subject only to your rules and the three default behaviors; torrents inignore_categoriesare never touched by anything. -
The tool tracks each torrent’s state (downloading, queued, stalled, seeding, stopped, checking, moving, errored, …) and logs every state transition, including when a download finishes and when a torrent becomes errored.
-
Files are only moved in provably safe states (seeding, stalled, queued, stopped, or forced seeding — i.e. download finished and payload idle). Torrents that qBittorrent is itself relocating (
moving), re-verifying (checking), or that are errored/missing files are skipped until they reach a safe state. -
Whether a download is actually complete is judged from transfer data (
progress,amount_left,completion_on), not just the state name — so a torrent stopped or queued at 100% is moved, while one stopped halfway is left alone. -
What a "move" is depends on
after_move:-
keep_seeding(default) — the move is delegated to qBittorrent (setLocation): it relocates the payload itself and keeps seeding it from the destination. The torrent stays in the client under your control (rules, forced-seeding limit, …). The destination must be a path qBittorrent can see; a destination underroot_pathis automatically translated back to qBittorrent’s view of the filesystem. -
stop— this tool stops the torrent, moves the payload host-side (rename when possible, copy + delete across filesystems; existing destinations are never overwritten), and leaves the stopped entry in qBittorrent. -
remove— asstop, but the entry is then removed from qBittorrent (its files are kept).
-
-
Before a host-side move, the torrent is stopped (works with both the qBittorrent 5.x
stopand 4.xpauseAPI) so qBittorrent releases its file handles. -
Moves are retry-safe: an already-relocated torrent is a no-op, and if a cycle moves the files but fails the follow-up step, the next cycle finishes the job.
-
Torrent lists are fetched in pages of 500 and moves run at most
max_concurrent_movesat a time, so clients saturated with thousands of torrents don’t overload this tool or the disk.
The action taken for an errored torrent depends on where in its life the error occurred:
-
Before/during download (payload incomplete): the tool attempts recovery — a recheck followed by a restart (
starton 5.x,resumeon 4.x) — with per-torrent exponential backoff (1 min, 2 min, 4 min, … capped at 1 h), so a persistently broken torrent is not hammered every polling cycle. Recovery is non-destructive and applies to all torrents, mapped or not. -
After a completed download (e.g.
missingFilesbecause the payload was already imported/moved): the configurederrored_completed_actionis applied, but only to torrents in a mapped category:-
keep— leave the torrent alone and log a warning. -
remove(default) — remove the torrent from qBittorrent, keeping any files. -
remove_with_data— remove the torrent and let qBittorrent delete its files too; this honors qBittorrent’s own "move to trash" preference.
-
Out of the box this tool has exactly three default behaviors — no more. Each can be tuned or disabled under behaviors: per server, and user-defined rules always take precedence over all of them. Torrents in ignore_categories are never touched by anything.
When a torrent finishes downloading (detected as a real state transition between polling cycles — torrents that were already finished when this tool starts are left alone), its category is overwritten with the seeding category (Seeding by default) and all of its tags are removed. The category is created through the qBittorrent API if it does not exist yet.
-
Torrents whose category is mapped in
categoriesare exempt — they follow the move flow instead. -
Torrents already in the seeding category, in an ignored category, or matched by a rule are exempt.
-
Tune with
behaviors.send_to_seeding:enabled,category,create_category,clear_tags.
Torrents in forced seeding (forcedUP) bypass qBittorrent’s own share limits, so they can seed forever. By default, a forced-seeding torrent that has been active for more than 7 days is deleted (via the delete flow below). An optional ratio limit can be set as well; exceeding either limit triggers deletion.
-
Tune with
behaviors.forced_seeding_limit:enabled,max_time_active(acceptss/m/h/d/wunits,nulldisables the time check),max_ratio(null, the default, disables the ratio check).
Whenever this tool deletes a torrent’s payload (forced-seeding limit, the delete rule action, or retries from the fallback category), it moves the files to the OS trash / recycle bin on the machine it runs on (using the configured path remapping, so the host-side files are trashed), then removes the torrent entry from qBittorrent.
If trashing is not possible right now (e.g. the files live on a mount with no trash location), the torrent is parked in the fallback category (Delete by default, created on demand) and retried on every polling cycle until the trash becomes available. You can also drop torrents into that category yourself to queue them for deletion.
-
With
use_trash: false, deletion is delegated to qBittorrent (deleteFiles=true), which honors qBittorrent’s own "move to trash" preference — the right choice when this tool runs in a container without a meaningful trash directory. -
Tune with
behaviors.delete:use_trash,fallback_category.
Rules give you full control over what happens for any state, state change, category, or tag — this tool never locks you into a fixed flow. Rules are evaluated per torrent on every polling cycle, in the order written; the first rule whose when conditions all match wins, its then actions run in order, and all default behaviors are skipped for that torrent.
rules:
- name: "human-readable name for the logs" # optional
when: # ALL conditions must hold; omitted ones match anything
states: [uploading, stalledUP] # current state (qBittorrent API names)
from_states: [downloading] # previous cycle's state -> matches transitions
categories: [music] # category is one of these
tags: [keep] # has at least one of these tags
complete: true # download complete (judged from transfer data)
min_time_active: "30d" # active at least this long
min_ratio: 2.0 # share ratio at least this
then: # actions, applied in order
- action: set_category # overwrite category (created if missing)
with: "music-archive"
- action: add_tags
with: ["processed"]Available conditions (when):
|
Current state, using qBittorrent API spellings: |
|
The state the torrent was in on the previous polling cycle. Combining |
|
The torrent’s category equals one of these (use |
|
The torrent carries at least one of these tags. |
|
|
|
The torrent has been active at least this long ( |
|
The share ratio is at least this value. |
Available actions (then), each written as action: plus an optional with: payload:
|
string |
Overwrite the torrent’s category (created via the API if missing). |
|
list |
Add tags (created automatically by qBittorrent). |
|
list |
Remove specific tags. |
|
— |
Remove all tags. |
|
— |
Stop (pause) the torrent (5.x |
|
— |
Start (resume) the torrent (5.x |
|
— |
Re-verify the payload on disk. |
|
string |
Move the payload to this directory, honoring the server’s |
|
— |
Remove the torrent from qBittorrent, keeping its files. |
|
— |
Remove the torrent and let qBittorrent delete its files (honors qBittorrent’s trash preference). |
|
— |
Delete the payload via this tool’s delete flow (host-side trash with fallback category). |
|
— |
Do nothing — shields matching torrents from the default behaviors and later rules. |
remove, remove_with_data, and delete are terminal: the torrent is gone afterwards, so any later actions in the same rule are skipped. move_files is terminal only with after_move: remove; with keep_seeding or stop the torrent is still in the client and later actions apply normally.
Examples:
rules:
# Keep anything tagged "keep" forever, out of reach of all defaults.
- name: "protected torrents"
when:
tags: [keep]
then:
- action: nothing
# Music finishing its download goes to an archive category instead of
# the default Seeding category.
- name: "archive finished music"
when:
from_states: [downloading, stalledDL, metaDL]
states: [uploading, stalledUP, queuedUP]
categories: [music]
complete: true
then:
- action: set_category
with: "music-archive"
- action: add_tags
with: ["processed"]
# Anything seeded past ratio 3 or 30 days of activity is deleted.
- name: "prune old seeds"
when:
complete: true
min_time_active: "30d"
then:
- action: deleteYour ecosystem already knows where everything lives: qBittorrent knows each category’s save path, and your arr apps maintain *remote path mappings — exactly the "path as the download client reports it" → "path as this machine sees it" table this tool needs in mixed environments (qBittorrent in a Docker container, this tool on the host, both touching the same filesystem). Configuration discovery lets you reuse that configuration instead of duplicating it.
Discovery is strictly opt-in and deliberately narrow: nothing is detected unless you ask for it, category by category and instance by instance, so a fresh install can never launch into behavior you didn’t configure.
Each ecosystem app was assessed for whether importing its configuration is useful and safe:
| Application | Discovered | Why / why not |
|---|---|---|
qBittorrent |
✅ Category save paths, per category via the |
The client’s own |
Sonarr / Radarr (API v3) |
✅ Remote path mappings, per instance via the |
Their remote path mappings are precisely the translation table this tool needs; import them instead of duplicating them. |
Lidarr / Readarr (API v1) |
✅ Remote path mappings (same |
Same resource, older API version; handled transparently. |
unpackerr |
❌ |
Configured purely by file/environment; exposes no API to read its paths from. |
Overseerr / Jellyseerr / Ombi / Requestrr |
❌ |
Request layers with no filesystem paths of their own — there is nothing to detect. |
slskd / Soulseek / Nicotine+ |
❌ |
Separate (non-BitTorrent) download pipelines; their paths never appear in qBittorrent, so importing them could only mislead. |
Set a mapped category’s destination to auto and the destination becomes whatever save path qBittorrent itself has configured for that category:
categories:
imported-movies: auto # follow qBittorrent's own save path for this category
imported-tv: 'G:\media\tv' # explicit destinations still work side by side-
The category list is fetched fresh every polling cycle, so if you change the category’s save path in qBittorrent the new value is used on the very next cycle — the client’s latest change always wins, no restart or config edit needed.
-
Detection is per category: only categories you explicitly set to
autoare affected. There is no "import all categories" mode, by design. -
A detected save path is qBittorrent’s own view of the filesystem. With the default
after_move: keep_seedingit is handed straight tosetLocation(qBittorrent moves the payload itself — path mapping not even required). Withstop/remove, this tool must translate it to its own view first: if no path mapping (explicit or imported) covers it, the torrent is skipped with a warning rather than moved into a fabricated local directory. -
If the category doesn’t exist in qBittorrent, has no explicit save path, or the category list can’t be fetched, affected torrents are skipped safely that cycle (with a warning explaining why).
-
A real directory literally named
autocan still be targeted by writing it as a path (./auto,/data/auto).
List the *arr instances to import from, and their remote path mappings join the translation table alongside your explicit path_prefix/root_path pair (the longest matching prefix wins):
servers:
- qbit_url: "http://localhost:8080"
arr:
- name: sonarr # label used in logs (optional)
url: "http://localhost:8989"
api_key: "YOUR_SONARR_API_KEY" # Settings -> General -> API Key
#host: gluetun # only import mappings for this download client host
#refresh: "60s" # how often to re-read the mappings (default 60s)
- name: radarr
url: "http://localhost:7878"
api_key: "YOUR_RADARR_API_KEY"-
Works with Sonarr and Radarr (API v3) and Lidarr and Readarr (API v1) — the version is negotiated automatically, so there is no
kindfield. -
Verified before use: a mapping whose local side does not exist on the machine this tool runs on is skipped (with a warning). A mapping meant for a different machine — or a container-internal path — can never mis-route a move.
-
Client changes win: mappings are re-read on the
refreshinterval (default 60s); edit them in the *arr app and this tool follows. If an instance is temporarily unreachable, the last good import keeps serving (and is retried every cycle). -
The optional
hostfilter restricts the import to mappings whose download-client host matches — useful when one *arr instance manages several download clients. -
Import failures are never fatal: the polling cycle continues with whatever mappings are known.
|
Note
|
Explicit configuration and discovery compose cleanly: your |
This tool is designed to complement the arr suite’s *Post-Import Category feature. Everything below applies equally to Sonarr (TV), Radarr (movies), and Lidarr (music) — all three are built on the same Servarr download-client framework and offer the same setting.
In the arr qBittorrent download client settings there is a *Post-Import Category: after a release is downloaded and imported into your library, the torrent is re-categorized so it stops showing up in the arr activity queue. Per the official *arr documentation, *using a post-import category disables *arr’s own completed-download-handling removal — the torrent will seed in that category forever, and nothing cleans it up.
That is exactly the gap this tool fills:
-
In Sonarr/Radarr/Lidarr → Settings → Download Clients → qBittorrent, set Category (e.g.
tv-sonarr,radarr,lidarr) and Post-Import Category (e.g.imported-tv,imported-movies,imported-music). -
In this tool’s
config.yaml, map only the post-import categories, and list the active categories inignore_categoriesas an explicit safety net:categories: imported-tv: 'G:\media\archive\tv' imported-movies: 'G:\media\archive\movies' imported-music: 'G:\media\archive\music' ignore_categories: ["tv-sonarr", "radarr", "lidarr"]
-
The lifecycle then becomes: *arr grabs the release → qBittorrent downloads it (active category, untouched by this tool) → *arr imports it (hardlink/copy into the library) and re-categorizes the torrent to the post-import category → this tool moves the leftover payload to your archive directory. With the default
after_move: keep_seedingthe torrent keeps seeding from the archive; setafter_move: removeif you want it removed from qBittorrent instead.
|
Warning
|
Never map an active download category ( |
If you rely on hardlinks for imports (the arr-recommended setup), note that this tool *moves the leftover payload. On the same filesystem the hardlinked library copy is unaffected (moving one link never touches the other); across filesystems the payload is copied and the original deleted, which likewise leaves the library copy intact.
|
Note
|
The default Send to Seeding behavior never interferes with *arr flows: it skips every category that is mapped in |
This tool interacts with exactly one thing: the qBittorrent WebUI API. That makes it a well-behaved neighbor to the rest of a typical media stack — as long as categories are partitioned correctly. This section spells out how each common companion fits in.
Identical to Sonarr/Radarr — see *arr Suite Integration. Use e.g. category lidarr (ignored) and post-import category imported-music (mapped or left to Send-to-Seeding).
unpackerr watches arr downloads for compressed releases and extracts them *in place before the arr application imports the extracted files. Both the archives and the extraction happen inside the *active category’s download directory — therefore:
-
Keep every category unpackerr watches in
ignore_categories(they are the same active *arr categories that must be ignored anyway). -
Never map an unpackerr-watched category in
categories: moving the payload mid-extraction would break both the extraction and the import. -
Once the *arr app imports and re-categorizes the torrent to a post-import category, the archives have served their purpose and this tool may safely move or clean up the leftovers.
Request managers sit upstream of Sonarr/Radarr: they submit requests to the arr applications and never talk to qBittorrent or the filesystem. There is nothing to configure and nothing that can conflict — availability detection happens through the *arr apps and your media server (Plex/Jellyfin/Emby), which read the *library, not the torrent payload directory.
Same as above: Requestrr is a Discord/chat frontend for Sonarr/Radarr/Overseerr. No interaction with qBittorrent, no conflict with this tool.
Soulseek clients are not BitTorrent clients and never appear in qBittorrent, so this tool does not see or touch their downloads. To organize them alongside your torrents, point their download directories at the same library/archive tree this tool moves torrents into, or let Lidarr import them via its watched-folder support. If you use slskd’s own move-on-completion feature, make sure its target directory and this tool’s destination directories don’t collide on individual paths (this tool refuses to overwrite existing destinations, so a collision fails safe with an error in the log).
A Dockerfile is included (multi-stage build, ~90 MB runtime image, no OpenSSL needed). The container reads config.yaml from — and writes its log to — the /config volume; if the file doesn’t exist a default template is created there on first start.
Build the image:
$ docker build -t organizarr .
Copy, fill in your values, and uncomment only what you need to change — everything commented out shows the default:
services:
organizarr:
image: organizarr # or ghcr.io/loadst0ne/organizarr once published
build: . # remove if you use a prebuilt image
container_name: organizarr
restart: unless-stopped
volumes:
# Config + log directory (config.yaml lives here; a template is
# created on first run if missing).
- ./config:/config
# Mount your download and destination trees so the container sees
# the same data qBittorrent writes. Use the SAME container-side
# paths that qBittorrent uses, and path remapping becomes
# unnecessary; otherwise set path_prefix/root_path in config.yaml.
- /path/to/downloads:/data/torrents # <-- FILL IN host download path
- /path/to/media:/data/media # <-- FILL IN host media/archive path
# If qBittorrent runs behind a VPN container (e.g. gluetun) with a
# published WebUI port, this tool just needs network access to that
# port. From a container, "host.docker.internal" reaches the host on
# Docker Desktop; on Linux, add the extra_hosts line below.
#extra_hosts:
# - "host.docker.internal:host-gateway"The matching config.yaml in the mounted ./config directory:
servers:
- qbit_url: "http://host.docker.internal:8080" # <-- FILL IN your WebUI URL
username: "" # "" = WebUI auth bypass; otherwise FILL IN
password: ""
categories:
# category: destination directory. With the default
# after_move: keep_seeding, qBittorrent relocates the payload itself,
# so use a path the qBittorrent container can see. With stop/remove
# this container moves the files, so use the container-side paths
# mounted above. <-- FILL IN
imported-tv: "/data/media/tv"
#after_move: keep_seeding # keep_seeding | stop | remove
#ignore_categories: ["tv-sonarr", "radarr", "lidarr"]
# In Docker, prefer letting qBittorrent handle deletion (its trash
# preference) instead of the container's (nonexistent) trash:
#behaviors:
# delete:
# use_trash: false
# Path remapping is only needed when qBittorrent's view of the paths
# differs from THIS container's view (see the volumes above):
#path_prefix: "/downloads" # what qBittorrent reports
#root_path: "/data/torrents" # where this container sees the same data
# Or import the remote path mappings your *arr apps already maintain:
#arr:
# - name: sonarr
# url: "http://sonarr:8989"
# api_key: "YOUR_SONARR_API_KEY"
#rate_limit_delay: 5
#log_file: "organizarr.log"
#max_log_file_size: "10M"
#max_concurrent_moves: 2
#errored_completed_action: remove$ docker run -d --name organizarr --restart unless-stopped \
-v ./config:/config \
-v /path/to/downloads:/data/torrents \
-v /path/to/media:/data/media \
organizarr
|
Note
|
Inside a container there is no desktop trash, so the delete flow’s |
A common setup: qBittorrent runs in a Linux container (e.g. behind gluetun in Docker Desktop on Windows), while this tool runs on the host.
qBittorrent then reports container paths such as /data/Anime/Some Show, which live on the host at e.g. G:\data\torrents\Anime\Some Show.
Use path_prefix (the container-side prefix) and root_path (the host-side equivalent) to bridge the two views:
servers:
- qbit_url: "http://localhost:8080"
username: "" # WebUI auth bypass enabled -> skip login
password: ""
after_move: remove # this tool moves the files host-side, then
# removes the torrent. See the note below for
# the keep_seeding alternative.
categories:
anime: 'G:\media\Anime' # host path where completed "anime" torrents go
path_prefix: "/data" # what the container calls the download root
root_path: 'G:\data\torrents' # what the host calls the same directory
rate_limit_delay: 5
log_file: "organizarr.log"
max_log_file_size: "10M"With this config, a completed torrent at /data/Anime/Some Show (container view) is located at G:\data\torrents\Anime\Some Show (host view), moved to G:\media\Anime\Some Show, and then removed from qBittorrent.
Tips:
-
path_prefixmust match the container path exactly, including letter case (/data, not/Data) — container paths are case-sensitive. -
Use single-quoted YAML strings for Windows paths (
'G:\data\torrents') so backslashes are not treated as escapes. -
With
after_move: stoporremove, destination directories (categories) are host paths, since the move is performed by this tool on the host. -
If your Sonarr/Radarr already have a remote path mapping for this setup (they usually do), you can import it instead of maintaining
path_prefix/root_pathby hand — see Configuration Discovery. Likewise,anime: automakes the destination follow whatever save path theanimecategory has inside qBittorrent.
|
Note
|
To keep torrents seeding after the move in this mixed setup (the default
|