-
Notifications
You must be signed in to change notification settings - Fork 0
Rules Architecture
Stephen Cox edited this page Dec 13, 2025
·
2 revisions
┌─────────────────────────────────────────┐
│ Trigger Execution │
│ (manual/scheduled/on_added/on_completed)│
└────────────────┬────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Load Torrent(s) │
│ • All torrents (manual/scheduled) │
│ • Single torrent (webhooks) │
└────────────────┬────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Load Rules (config/rules.yml) │
│ Rules execute in file order │
└────────────────┬────────────────────────┘
│
┌────────────┴────────────┐
│ For Each Rule: │
│ 1. Check if enabled │
│ 2. Check trigger filter │
└────────────┬────────────┘
│
┌────────────▼────────────┐
│ For Each Torrent: │
└────────────┬────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Evaluate Conditions │
│ 1. Check "all" group (AND) │
│ 2. Check "any" group (OR) │
│ 3. Check "none" group (NOT) │
│ All groups must pass │
└────────────────┬────────────────────────┘
│
┌────────┴────────┐
│ Matched? │
└────────┬────────┘
Yes ◄──┴──► No
│ │
▼ ▼
┌──────────┐ Continue
│ Execute │ to next
│ Actions │ torrent
└─────┬────┘
│
▼
┌───────────────┐
│ stop_on_match │
│ = true? │
└───────┬───────┘
Yes │ No
Skip │ Continue
this │ rules for
torrent │ this torrent
Rules support three logical groups that can be combined:
-
all: Every condition in the list must be true (AND logic) -
any: At least one condition must be true (OR logic) -
none: No conditions can be true (NOT logic)
Evaluation Order:
- All three groups are evaluated independently
- The rule matches only if all groups pass
- Empty/missing groups are skipped (treated as pass)
Examples:
# Only "all" group
conditions:
all:
- field: info.ratio
operator: ">="
value: 2.0
- field: info.state
operator: ==
value: uploading
# Result: ratio >= 2.0 AND state = uploading# Only "any" group
conditions:
any:
- field: info.state
operator: ==
value: error
- field: info.state
operator: ==
value: missingFiles
# Result: state = error OR state = missingFiles# Combining groups
conditions:
all:
- field: info.ratio
operator: ">="
value: 2.0
none:
- field: info.category
operator: ==
value: keep
# Result: (ratio >= 2.0) AND NOT (category = keep)# Complex combination
conditions:
all:
- field: info.size
operator: ">"
value: 10737418240 # 10 GB
any:
- field: info.name
operator: contains
value: "1080p"
- field: info.name
operator: contains
value: "2160p"
none:
- field: info.category
operator: in
value: [keep, seedbox]
# Result: (size > 10GB) AND (name has 1080p OR 2160p) AND NOT (category in [keep, seedbox])The engine uses dot notation to access different qBittorrent API endpoints efficiently.
Dot Notation Format: endpoint.property
Examples:
-
info.name→ Torrent name from torrents/info endpoint -
trackers.url→ Tracker URLs from torrents/trackers endpoint -
files.name→ File names from torrents/files endpoint
API Call Patterns:
| Field Category | API Endpoint | When Called | Cache Scope | Cost |
|---|---|---|---|---|
info.* |
/torrents/info | Pre-loaded | Per execution | Free |
trackers.* |
/torrents/trackers | First use per torrent | Per execution | 1 call/torrent |
files.* |
/torrents/files | First use per torrent | Per execution | 1 call/torrent |
peers.* |
/sync/torrentPeers | First use per torrent | Per execution | 1 call/torrent |
properties.* |
/torrents/properties | First use per torrent | Per execution | 1 call/torrent |
webseeds.* |
/torrents/webseeds | First use per torrent | Per execution | 1 call/torrent |
transfer.* |
/transfer/info | First use (global) | Per execution | 1 call total |
app.* |
/app/preferences | First use (global) | Per execution | 1 call total |
Caching Behavior:
- info.*: Already loaded, zero cost
- Per-torrent fields: Called once per torrent, then cached for that execution
- Global fields: Called once total, shared across all torrents
Performance Tips:
- Use
info.*fields whenever possible (free) - Avoid expensive fields (
files.*,trackers.*) in high-frequency webhooks - Global fields (
transfer.*,app.*) are cheap to use
Collection Field Behavior:
Some fields return lists (collections):
-
trackers.*- List of trackers -
files.*- List of files -
peers.*- List of peers -
webseeds.*- List of web seeds
Operators check if ANY item matches:
- field: trackers.url
operator: contains
value: ".private"
# Returns TRUE if ANY tracker URL contains ".private"- field: files.name
operator: matches
value: '(?i)\.rar$'
# Returns TRUE if ANY file name ends with .rarqbt-rules v0.3.0 | Python-based rules engine for qBittorrent automation
GitHub • PyPI • Issues • Discussions • Contributing • License
Requirements: Python 3.8+ • qBittorrent 5.0+
Made with ❤️ by the qbt-rules community | Licensed under MIT
v0.3.0 | GitHub
- ✅ Unified CLI (
qbt-rules) - ✅ Custom triggers
- ✅ Trigger-agnostic mode
- ✅ Size operators (
50GB)