Table of Contents
- Lists
- The two-file model
- blacklist
- whitelist
- Pattern syntax
- qBittorrent (via Blocklist Sync)
- Cleanuparr Malware Blocker (Sonarr/Radarr queue)
- Which forms to use
- Merge script interaction
- Pattern matching
- Examples
- Keeping Norwegian subtitle files
- Supporting AV1 in .webm containers
- Adding a site-specific junk extension
- What lives in each file right now
- Consumer consequences
Lists
The two-file model
The repository contains exactly two data files. Each has a single, clear role:
| File | Role | Source of truth | Edit it? |
|---|---|---|---|
blacklist |
Extensions blocked by downloaders and file cleaners | Upstream Cleanuparr, minus whitelist |
Only for manual additions that upstream missed. Removals do not stick -- use whitelist instead |
whitelist |
Extensions that must never be blocked or deleted | Locally maintained, not synced from upstream | Yes. This is the main file you interact with |
blacklist.prev also exists in the repo but is not a data file -- it is
the three-way merge baseline used by the sync script. Never edit it.
blacklist
The blacklist is the output file consumed by Cleanuparr's Blocklist Sync feature, which pushes the patterns to qBittorrent's excluded file names. It is regenerated on every sync as:
upstream_new | custom_local_additions - whitelist
Where custom_local_additions is detected by comparing the committed
blacklist against the previous upstream snapshot. See
Sync for the full algorithm.
When to edit blacklist directly
In almost every case, you do not. The intended workflow is:
- To remove an entry (stop blocking it): add it to
whitelist. - To add an entry that upstream should also have: file an upstream issue with Cleanuparr.
- To add an entry that is specific to your setup and not worth
upstreaming: edit
blacklistdirectly. The three-way merge preserves manual additions across syncs.
When editing blacklist directly does not work
Removing a line from blacklist does not work as a removal mechanism.
The sync will re-add anything upstream has on the next run. If you want
something gone, put it in whitelist.
whitelist
The whitelist is the locally-maintained allow list. It is the single source of truth for "what must be kept." It is not synced from upstream -- any changes you make are permanent until you change them again.
Format
One glob pattern per line, sorted, no blank lines, no comments:
*.ass
*.avi
*.mkv
*.mp4
*.srt
*.ssa
*.sub
*.webm
The sort order is not enforced by the script but is the convention and makes diffs easier to read.
Semantics
Each line is treated as an exact string and subtracted from the blacklist. See Pattern matching below for the details.
Adding an entry
Edit whitelist in Gitea (or via a local clone and push), add the new
line, commit. The next sync run (or manual dispatch) will strip it from
the blacklist automatically.
You do not also need to remove it from the blacklist by hand -- the sync does that.
Removing an entry
Delete the line from whitelist and commit. The next sync will re-add
the entry to the blacklist if upstream still has it. If upstream no longer
has the entry, the entry stays gone (which is probably what you want).
Pattern syntax
The patterns in blacklist and whitelist are consumed by two tools with
different pattern capabilities. This section documents both and explains
which to use.
qBittorrent (via Blocklist Sync)
qBittorrent's "Excluded file names" field uses Qt glob wildcards
(internally QRegularExpression::fromWildcard()). The following forms are
supported:
| Pattern | Meaning | Example | Matches |
|---|---|---|---|
* |
Zero or more characters | *.srt |
Any file ending in .srt |
? |
Exactly one character | *.r?? |
.r00, .r01, ..., .r99 |
[abc] |
One character from the set | *.[rs]00 |
.r00 or .s00 |
[a-z] |
One character in the range | *.[r-z]?? |
.r00 through .z99 |
[!abc] |
One character NOT in the set | *.[!m]?? |
Any 3-char ext not starting with m |
| Literal | Exact string match | VOSTFR |
A file named exactly VOSTFR |
Not supported by qBittorrent: regex syntax (^, $, \d, \w,
(?i), +, etc.), backslash escapes (backslash is not an escape
character in Qt glob), and the regex: prefix. Any of these will be
silently ignored or matched literally, causing the pattern to fail.
To match special glob characters literally, place them in brackets:
[?] matches a literal question mark, [*] matches a literal asterisk.
Reference: Qt 6 QRegularExpression::fromWildcard
Cleanuparr Malware Blocker (Sonarr/Radarr queue)
Cleanuparr's Malware Blocker supports all the wildcard forms above plus
regex with the regex: prefix:
regex:.*\.srt$
Regex patterns only work in Cleanuparr's Malware Blocker when it reads the
whitelist (or blacklist) directly for queue inspection. They do not
work when pushed to qBittorrent via Blocklist Sync, because qBittorrent
does not understand the regex: prefix.
Which forms to use
Since the blacklist is pushed to qBittorrent via Blocklist Sync, all
entries in blacklist and whitelist should use wildcard forms only
(the first six rows in the table above). This ensures patterns work in
both consumers:
- qBittorrent (via Blocklist Sync) -- wildcards only
- Cleanuparr Malware Blocker (direct) -- wildcards and regex both work
Using wildcards everywhere is the safe default. Avoid regex: unless you
are certain the pattern will only be consumed by Cleanuparr's Malware
Blocker and never pushed to qBittorrent.
Merge script interaction
The merge script subtracts the whitelist from the blacklist as exact
strings, not by pattern semantics. The forms are not interchangeable:
*.srt and *.[s]rt describe the same files but are different strings,
so putting one in the whitelist will not strip the other from the
blacklist. Pick one form and use it consistently in both files.
Pattern matching
The whitelist-to-blacklist exclusion uses exact-string set subtraction, not glob matching. This is an intentional design choice that has two important consequences.
Exact entries are stripped
*.srt in the whitelist removes exactly the string *.srt from the
blacklist. If upstream has *.srt as a line, it gets removed. If upstream
does not have *.srt, nothing happens.
Partial matches are not affected
*.srt in the whitelist does not strip:
| Blacklist entry | Stripped? | Why |
|---|---|---|
*.srt |
yes | Identical string |
*sample.srt |
no | Different string |
*.srt.bak |
no | Different string |
file.srt |
no | Different string |
This is what makes the whitelist safe to maintain. You can whitelist
*.srt to keep bundled subtitle files without accidentally unblocking
sample files or junk variants that happen to end in .srt.
Why not glob matching
A glob-based exclusion would strip anything matching *.srt as a pattern,
which would also strip *sample.srt and *.srt.bak. That is usually not
what you want -- sample files are legitimate junk that the blacklist
should still remove.
Exact-string subtraction is also trivially simple to reason about: if the line you want stripped is in the blacklist as the exact same string, put that same string in the whitelist. Done.
Examples
Keeping Norwegian subtitle files
Scenario: torrents include .srt files as bundled Norwegian subtitles.
You want qBittorrent to download them, not strip them.
# whitelist entry
*.srt
After the next sync, *.srt is gone from blacklist. Cleanuparr's
Blocklist Sync pushes the new list to qBittorrent, which then accepts
.srt files from within torrents. *sample.srt remains blocked because
exact-string subtraction does not touch it.
Supporting AV1 in .webm containers
Scenario: you want qBittorrent to accept .webm AV1 releases, which are
currently blocked because the upstream blacklist treats *.webm as junk.
# whitelist entry
*.webm
After the next sync, *.webm is gone from blacklist. Cleanuparr's
Blocklist Sync pushes the updated list to qBittorrent and .webm
torrents download normally. *sample.webm remains blocked.
Adding a site-specific junk extension
Scenario: a private tracker keeps injecting *.nfo.gz spam files that
upstream does not block.
# Edit blacklist directly, add the line:
*.nfo.gz
Commit and push. The next sync runs, the three-way merge sees
*.nfo.gz in local - upstream_prev, classifies it as a manual addition,
and preserves it through the merge. Subsequent syncs continue to preserve
it even as upstream evolves.
If upstream ever adds *.nfo.gz itself, the entry moves from "custom"
to "upstream" on the next sync -- still present, still blocked, just
sourced differently.
What lives in each file right now
The whitelist ships with the extensions required for a normal media stack with subtitles and AV1/webm releases:
*.ass - SubStation Alpha subtitles
*.avi - Audio Video Interleave container
*.mkv - Matroska container
*.mp4 - MPEG-4 container
*.srt - SubRip subtitles
*.ssa - SubStation Alpha subtitles
*.sub - MicroDVD / VobSub subtitles
*.webm - WebM container (AV1, VP9)
The blacklist contains whatever upstream Cleanuparr ships, minus everything in the whitelist above. The actual contents change as upstream evolves -- check the file in Gitea for the current state.
Consumer consequences
Changes to either file affect what Cleanuparr's two features see:
| Change | Effect on Blocklist Sync (pushed to qBittorrent) | Effect on Malware Blocker (whitelist mode) |
|---|---|---|
Add to whitelist |
Stops being pushed to qBittorrent's excluded list | Starts allowing this extension in queue |
Remove from whitelist |
Resumes being pushed (if upstream has it) | Stops allowing this extension in queue |
Add to blacklist directly |
Starts being pushed to qBittorrent's excluded list | No effect (Malware Blocker reads whitelist) |
Remove from blacklist directly |
No effect (sync re-adds from upstream) | No effect |
See Consumers for configuration details.