External Programs
Launch scripts or desktop applications directly from the torrent context menu. Each program definition stores the executable path, optional arguments, and path-mapping rules so qui can pass torrent metadata to your tools.
Security: Allow List
To keep this power feature safe, define an allow list in config.toml so only trusted paths can be executed:
externalProgramAllowList = [
"/usr/local/bin/sonarr",
"/home/user/bin" # Directories allow any executable inside them
]
Leave the list empty to keep the previous behaviour (any path accepted). The allow list lives exclusively in config.toml, which the web UI cannot edit, so you retain control over what binaries are exposed.
Where Programs Run
External programs always run on the same machine (or container) that is hosting the qui backend, not on the browser client. Make sure any executable paths, mounts, or environment variables are available to that host process. When you deploy qui inside Docker, the program runs inside the container unless you mount the executable in.
Creating and Editing a Program
- Open qui and go to Settings → External Programs
- Click Create External Program
- Fill in the form fields, then press Create. Toggle Enable this program to make it available in torrent menus
- Use the edit and delete actions in the list to maintain existing programs
Field Reference
| Field | Description |
|---|---|
| Name | Display label shown in the torrent context menu and settings list. Must be unique. |
| Program Path | Absolute path to the executable or script. Use the host path seen by the qui backend (e.g. /usr/local/bin/my-script.sh, C:\Scripts\postprocess.bat, C:\python312\python.exe). |
| Arguments Template | Optional string of command-line arguments. qui substitutes torrent metadata placeholders before spawning the process. |
| Path Mappings | Optional array of from → to prefixes that rewrite remote qBittorrent paths into local mount points. Helpful when qui runs locally but qBittorrent stores data elsewhere. |
| Launch in terminal window | Opens the program in an interactive terminal (cmd.exe on Windows, first available emulator on Linux/macOS). Disable for GUI apps or background daemons. |
| Enable this program | Determines whether the program shows up in the torrent context menu. |
Torrent Placeholders
Arguments are parsed with shell-style quoting and each placeholder is replaced with the corresponding torrent value before execution.
| Placeholder | Value |
|---|---|
{hash} | Torrent hash (always lowercase) |
{name} | Torrent name |
{save_path} | Torrent save path after path mappings are applied |
{content_path} | Full content path (file or folder) after path mappings are applied |
{category} | Torrent category |
{tags} | Comma-separated list of tags |
{state} | qBittorrent torrent state string |
{size} | Size in bytes |
{progress} | Progress value between 0 and 1 rounded to two decimal places |
Example arguments:
"{hash}" "{name}" --save "{save_path}" --category "{category}" --tags "{tags}"
D:\Upload Assistant\upload.py {save_path}\{name}
qui splits the template into arguments before substitutions are run, so you do not need to wrap values in extra quotes unless the called application expects them.
Path Mappings
Use path mappings when the filesystem paths reported by qBittorrent do not match the paths visible to qui. Each mapping replaces the longest matching prefix.
| Remote path (from qBittorrent) | Local path seen by qui | Mapping |
|---|---|---|
/data/torrents | /mnt/qbt | from=/data/torrents, to=/mnt/qbt |
Z:\downloads | /srv/downloads | from=Z:\downloads, to=/srv/downloads |
Given the template above, {save_path} becomes /mnt/qbt/Movies instead of /data/torrents/Movies. Be sure to use the same path separator style (/ vs \) as the remote qBittorrent instance. If no mapping matches, the original path is used.
Launch Modes
- Enable terminal window for scripts that need interaction or visible output.
- Disable terminal window for GUI applications or background tasks.
Programs run asynchronously - qui does not wait for completion.
Executing Programs
- Select one or more torrents
- Right-click to open the context menu
- Hover External Programs, then click the program name
- qui queues one execution per selected torrent. Results are reported via toast notifications (success, partial success, or failure)
Execution requests include the torrents from the currently selected instance only. Disabled programs are hidden from the submenu. Command failures emitted by the host OS are logged at info/debug level through zerolog; enable debug logging to see the full command line and any non-zero exit codes.
REST API
Automation workflows can manage external programs through the backend API (all endpoints require authentication):
| Method | Endpoint | Description |
|---|---|---|
GET | /api/external-programs | List programs |
POST | /api/external-programs | Create a program |
PUT | /api/external-programs/{id} | Update a program |
DELETE | /api/external-programs/{id} | Remove a program |
POST | /api/external-programs/execute | Execute a program |
Example request:
POST /api/external-programs/execute
Content-Type: application/json
{
"program_id": 2,
"instance_id": 1,
"hashes": ["c0ffee...", "deadbeef..."]
}
The response contains a results array with per-hash success flags and optional error messages. Treat the endpoint as fire-and-forget; it returns once the processes have been spawned.
Troubleshooting
- Docker: The executable must be inside the container or bind-mounted.
- Paths are wrong: Add or adjust path mappings so
{save_path}and{content_path}resolve to local mount points. - Multiple torrents: The program runs once per torrent. Ensure your script handles concurrent executions or uses a locking mechanism.