Skip to content

post processing

Alexander Herling edited this page Oct 11, 2026 · 16 revisions

Post-processing

Post-processing is everything that happens after the last byte arrives: verifying the payload, repairing it, unpacking it, cleaning up, running your script and uploading the result. It is modelled on SABnzbd's, and where it deliberately departs, this page says so.

Global settings are under Settings → Post-processing, on the tabs Unpacking, Repair & cleanup, Package names, Malware scan (ClamAV) and Scripts & upload; almost every one of them can be overridden per category and per package.

Levels

Settings → Post-processing & delivery on its Unpacking tab, beside Repair & cleanup, Package names, Malware scan (ClamAV) and Scripts & upload: default level, recursive unpacking, unpacking into subfolders, dissolving a folder named like the package, unpacking while downloading, pausing downloads during post-processing and the password list

Four levels, each including the previous one:

Level Does
None Nothing
+Repair PAR2 verification and repair
+Unpack …and extraction
+Delete …and deletion of the source archives

The level is resolved by inheritance: package → category → global default. The global default is +Unpack.

The pipeline, in order

  1. PAR2 repair — see Usenet and NZB; recovery volumes are fetched only when a repair needs them, unless Download all PAR2 volumes is on, and a download that cannot be repaired is stopped before it gets here, unless Abort hopeless Usenet downloads is off
  2. SFV verification
  3. RAR integrity test
  4. Extraction
  5. Archive deletion
  6. PAR2 deletion
  7. Cleanup
  8. Malware scan — with ClamAV, when it is switched on (see below)
  9. Plugin steps
  10. User script
  11. Upload — to an rclone remote, a plugin destination or an object storage bucket
  12. Sorting — series and films are moved and renamed by the category's templates (see below)

Every step keeps its own history, and an interrupted pipeline resumes after a restart rather than starting over: a package whose upload or plugin step was cut off by a service stop stays in post-processing, and a script or upload that had already finished does not run again. What went wrong is shown in the language of the interface, with the tool's own output beside it as detail.

Verification

PAR2

For Usenet packages. If the main index cannot be parsed, verification uses one of the .vol volumes of the same set instead before the package is treated as unrepairable (SABnzbd's promote_par2). PAR2 files are detected by content, not only by extension.

A PAR2 set repairs only inside its own package. A set that names an absolute path or a ../ outside the package folder is treated as unreadable and writes nothing — as are such ZIP members and SFV entries.

SFV

Any .sfv index found in the package is CRC32-verified before extraction, for every package kind, not only Usenet. Enabled by default, switchable globally and inheritable or overridable per category.

A differing checksum or a missing listed file fails the step, skips extraction and cleanup, and fails the package. The step history names the affected files.

RAR integrity test

unrar t or 7z t, run only when neither a PAR2 set nor an .sfv index answered whether the payload arrived intact. (SABnzbd's try_rar_check.)

A missing tool, or an archive whose password is not yet known, is recorded as skipped rather than as damage.

What a failed verification blocks

"Post-process only verified packages" (SABnzbd's safe_postproc) is on by default and overridable per category. With it on, a failed PAR2, SFV or RAR check stops unpacking, cleanup and plugin steps; switched off, they run anyway.

"Post-process anyway" is a per-package action that runs the pipeline once despite a failed verification, without changing the setting — for example for a damaged recovery set beside intact archives.

The failed step stays on the record either way, and a user script still receives status 3.

Extraction

Supported: ZIP (including ZipCrypto and AES), 7z and RAR, plus multi-part RAR, 7z and split-ZIP sets.

Extraction runs through a staging area; completed contents are then moved into the package directory. Live progress is reported for ZIP, 7z, unrar and external 7-Zip.

Passwords

Attempted in this order:

  1. A password announced with an indexer hit — from the SABnzbd {{secret}} marker in the title, or from an indexer that writes a real password where Newznab specifies a 0/1/2 flag.
  2. The package password, set in the LinkGrabber or the import dialog.
  3. The configurable password list (data/passwords.txt by default). It is read only as a regular file of at most 4 MiB, and choosing another file needs the administration area (api:admin).
  4. {{password}} in the NZB file name.

The {{secret}} marker is removed from the package name, so the password does not show in the LinkGrabber and the queue. A package password with leading or trailing whitespace is tried as typed and then trimmed; entries in the password list are always trimmed.

When unpacking fails

The reason is one click away. A package whose unpacking or post-processing failed carries an Extraction failed or Post-processing failed badge on its header in the Downloads view; the badge is a button that opens the package's post-processing steps, and a failed step shows its reason in full.

A failure says what failed. A checksum error, a truncated volume and a rejected command line are not reported as "wrong password". Where the unpacker's exit code cannot decide, the message says "wrong password or damaged data", and damaged data stops the retry through the rest of the password list. A destination that refuses the file has its own reason; no password changes it.

If an archive opens by hand but not in the service:

  • On Windows, 7-Zip cannot receive a password containing a ". That candidate fails with The password contains a quotation mark (") and the next one is tried. unrar takes such a password as typed.
  • The configured unrar executable must really be unrar: 7-Zip reads unrar's password switch differently and would report a correct password as wrong. The service checks this before it runs.

Every run of unrar or 7z is written to the log with the tool, its arguments and its exit code, so a failure can be read back exactly as it was called. The password appears as -p***, never in clear.

An unrar older than 6.12 or a 7-Zip older than 25.00 is not started, because both let a link inside the archive write outside the destination. The set fails with extract.tool_outdated, naming the tool, its version and the minimum. Nothing lifts this floor; replace the tool — see External tools.

Every unpacked file must have exactly one name. An archive that unpacks a hard link to a file outside the extraction folder fails before anything is moved into the package folder (Linux and macOS; Windows does not report the number of names a file has).

An archive bomb is stopped while it unpacks, not after the disk is full.

Safety limits

Limit Default
Maximum archive entries 20,000
Maximum extracted size 100 GiB

Recursive extraction

Archives found inside extracted archives can be unpacked too, capped at three additional passes. Disabled by default, configurable globally and per category.

Successfully extracted inner archives are always removed. Recursive extraction is disabled for torrent packages, to protect payloads that may still be seeding.

A folder per archive

By default everything an archive holds is unpacked straight into the package folder. With Unpack into subfolders on, under Settings → Post-processing → Unpacking, every archive set is unpacked into a folder of its own inside the package folder instead, named after the archive without its volume and extension suffix:

Archive Folder
Film.part1.rar, Film.part2.rar Film/
Extras.zip Extras/
x.7z.001, x.7z.002 x/
  • Off by default. A category overrides it with Subfolder per archive — Inherit, On or Off.
  • The archives stay where they are, in the package folder; only what they hold goes into the new folder. Deleting them afterwards is still the +Delete level's decision.
  • An archive found inside one is unpacked, with recursive extraction on, inside the folder its outer archive went into — never beside it in the package folder.
  • Two archives with one name — Film.zip beside Film.rar, or names that differ only in case — get a folder each: the first keeps Film/, the next takes Film (1)/, the same one on every run.
  • A file in the way — a file or a symbolic link already carrying the folder's name — moves the name on to Film (1), Film (2) and so on. A folder of that name is used as it is, so a second run, after a crash or a manual extraction, merges into the folder the first run chose.
  • The name follows the same rules as a package folder: it cannot leave the package folder, and it is shortened where needed to leave room for what the archive holds.

A user script still receives the package folder as its final directory. Every upload route and every plugin step sees the files inside these folders — see Upload.

A folder named like the package

Many releases carry their own folder: the outer RAR of a scene release holds Release/, and an NZB or torrent often brings one along, so the files end up in Release/Release/…. With Dissolve a folder named like the package on, under Settings → Post-processing → Unpacking, rDownloader moves the content of that inner folder up into the package folder and removes the empty folder.

  • Off by default. A category overrides it with Dissolve a folder named like the package — Inherit, On or Off.
  • When: after unpacking, deleting the archives and the cleanup, before the malware scan, the plugin steps, your script, the upload and the sorting — and only when the package got that far, so a failed package keeps its layout for the next try. A package without archives qualifies too.
  • Only one folder, only one level. The package folder must hold nothing but that one folder, and its name must match the package folder's name after the same clean-up a package folder's name gets, ignoring upper and lower case. A second file beside it, another name or a link leaves everything as it is; Release/Release/Release/ loses one level, not two.
  • With a folder per archive the same rule applies inside each archive's folder (Film/ holding only Film/). The archive's own folder stays, even when the archive is named like the package.
  • A torrent that is still seeding keeps its files where the torrent client reads them.
  • Nothing is overwritten. If a name is already taken one level up, everything stays where it is and the package's steps show a warning. If the service stops halfway, the next start finishes the move.

Unpacking while downloading

A large Usenet release is normally unpacked in a second long pass after its last byte. With Unpack while downloading on, under Settings → Post-processing → Unpacking, a multi-part RAR archive (Film.part1.rar, Film.part2.rar … or Film.rar, Film.r00 …) is unpacked part by part while the rest is still downloading, so the package is done shortly after the download.

  • Off by default. A category overrides it with Unpack while downloading — Inherit, On or Off. It applies to Usenet packages only and needs unrar; with 7-Zip as the RAR tool the archive is unpacked after the download.
  • It starts once the first part is complete and stops before every further part until that part has arrived complete. It needs room for the unpacked files beside the running download; if the disk is too full it does not start.
  • Nothing lands in the package folder early. What is unpacked waits in a hidden staging folder. Once the download is complete, the package is verified as always — PAR2, SFV, the RAR test — and only if nothing had to be repaired are the files moved into place. The unpack step then reads Unpacked while downloading.
  • When something goes wrong, the usual way takes over. A part with missing articles, a part that needs repair, a pause, a restart or a crash drops the attempt and its staging folder; the archive is unpacked after the download from the (repaired) parts, exactly as without the option. A password is only tried if the package has its own; otherwise the usual password list is tried after the download.
  • A folder per archive, deleting the archives at +Delete and recursive extraction work as without the option.

Deleting the PAR2 recovery set

Optional, off by default, switchable globally and per category. It runs after unpacking, so a failed extraction still has its recovery data. Only the set sharing the archive's stem is deleted; a second release in the same folder keeps its own.

Cleanup

A configurable list of file extensions to remove, plus optional removal of small sample files (threshold 300 MiB by default). A folder the cleanup leaves empty, such as a Sample folder, is removed with it; a folder that still holds anything, and the package folder itself, stay. Both settings are inheritable per category. The cleanup looks four folder levels deep into what the archives held, with a folder per archive as without one.

User scripts

Scripts live in the scripts directory — scripts/ next to the database by default, configurable in Settings. Only scripts from this directory can be selected.

An AI assistant connected over MCP cannot choose a script for a package, a category or an automation, nor the completion or reconnect script, unless you switch AI assistants (MCP) may set scripts on in Settings → Post-processing → Scripts & upload. It is off by default, and no assistant can switch it.

They are executed without a shell:

  • Unix — executable files, .sh, .py
  • Windows — .bat, .cmd, .ps1, .py, .exe

For a .bat or .cmd script every argument is escaped for cmd.exe; if an argument — a package name, say — cannot be escaped safely, the step fails with script.batch_arguments_refused and the script does not start.

Arguments (SABnzbd-compatible, positional)

# Value
1 Final directory of the package
2 Original package name
3 Clean package name
4 (empty)
5 Category
6 (empty)
7 Status — 0 ok, 1 download failed, 2 unpack failed, 3 verification failed

Environment variables

rDownloader SABnzbd alias Content
RD_FINAL_DIR SAB_COMPLETE_DIR Final directory of the package
RD_PACKAGE_NAME SAB_FILENAME Package name
RD_CLEAN_NAME SAB_FINAL_NAME Clean package name
RD_CATEGORY SAB_CAT Category
RD_STATUS SAB_PP_STATUS Status code, as above
RD_PACKAGE_ID SAB_NZO_ID Package id
RD_KIND — Package kind (HTTP, Usenet, …)
RD_SCRIPT_DIR SAB_SCRIPT_DIR Scripts directory

What a script inherits

A script does not inherit the service's environment. It starts from an empty one plus:

  • PATH, HOME, TMPDIR, TZ, LANG and every LC_* variable;
  • on Windows also USERPROFILE, SystemRoot, windir, SystemDrive, ComSpec, PATHEXT, TEMP, TMP, APPDATA and LOCALAPPDATA;
  • the RD_* and SAB_* variables in the table above, set by rDownloader for this run.

Nothing else passes — not a credential the service was started with, not a variable a container runtime injected. The same applies to every program post-processing starts: the archive tools, ffmpeg and rclone, which additionally keeps its own RCLONE_* variables, XDG_CONFIG_HOME, XDG_CACHE_HOME and the proxy variables (HTTP_PROXY, HTTPS_PROXY, NO_PROXY, ALL_PROXY).

A script that needs anything else — PYTHONPATH, a virtual environment, an API key for a notification — sets it itself: read it from a file in the scripts directory, or start the real program through a small wrapper script that exports what it needs.

Under the systemd user unit of the deb and rpm packages a script also inherits the unit's restrictions: it cannot gain privileges, so sudo and setuid programs do not work in it (see Security and privacy).

Timeout, output and exit status

  • The timeout is configurable; the default is 3,600 seconds. A script that exceeds it is terminated.
  • stdout and stderr are captured and stored in the package's step history.
  • A non-zero exit status marks the script step as failed, but the package still completes — unless an earlier repair or unpack step already failed.

The same sandbox is reused by the reconnect script and the queue-completion script.

Upload

An optional final step through rclone, using either copy or move, configured globally or per category.

Uploading through a storage plugin is the other route: the bundled webdav-storage plugin uploads a finished package to a WebDAV destination, verifying each file before the local copy is deleted. See Bundled plugins.

An object storage profile is the third: object-storage:<profile-id>/<bucket>/<prefix> sends the package to an S3-compatible bucket, an Azure container or a Google Cloud Storage bucket in parts that continue after a restart. Use an object storage profile next to the upload target fills it in. See Object storage.

Every route uploads the whole package, folders included, under its path relative to the package: Film/film.mkv arrives as <prefix>/<package>/Film/film.mkv. Symbolic links are not followed. Under Move, each file is deleted only once the destination has confirmed it, and a folder once it is empty; the package folder itself stays.

Every route keeps the upload limit. Storage plugins and object storage follow a bandwidth profile switch while they upload; rclone keeps the rate in force when it starts for the whole run.

A failed upload fails the package. The upload's progress names its destination as the current item. An rclone upload that moves no byte for 30 minutes is stopped and fails; rclone also stops together with the service.

Malware scan

rDownloader can have every finished package checked by ClamAV before it counts as finished and before a plugin step, your script or the upload sees it. Switch on Scan packages for malware (ClamAV) under Settings → Post-processing → Malware scan (ClamAV); a category can switch it on or off for itself.

ClamAV itself is not part of rDownloader. It talks to a running clamd, the ClamAV daemon:

  • clamd address — host:port over the network, e.g. clamav:3310 for the container beside rDownloader, or unix:/run/clamav/clamd.ctl for the local socket of a clamd on the same machine (not on Windows). Empty means 127.0.0.1:3310. Changing the address takes an administrator: every file of every package goes there.
  • Test clamd asks it for its version and shows the engine and the signature database's date. Nothing is scanned.
  • Largest scanned file — 25 MiB by default, the same as clamd's own StreamMaxLength. A larger file is not scanned, and the scan step says how many were left out. To scan larger files, raise both: StreamMaxLength in clamd.conf and this setting.
  • Timeout per exchange — how long the connection, one block of a file or clamd's verdict may take, 120 seconds by default.

What happens:

  • The scan sees every file in the package folder after unpacking and cleanup, including those in a folder per archive; clamd also looks inside archives that are left. Only the files' bytes are sent, only to that address — no names, no paths, nothing to anyone else.
  • Something found: the scan step names the signature and the file, the package fails, and the plugin steps, the script and the upload are marked as skipped and do not run. The audit log records Malware detected, and the package-failed notification is titled Malware found. The files stay where they are — nothing is deleted or moved; you decide what happens to them.
  • clamd not reachable (not running, wrong address, no answer in time): the scan step is marked as skipped with the reason, shown as a warning, and the package carries on. A scan that did not run is never shown as clean.
  • After a restart the scan runs again; a package is never released on a verdict that was not recorded.

For Docker, see Docker and NAS.

Plugin steps

Post-processing plugins add steps of their own. Three are bundled: SHA-256 and MD5 sidecar verification, and a file-name tidier that replaces spaces with dots. Enable them under Settings → Post-processing → Scripts & upload (Plugin steps).

A step sees every file of the package, including those inside a folder per archive, and a file it renames keeps its folder: the tidier renames Film/My Film.mkv to Film/My.Film.mkv, never the folder.

The checksum steps verify files of any size. They read a .md5 or .sha256 file's entries from the folder it is in, so one that came out of an archive checks the files beside it. A listed file post-processing removed on purpose — an unpacked volume, a PAR2 file, something the cleanup deleted — is passed over. Any other listed file the package lacks, a release split across two packages for instance, leaves the step completed with a warning on it naming what was not checked; a wrong checksum, or not one listed file there to check, fails it.

Tidy package names

The Tidy file names step renames the files inside a package folder once the package is done; it never touches the folder. Tidy package names, under Settings → Post-processing → Package names, applies the same rules to the name of a new package — and so to its folder — when the package is created, before the folder exists:

Rule Example
Remove bracket tags Big Buck Bunny [1080p] (x264) → Big Buck Bunny
Spaces → dots Big Buck Bunny → Big.Buck.Bunny
Collapse separators Big..Buck_-_Bunny → Big.Buck.Bunny
Lowercase Big.Buck.Bunny → big.buck.bunny
  • All four are off by default. The settings show what the example Big Buck Bunny [1080p] becomes with the switches as they stand, before you save.
  • A category overrides each switch — Inherit, On or Off — in its editor under Storage, categories and rules. The category that counts is the one the package lands in; category rules that look at the name see the original one.
  • Only names rDownloader makes up itself are tidied: the LinkGrabber's automatic name, an NZB (uploaded, from a hot folder or from Sonarr/Radarr through the SABnzbd adapter), a torrent or magnet, a direct link's name taken from its address, and the release name learned for a package that was named after its hoster. A name you type when adding, a name a request or the browser extension sends, and a name you rename a package to stay exactly as they are.
  • The LinkGrabber shows the tidied name of a package before you add it; hovering it shows the original.
  • A name the rules would empty — [1080p] with the tags removed — stays unchanged, and the folder name still follows the usual folder rules afterwards.

Regex rules

After the four switches, an ordered list of regex rules runs — each a pattern to find and what to replace every match with. $1, $2 … insert the pattern's groups (${name} a named one), and an empty replacement removes the match. For example _ → . turns Sintel_Directors_Cut_Update_v1.0.2_EXAMPLE into Sintel.Directors.Cut.Update.v1.0.2.EXAMPLE.

  • Add, edit, reorder and remove rules under Tidy package names; at most ten, pattern and replacement at most 200 characters each. Edit opens the regex editor the routing rules use, with a Replace with field and what each sample package name becomes.
  • The expressions are those of the routing rules: no backreferences and no lookaround, so a rule can never slow intake down. A rule that is not valid is refused when you save, naming its number.
  • A category can use own regex rules: its list then replaces the global one — an empty list means no regex rule for that category.
  • A name a rule would empty stays as it was before the rules.

Sorting series and films

Without Sonarr or Radarr, a category can file finished episodes and films itself — like SABnzbd's Sorting and NZBGet's VideoSort. Open the category under Settings → Storage & rules → Categories, switch on Sort series and films and write a template for each kind you want sorted:

Kind Recognised from Example template
Series S01E02, 1x02; several episodes as S01E01E02, S01E01-E02, S01E01-02 {show}/Season {season:00}/{show} - S{season:00}E{episode:00} - {title}
Dated episodes 2024.03.15, 2024-03-15 {show}/{year}/{show} - {date} - {title}
Films a title followed by its year, Film.2010… or Film (2010) {movie} ({year})/{movie} ({year})

A field sits in braces, and a colon formats it: {season:00} pads to two digits, :lower, :upper and :dots (spaces as dots) change the text. / separates folders; the last part is the file name without its extension, which the file keeps. The fields:

  • Series: show, season, episode, title (the episode title), year (a year the show name ends with), resolution, source
  • Dated episodes: show, date (2024-03-15), year, month, day, title, resolution, source
  • Films: movie, year, resolution, source

A multi-episode file names its first and last episode — S01E16-E17. A field without a value is left out together with the brackets around it, so {show} ({year}) reads Show when the name carried no year.

The preview below the templates shows, for example names you can change, what each name is recognised as and where it would land — before you save.

What the sort does:

  • It runs last, after the script and the upload, and only for a package that finished without errors. A failed package keeps its files where a retry finds them.
  • Files land below the category's folder and never outside it: .., absolute paths and drive letters are refused in a template and in a name, every part goes through the same name rules as a download, and a folder that is a link to somewhere else is not followed.
  • Subtitles and the NFO follow their video (Show.S01E01.en.srt → <new name>.en.srt). In a package with a single video they all follow it, and a video with an unreadable name (a8f3c2.mkv) is recognised from the package name.
  • Anything not recognised stays where it is, and so does a kind without a template. Samples are never sorted.
  • A name already taken follows the category's collision policy: rename puts the file beside it as name (1), skip and ask leave it in the package, compare drops an identical copy, overwrite replaces the old file and records it in the audit log.
  • Torrents are not sorted: their files keep seeding from where they are.

Only what the name says is used — no online database is asked. Absolute numbering (anime), season packs without episode numbers and films without a year are not recognised.

Controls

  • The post-processing queue is visible in the Downloads view, with live progress per package.
  • Manual extraction of completed packages and archives is available at any time.
  • Pause downloads during post-processing — on by default, so a repair does not compete with the queue for disk throughput.
  • Quiet hours postpone repair, unpacking and uploads without touching downloads.

Category overrides

Per category you can override: post-processing level, script, cleanup list, SFV verification, "post-process only verified packages", PAR2 deletion, recursive extraction, a folder per archive (Subfolder per archive), dissolving a folder named like the package (Dissolve a folder named like the package), unpacking while downloading (Unpack while downloading), the malware scan (Malware scan (ClamAV)), the package-name rules (Tidy package names) and upload target. The sort templates (Sort series and films) belong to the category alone; there is no global template.

Related pages

Clone this wiki locally