cleanuperr is a tool for automating the cleanup of unwanted or blocked files in Sonarr, Radarr, and supported download clients like qBittorrent. It removes incomplete or blocked downloads, updates queues, and enforces blacklists or whitelists to manage file selection. After removing blocked content, cleanuperr can also trigger a search to replace the deleted shows/movies.
cleanuperr was created primarily to address malicious files, such as *.lnk
or *.zipx
, that were getting stuck in Sonarr/Radarr and required manual intervention. Some of the reddit posts that made cleanuperr come to life can be found here, here, here and here.
The tool supports both qBittorrent's built-in exclusion features and its own blocklist-based system. Binaries for all platforms are provided, along with Docker images for easy deployment.
Refer to the Environment variables section for detailed configuration instructions and the Setup section for an in-depth explanation of the cleanup process.
- Marks unwanted files as skip/unwanted in the download client.
- Automatically strikes stalled or stuck downloads.
- Removes and blocks downloads that reached the maximum number of strikes or are marked as unwanted by the download client or by cleanuperr and triggers a search for removed downloads.
Only the latest versions of the following apps are supported, or earlier versions that have the same API as the latest version:
- qBittorrent
- Deluge
- Transmission
- Sonarr
- Radarr
- Lidarr
This tool is actively developed and still a work in progress, so using the latest
Docker tag may result in breaking changes. Join the Discord server if you want to reach out to me quickly (or just stay updated on new releases) so we can squash those pesky bugs together:
- Content blocker will:
- Run every 5 minutes (or configured cron).
- Process all items in the *arr queue.
- Find the corresponding item from the download client for each queue item.
- Mark the files that were found in the queue as unwanted/skipped if:
- They are listed in the blacklist, or
- They are not included in the whitelist.
- If all files of a download are unwanted:
- It will be removed from the *arr's queue and blocked.
- It will be deleted from the download client.
- A new search will be triggered for the *arr item.
- Queue cleaner will:
- Run every 5 minutes (or configured cron, or right after
content blocker
). - Process all items in the *arr queue.
- Check each queue item if it is stalled (download speed is 0), stuck in matadata downloading or failed to be imported.
- If it is, the item receives a strike and will continue to accumulate strikes every time it meets any of these conditions.
- Check each queue item if it meets one of the following condition in the download client:
- Marked as completed, but 0 bytes have been downloaded (due to files being blocked by qBittorrent or the content blocker).
- All associated files of are marked as unwanted/skipped.
- If the item DOES NOT match the above criteria, it will be skipped.
- If the item DOES match the criteria or has received the maximum number of strikes:
- It will be removed from the *arr's queue and blocked.
- It will be deleted from the download client.
- A new search will be triggered for the *arr item.
- Run every 5 minutes (or configured cron, or right after
- Go to qBittorrent -> Options -> Downloads -> make sure
Excluded file names
is checked -> Paste an exclusion list that you have copied.- blacklist, or
- permissive blacklist, or
- create your own
- qBittorrent will block files from being downloaded. In the case of malicious content, nothing is downloaded and the torrent is marked as complete.
- Start cleanuperr with
QUEUECLEANER__ENABLED
set totrue
. - The queue cleaner will perform a cleanup process as described in the How it works section.
- Set both
QUEUECLEANER__ENABLED
andCONTENTBLOCKER__ENABLED
totrue
in your environment variables. - Configure and enable either a blacklist or a whitelist as described in the Arr variables section.
- Once configured, cleanuperr will perform the following tasks:
- Execute the content blocker job, as explained in the How it works section.
- Execute the queue cleaner job, as explained in the How it works section.
- Set
QUEUECLEANER__ENABLED
totrue
. - Set
QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES
to a desired value. - Optionally set failed import message patterns to ignore using
QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__<NUMBER>
. - Set
DOWNLOAD_CLIENT
tonone
.
No other action involving a download client would work (e.g. content blocking, removing stalled downloads, excluding private trackers).
version: "3.3"
services:
cleanuperr:
volumes:
- ./cleanuperr/logs:/var/logs
environment:
- LOGGING__LOGLEVEL=Information
- LOGGING__FILE__ENABLED=false
- LOGGING__FILE__PATH=/var/logs/
- LOGGING__ENHANCED=true
- TRIGGERS__QUEUECLEANER=0 0/5 * * * ?
- TRIGGERS__CONTENTBLOCKER=0 0/5 * * * ?
- QUEUECLEANER__ENABLED=true
- QUEUECLEANER__RUNSEQUENTIALLY=true
- QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES=5
- QUEUECLEANER__IMPORT_FAILED_IGNORE_PRIVATE=false
- QUEUECLEANER__IMPORT_FAILED_DELETE_PRIVATE=false
# - QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__0=title mismatch
# - QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__1=manual import required
- QUEUECLEANER__STALLED_MAX_STRIKES=5
- QUEUECLEANER__STALLED_IGNORE_PRIVATE=false
- QUEUECLEANER__STALLED_DELETE_PRIVATE=false
- CONTENTBLOCKER__ENABLED=true
- CONTENTBLOCKER__IGNORE_PRIVATE=false
- CONTENTBLOCKER__DELETE_PRIVATE=false
- DOWNLOAD_CLIENT=none
# OR
# - DOWNLOAD_CLIENT=qBittorrent
# - QBITTORRENT__URL=http://localhost:8080
# - QBITTORRENT__USERNAME=user
# - QBITTORRENT__PASSWORD=pass
# OR
# - DOWNLOAD_CLIENT=deluge
# - DELUGE__URL=http://localhost:8112
# - DELUGE__PASSWORD=testing
# OR
# - DOWNLOAD_CLIENT=transmission
# - TRANSMISSION__URL=http://localhost:9091
# - TRANSMISSION__USERNAME=test
# - TRANSMISSION__PASSWORD=testing
- SONARR__ENABLED=true
- SONARR__SEARCHTYPE=Episode
- SONARR__BLOCK__TYPE=blacklist
- SONARR__BLOCK__PATH=https://example.com/path/to/file.txt
- SONARR__INSTANCES__0__URL=http://localhost:8989
- SONARR__INSTANCES__0__APIKEY=secret1
- SONARR__INSTANCES__1__URL=http://localhost:8990
- SONARR__INSTANCES__1__APIKEY=secret2
- RADARR__ENABLED=true
- RADARR__BLOCK__TYPE=blacklist
- RADARR__BLOCK__PATH=https://example.com/path/to/file.txt
- RADARR__INSTANCES__0__URL=http://localhost:7878
- RADARR__INSTANCES__0__APIKEY=secret3
- RADARR__INSTANCES__1__URL=http://localhost:7879
- RADARR__INSTANCES__1__APIKEY=secret4
- LIDARR__ENABLED=true
- LIDARR__BLOCK__TYPE=blacklist
- LIDARR__BLOCK__PATH=https://example.com/path/to/file.txt
- LIDARR__INSTANCES__0__URL=http://radarr:8686
- LIDARR__INSTANCES__0__APIKEY=secret5
- LIDARR__INSTANCES__1__URL=http://radarr:8687
- LIDARR__INSTANCES__1__APIKEY=secret6
image: ghcr.io/flmorg/cleanuperr:latest
restart: unless-stopped
Click here
Variable | Required | Description | Default value |
---|---|---|---|
LOGGING__LOGLEVEL | No | Can be Verbose , Debug , Information , Warning , Error or Fatal . |
Information |
LOGGING__FILE__ENABLED | No | Enable or disable logging to file. | false |
LOGGING__FILE__PATH | No | Directory where to save the log files. | empty |
LOGGING__ENHANCED | No | Enhance logs whenever possible. A more detailed description is provided. here |
true |
TRIGGERS__QUEUECLEANER | Yes if queue cleaner is enabled | - Quartz cron trigger. - Can be a max of 6h interval. - Is ignored if QUEUECLEANER__RUNSEQUENTIALLY=true and CONTENTBLOCKER__ENABLED=true . |
0 0/5 * * * ? |
TRIGGERS__CONTENTBLOCKER | Yes if content blocker is enabled | - Quartz cron trigger. - Can be a max of 6h interval. |
0 0/5 * * * ? |
QUEUECLEANER__ENABLED | No | Enable or disable the queue cleaner. | true |
QUEUECLEANER__RUNSEQUENTIALLY | No | If set to true, the queue cleaner will run after the content blocker instead of running in parallel, streamlining the cleaning process. | true |
QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES | No | - After how many strikes should a failed import be removed. - 0 means never. |
0 |
QUEUECLEANER__IMPORT_FAILED_IGNORE_PRIVATE | No | Whether to ignore failed imports from private trackers. | false |
QUEUECLEANER__IMPORT_FAILED_DELETE_PRIVATE | No | - Whether to delete failed imports of private downloads from the download client. - Does not have any effect if QUEUECLEANER__IMPORT_FAILED_IGNORE_PRIVATE is true .- Set this to true if you don't care about seeding, ratio, H&R and potentially losing your tracker account. |
false |
QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__0 | No | - First pattern to look for when an import is failed. - If the specified message pattern is found, the item is skipped. |
empty |
QUEUECLEANER__STALLED_MAX_STRIKES | No | - After how many strikes should a stalled download be removed. - 0 means never. |
0 |
QUEUECLEANER__STALLED_IGNORE_PRIVATE | No | Whether to ignore stalled downloads from private trackers. | false |
QUEUECLEANER__STALLED_DELETE_PRIVATE | No | - Whether to delete stalled private downloads from the download client. - Does not have any effect if QUEUECLEANER__STALLED_IGNORE_PRIVATE is true .- Set this to true if you don't care about seeding, ratio, H&R and potentially losing your tracker account. |
false |
CONTENTBLOCKER__ENABLED | No | Enable or disable the content blocker. | false |
CONTENTBLOCKER__IGNORE_PRIVATE | No | Whether to ignore downloads from private trackers. | false |
CONTENTBLOCKER__DELETE_PRIVATE | No | - Whether to delete private downloads that have all files blocked from the download client. - Does not have any effect if CONTENTBLOCKER__IGNORE_PRIVATE is true .- Set this to true if you don't care about seeding, ratio, H&R and potentially losing your tracker account. |
false |
Click here
Variable | Required | Description | Default value |
---|---|---|---|
DOWNLOAD_CLIENT | No | Download client that is used by *arrs Can be qbittorrent , deluge , transmission or none |
none |
QBITTORRENT__URL | No | qBittorrent instance url | http://localhost:8112 |
QBITTORRENT__USERNAME | No | qBittorrent user | empty |
QBITTORRENT__PASSWORD | No | qBittorrent password | empty |
DELUGE__URL | No | Deluge instance url | http://localhost:8080 |
DELUGE__PASSWORD | No | Deluge password | empty |
TRANSMISSION__URL | No | Transmission instance url | http://localhost:9091 |
TRANSMISSION__USERNAME | No | Transmission user | empty |
TRANSMISSION__PASSWORD | No | Transmission password | empty |
Click here
Variable | Required | Description | Default value |
---|---|---|---|
SONARR__ENABLED | No | Enable or disable Sonarr cleanup | false |
SONARR__BLOCK__TYPE | No | Block type Can be blacklist or whitelist |
blacklist |
SONARR__BLOCK__PATH | No | Path to the blocklist (local file or url) Needs to be json compatible |
empty |
SONARR__SEARCHTYPE | No | What to search for after removing a queue item Can be Episode , Season or Series |
Episode |
SONARR__INSTANCES__0__URL | No | First Sonarr instance url | http://localhost:8989 |
SONARR__INSTANCES__0__APIKEY | No | First Sonarr instance API key | empty |
RADARR__ENABLED | No | Enable or disable Radarr cleanup | false |
RADARR__BLOCK__TYPE | No | Block type Can be blacklist or whitelist |
blacklist |
RADARR__BLOCK__PATH | No | Path to the blocklist (local file or url) Needs to be json compatible |
empty |
RADARR__INSTANCES__0__URL | No | First Radarr instance url | http://localhost:7878 |
RADARR__INSTANCES__0__APIKEY | No | First Radarr instance API key | empty |
LIDARR__ENABLED | No | Enable or disable LIDARR cleanup | false |
LIDARR__BLOCK__TYPE | No | Block type Can be blacklist or whitelist |
blacklist |
LIDARR__BLOCK__PATH | No | Path to the blocklist (local file or url) Needs to be json compatible |
empty |
LIDARR__INSTANCES__0__URL | No | First LIDARR instance url | http://localhost:8686 |
LIDARR__INSTANCES__0__APIKEY | No | First LIDARR instance API key | empty |
Click here
Variable | Required | Description | Default value |
---|---|---|---|
HTTP_MAX_RETRIES | No | The number of times to retry a failed HTTP call (to *arrs, download clients etc.) | 0 |
HTTP_TIMEOUT | No | The number of seconds to wait before failing an HTTP call (to *arrs, download clients etc.) | 100 |
- The queue cleaner and content blocker can be enabled or disabled separately, if you want to run only one of them.
- Only one download client can be enabled at a time. If you have more than one download client, you should deploy multiple instances of cleanuperr.
- The blocklists (blacklist/whitelist) should have a single pattern on each line and supports the following:
*example // file name ends with "example"
example* // file name starts with "example"
*example* // file name has "example" in the name
example // file name is exactly the word "example"
regex:<ANY_REGEX> // regex that needs to be marked at the start of the line with "regex:"
- Multiple Sonarr/Radarr/Lidarr instances can be specified using this format, where
<NUMBER>
starts from0
:
SONARR__INSTANCES__<NUMBER>__URL
SONARR__INSTANCES__<NUMBER>__APIKEY
- Multiple failed import patterns can be specified using this format, where
<NUMBER>
starts from 0:
QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__<NUMBER>
- This blacklist and this whitelist can be used for Sonarr and Radarr, but they are not suitable for other *arrs.
- Download the binaries from releases.
- Extract them from the zip file.
- Edit appsettings.json. The paths from this json file correspond with the docker env vars, as described above.
Check out this stackoverflow answer on how to do it: https://stackoverflow.com/a/15719678
Special thanks for inspiration go to:
- ThijmenGThN/swaparr
- ManiMatter/decluttarr
- PaeyMoopy/sonarr-radarr-queue-cleaner
- Sonarr & Radarr for the logo
If I made your life just a tiny bit easier, consider buying me a coffee!