Torrent Post-Processing: Running Scripts on Completion
In a torrent workflow, post-processing refers to the automated series of actions performed on files immediately after a download finishes. This guide explains the core concepts of torrent post-processing, typical automation use cases, and the exact steps required to configure popular torrent clients to trigger external scripts upon download completion.
What Is Post-Processing in a Torrent Workflow?
Post-processing bridges the gap between completing a raw download and preparing the file for its final purpose. Once a torrent client finishes downloading and verifying data chunks, it enters the post-processing phase.
Common post-processing tasks include: * Extracting
archives: Automatically uncompressing .rar or
.zip archives included in the download payload. *
File organization and renaming: Renaming files
according to specific naming conventions and moving them to target
directories. * Media server integration: Triggering
library scans in media managers like Plex, Jellyfin, or Emby. *
Format conversion: Transcoding video or audio files
into preferred codecs or containers. * Notifications:
Sending alerts to platforms like Discord, Telegram, or email with
download statistics. * Seed management: Moving data via
hardlinks or symlinks so the client can continue seeding without
interfering with the target destination.
How Torrent Clients Trigger Scripts
Torrent clients monitor the download progress. When a torrent reaches 100% (or meets specific criteria like category completion), the client executes a system command pointing to a script—such as a Bash script, Python script, PowerShell script, or batch file.
During execution, the client passes metadata to the script using command-line arguments or environment variables. This metadata typically includes: * Torrent name * Save path / target directory * Torrent hash / ID * Category or tag * Number of files
Configuring Script Execution in Popular Clients
1. qBittorrent
qBittorrent provides native support for passing command-line parameters directly to an external executable.
- Open Options (
Tools>OptionsorPreferences). - Navigate to the Downloads tab.
- Scroll down to the Run external program section.
- Check Run external program on torrent finished.
- Input the path to your interpreter/script followed by parameters.
Example command for Linux/macOS:
/usr/bin/python3 /scripts/post_process.py "%N" "%F" "%D" "%I"Example command for Windows:
powershell.exe -ExecutionPolicy Bypass -File "C:\Scripts\post_process.ps1" -TorrentName "%N" -ContentPath "%F"Key qBittorrent Variables: * %N: Torrent name *
%F: Content path (same as root path for multi-file
torrents) * %D: Save path * %I: Info hash *
%L: Category
2. Transmission
Transmission triggers scripts using its configuration file or daemon settings, passing metadata via predefined environment variables.
Stop the Transmission service.
Open
settings.json.Configure the following keys:
"script-torrent-done-enabled": true, "script-torrent-done-filename": "/path/to/script.sh"Save the file and restart Transmission.
Key Transmission Environment Variables: *
TR_TORRENT_NAME: Name of the torrent *
TR_TORRENT_DIR: Path to the download directory *
TR_TORRENT_HASH: Torrent info hash *
TR_TIME_LOCALTIME: Time the download completed
3. Deluge
Deluge uses the official Execute plugin to handle post-processing triggers.
- Open Preferences and select Plugins.
- Enable the Execute plugin.
- Select Execute from the left-hand sidebar menu.
- Click Add, select the event Torrent Complete, and provide the absolute path to your script.
- Apply the changes.
Deluge automatically passes arguments to the script:
torrent_id (Arg 1), torrent_name (Arg 2), and
save_path (Arg 3).
Writing a Basic Post-Processing Script
Below is an example of a Python post-processing script designed to handle inputs, log the completion, and extract compressed archives if present:
#!/usr/bin/env python3
import sys
import os
import zipfile
import logging
# Configure logging
logging.basicConfig(filename='/tmp/torrent_post_process.log', level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s')
def main():
if len(sys.argv) < 3:
logging.error("Insufficient arguments passed.")
sys.exit(1)
torrent_name = sys.argv[1]
content_path = sys.argv[2]
logging.info(f"Processing finished download: {torrent_name}")
logging.info(f"Target path: {content_path}")
# Check if target is a directory or single file
if os.path.isdir(content_path):
for root, _, files in os.walk(content_path):
for file in files:
if file.endswith('.zip'):
zip_path = os.path.join(root, file)
logging.info(f"Extracting: {zip_path}")
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
zip_ref.extractall(root)
logging.info(f"Post-processing complete for {torrent_name}")
if __name__ == "__main__":
main()Best Practices
- Use Hardlinks: If you need to seed while sorting files into a media library, create hardlinks instead of copying or moving files. Hardlinks duplicate the file reference without using additional storage space.
- Make Scripts Executable: On Linux and macOS
systems, ensure the client process has permission to execute the script
by running
chmod +x /path/to/script.sh. - Implement Logging: Because torrent client scripts execute in non-interactive background shells, write logs to a dedicated file to simplify debugging.
- Account for File Locks: Ensure that unarchiving or moving utilities do not execute until the torrent client has fully released write locks on the finished payload.