cleanuperr
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.
Important note
Only the latest versions of qBittorrent, Deluge, Sonarr etc. are supported, or earlier versions that have the same API as the latest version.
This tool is actively developed and still a work in progress. 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: https://discord.gg/cJYPs9Bt
Setup
Using qBittorrent's built-in feature (works only with qBittorrent)
- Go to qBittorrent -> Options -> Downloads -> make sure
Excluded file namesis checked -> Set an exclusion list.- blacklist
- permissive blacklist
- create your own
- Start cleanuperr with
QUEUECLEANER__ENABLEDset totrue. - cleanuperr will execute a queue cleaner cron job at every 5 minutes that will:
- go through all items from Sonarr/Radarr's queue.
- each a queue item is checked:
- if it has been marked as completed and 0 bytes have been downloaded (because qBittorrent blocked the files).
- if all its files are skipped.
- if the item IS NOT as described, it is skipped.
- if the item IS as described, it is removed from Sonarr/Radarr's queue, removed from qBittorrent and a search is triggered for the show/movie.
Using cleanuperr's blocklist (works with all supported download clients)
- Start cleanuperr with both
QUEUECLEANER_ENABLEDandCONTENTBLOCKER_ENABLEDset totrue. - Be sure to set and enable a blacklist or a whitelist as described in the Environment variables section.
- cleanuperr with execute the following jobs:
- the same queue cleaner as described here
- a content blocker cron job at every 5 minutes that will mark files as unwanted/skipped if:
- they are in the blacklist.
- they are not in the whitelist.
Usage
Docker
docker run -d \
-e TRIGGERS__QUEUECLEANER="0 0/5 * * * ?" \
-e QBITTORRENT__ENABLED=true \
-e QBITTORRENT__URL="http://localhost:8080" \
-e QBITTORRENT__USERNAME="user" \
-e QBITTORRENT__PASSWORD="pass" \
-e SONARR__ENABLED=true \
-e SONARR__INSTANCES__0__URL="http://localhost:8989" \
-e SONARR__INSTANCES__0__APIKEY="secret1" \
-e SONARR__INSTANCES__1__URL="http://localhost:8990" \
-e SONARR__INSTANCES__1__APIKEY="secret2" \
-e RADARR__ENABLED=true \
-e RADARR__INSTANCES__0__URL="http://localhost:7878" \
-e RADARR__INSTANCES__0__APIKEY="secret3" \
-e RADARR__INSTANCES__1__URL="http://localhost:7879" \
-e RADARR__INSTANCES__1__APIKEY="secret4" \
...
flaminel/cleanuperr:latest
Docker compose yaml
version: "3.3"
services:
cleanuperr:
environment:
- LOGGING__LOGLEVEL__DEFAULT=Information
- TRIGGERS__QUEUECLEANER=0 0/5 * * * ?
- TRIGGERS__CONTENTBLOCKER=0 0/5 * * * ?
- QUEUECLEANER__ENABLED=true
- CONTENTBLOCKER__ENABLED=true
- CONTENTBLOCKER__BLACKLIST__ENABLED=true
- CONTENTBLOCKER__BLACKLIST__PATH=https://raw.githubusercontent.com/flmorg/cleanuperr/refs/heads/main/blacklist
# OR
# - CONTENTBLOCKER__WHITELIST__ENABLED=true
# - CONTENTBLOCKER__BLACKLIST__PATH=https://raw.githubusercontent.com/flmorg/cleanuperr/refs/heads/main/whitelist
- QBITTORRENT__ENABLED=true
- QBITTORRENT__URL=http://localhost:8080
- QBITTORRENT__USERNAME=user
- QBITTORRENT__PASSWORD=pass
# OR
# - DELUGE__ENABLED=true
# - DELUGE__URL=http://localhost:8112
# - DELUGE__PASSWORD=testing
# OR
# - TRANSMISSION__ENABLED=true
# - TRANSMISSION__URL=http://localhost:9091
# - TRANSMISSION__USERNAME=test
# - TRANSMISSION__PASSWORD=testing
- SONARR__ENABLED=true
- 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__INSTANCES__0__URL=http://localhost:7878
- RADARR__INSTANCES__0__APIKEY=secret3
- RADARR__INSTANCES__1__URL=http://localhost:7879
- RADARR__INSTANCES__1__APIKEY=secret4
image: flaminel/cleanuperr:latest
restart: unless-stopped
Environment variables
| Variable | Required | Description | Default value |
|---|---|---|---|
| LOGGING__LOGLEVEL__DEFAULT | No | Can be Debug, Information, Warning or Error |
Information |
| TRIGGERS__QUEUECLEANER | Yes if queue cleaner is enabled | Quartz cron trigger | 0 0/5 * * * ? |
| TRIGGERS__CONTENTBLOCKER | Yes if content blocker is enabled | Quartz cron trigger | 0 0/5 * * * ? |
| QUEUECLEANER__ENABLED | No | Enable or disable the queue cleaner | true |
| CONTENTBLOCKER__ENABLED | No | Enable or disable the content blocker | false |
| CONTENTBLOCKER__BLACKLIST__ENABLED | Yes if content blocker is enabled and whitelist is not enabled | Enable or disable the blacklist | false |
| CONTENTBLOCKER__BLACKLIST__PATH | Yes if blacklist is enabled | Path to the blacklist (local file or url); Needs to be json compatible | empty |
| CONTENTBLOCKER__WHITELIST__ENABLED | Yes if content blocker is enabled and blacklist is not enabled | Enable or disable the whitelist | false |
| CONTENTBLOCKER__BLACKLIST__PATH | Yes if whitelist is enabled | Path to the whitelist (local file or url); Needs to be json compatible | empty |
| QBITTORRENT__ENABLED | No | Enable or disable qBittorrent | true |
| QBITTORRENT__URL | Yes if qBittorrent is enabled | qBittorrent instance url | http://localhost:8112 |
| QBITTORRENT__USERNAME | Yes if qBittorrent is enabled | qBittorrent user | empty |
| QBITTORRENT__PASSWORD | Yes if qBittorrent is enabled | qBittorrent password | empty |
| DELUGE__ENABLED | No | Enable or disable Deluge | false |
| DELUGE__URL | Yes if Deluge is enabled | Deluge instance url | http://localhost:8080 |
| DELUGE__PASSWORD | Yes if Deluge is enabled | Deluge password | empty |
| TRANSMISSION__ENABLED | No | Enable or disable Transmission | true |
| TRANSMISSION__URL | Yes if Transmission is enabled | Transmission instance url | http://localhost:9091 |
| TRANSMISSION__USERNAME | No | Transmission user | empty |
| TRANSMISSION__PASSWORD | No | Transmission password | empty |
| SONARR__ENABLED | No | Whether Sonarr cleanup is enabled or not | true |
| SONARR__INSTANCES__0__URL | Yes | First Sonarr instance url | http://localhost:8989 |
| SONARR__INSTANCES__0__APIKEY | Yes | First Sonarr instance API key | empty |
| RADARR__ENABLED | No | Whether Radarr cleanup is enabled or not | false |
| RADARR__INSTANCES__0__URL | Yes | First Radarr instance url | http://localhost:8989 |
| RADARR__INSTANCES__0__APIKEY | Yes | First Radarr instance API key | empty |
To be noted
- The blacklist and the whitelist can not be both enabled at the same time.
- 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"
<ANY_REGEX> // regex
- Multiple Sonarr/Radarr instances can be specified using this format, where
<NUMBER>starts from 0:
SONARR__INSTANCES__<NUMBER>__URL
SONARR__INSTANCES__<NUMBER>__APIKEY
Binaries (if you're not using Docker)
- 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.
Run as a Windows Service
Check out this stackoverflow answer on how to do it: https://stackoverflow.com/a/15719678