Skip to content

Conditions

Stephen Cox edited this page Dec 13, 2025 · 3 revisions

Conditions determine which torrents match a rule. Three logical groups are available: all, any, and none.

Overview

Condition Groups:

Group Logic Description Use When
all AND Every condition must be true Need multiple criteria simultaneously
any OR At least one condition must be true Match alternatives or broad filtering
none NOT No conditions can be true Exclusions or inverse matching

Combining Groups:

  • All three groups can be used together
  • All groups must pass for the rule to match
  • Empty/missing groups are ignored (treated as pass)

ALL Conditions (AND Logic)

Description: Every condition in the all list must be true for the group to pass.

Structure:

conditions:
  all:
    - field: info.name
      operator: contains
      value: "1080p"
    - field: info.category
      operator: ==
      value: ""
    - field: info.size
      operator: ">"
      value: 1073741824
# ALL three must be true: name has "1080p" AND no category AND size > 1GB

Use Cases:

  • Narrow down matches - Require multiple criteria
  • Precise filtering - All conditions must align
  • Most common pattern - Default choice for most rules

Examples:

# HD movies without category
conditions:
  all:
    - field: info.name
      operator: matches
      value: '(?i).*(1080p|2160p).*'
    - field: info.category
      operator: ==
      value: ""
# Private tracker torrents over 2.0 ratio
conditions:
  all:
    - field: info.ratio
      operator: ">="
      value: 2.0
    - field: trackers.url
      operator: contains
      value: ".private"
# Old completed torrents not in keep category
conditions:
  all:
    - field: info.completion_on
      operator: older_than
      value: 30 days
    - field: info.ratio
      operator: ">="
      value: 1.0
    - field: info.category
      operator: "!="
      value: keep

ANY Conditions (OR Logic)

Description: At least one condition in the any list must be true for the group to pass.

Structure:

conditions:
  any:
    - field: info.state
      operator: ==
      value: error
    - field: info.state
      operator: ==
      value: missingFiles
    - field: info.state
      operator: ==
      value: stalledDL
# ANY one must be true: state=error OR state=missingFiles OR state=stalledDL

Use Cases:

  • Match alternatives - Multiple acceptable patterns
  • Broad filtering - "Either this OR that"
  • List of exceptions - Match any of several values

Examples:

# Remove torrents in error states
conditions:
  any:
    - field: info.state
      operator: ==
      value: error
    - field: info.state
      operator: ==
      value: missingFiles
# Match either 1080p or 2160p resolution
conditions:
  any:
    - field: info.name
      operator: contains
      value: "1080p"
    - field: info.name
      operator: contains
      value: "2160p"
# Block multiple file extensions
conditions:
  any:
    - field: files.name
      operator: matches
      value: '(?i)\.rar$'
    - field: files.name
      operator: matches
      value: '(?i)\.zip$'
    - field: files.name
      operator: matches
      value: '(?i)\.7z$'

Tip: For list matching, use in operator instead:

# Simpler alternative to above
conditions:
  any:
    - field: info.state
      operator: in
      value: [error, missingFiles, stalledDL]

NONE Conditions (NOT Logic)

Description: No conditions in the none list can be true for the group to pass.

Structure:

conditions:
  none:
    - field: info.category
      operator: in
      value: [keep, seedbox]
    - field: info.tags
      operator: contains
      value: "permanent"
# NONE can be true: NOT (category in [keep, seedbox]) AND NOT (has "permanent" tag)

Use Cases:

  • Exclusions - Exclude specific cases
  • Inverse filtering - "Everything except..."
  • "Unless" clauses - Do action unless condition is true

Examples:

# Delete old torrents NOT in keep category
conditions:
  all:
    - field: info.completion_on
      operator: older_than
      value: 30 days
  none:
    - field: info.category
      operator: ==
      value: keep
# Apply limits EXCEPT to private trackers
conditions:
  all:
    - field: info.ratio
      operator: ">="
      value: 2.0
  none:
    - field: trackers.url
      operator: contains
      value: ".private"
# Stop seeding UNLESS in seedbox category
conditions:
  all:
    - field: info.ratio
      operator: ">="
      value: 3.0
    - field: info.seeding_time
      operator: ">"
      value: 2592000  # 30 days
  none:
    - field: info.category
      operator: ==
      value: seedbox

Combining Condition Groups

You can use multiple groups together. All groups must pass for the rule to match.

Pattern 1: all + none ("Match these, except...")

conditions:
  all:
    - field: info.ratio
      operator: ">="
      value: 2.0
    - field: info.completion_on
      operator: older_than
      value: 7 days
  none:
    - field: info.category
      operator: in
      value: [keep, seedbox, long-term]
# Match: ratio >= 2.0 AND completed > 7 days ago
# Except: NOT in categories keep/seedbox/long-term

Pattern 2: any + all ("Match any of these, but also require...")

conditions:
  any:
    - field: info.name
      operator: contains
      value: "1080p"
    - field: info.name
      operator: contains
      value: "2160p"
  all:
    - field: info.size
      operator: ">"
      value: 5368709120  # > 5GB
    - field: info.category
      operator: ==
      value: ""
# Match: (1080p OR 2160p) AND size > 5GB AND no category

Pattern 3: all + any + none (Complex filtering)

conditions:
  all:
    - field: info.completion_on
      operator: older_than
      value: 14 days
  any:
    - field: info.ratio
      operator: ">="
      value: 3.0
    - field: info.num_leechs
      operator: ==
      value: 0
  none:
    - field: info.category
      operator: in
      value: [seedbox, permanent]
    - field: trackers.url
      operator: contains
      value: ".private"
# Match: completed > 14 days ago
#    AND (ratio >= 3.0 OR no leeches)
#    AND NOT (in seedbox/permanent categories)
#    AND NOT (private tracker)

Nested Conditions (Advanced)

New Feature: You can nest all, any, and none groups inside each other for complex logical expressions.

How It Works:

  • Instead of a field condition, provide another group (all, any, or none)
  • Nesting can be multiple levels deep
  • Useful for expressing complex boolean logic

Pattern 1: Nested ANY inside ALL

conditions:
  all:
    - field: info.state
      operator: in
      value: [uploading, stalledUP, pausedUP]
    - any:  # Nested any group
        - field: info.ratio
          operator: ">="
          value: 5.0
        - field: info.completion_on
          operator: older_than
          value: "90 days"
# Match: (state is uploading/stalledUP/pausedUP) AND (ratio >= 5.0 OR completed > 90 days ago)

Pattern 2: Nested ALL inside ANY

conditions:
  any:
    - all:  # Nested all group
        - field: info.ratio
          operator: ">="
          value: 1.0
        - field: info.state
          operator: "=="
          value: uploading
    - field: info.ratio
      operator: "<"
      value: 0.1
# Match: ((ratio >= 1.0 AND state = uploading) OR ratio < 0.1)

Pattern 3: Nested NONE inside ALL

conditions:
  all:
    - field: info.size
      operator: larger_than
      value: "10GB"
    - none:  # Nested none group
        - field: info.category
          operator: in
          value: [keep, seedbox]
        - field: trackers.url
          operator: contains
          value: ".private"
# Match: size > 10GB AND NOT (in keep/seedbox OR private tracker)

Pattern 4: Multiple Nesting Levels

conditions:
  all:
    - field: info.state
      operator: "=="
      value: uploading
    - any:  # Level 1 nesting
        - field: info.ratio
          operator: ">="
          value: 3.0
        - all:  # Level 2 nesting
            - field: info.completion_on
              operator: older_than
              value: "30 days"
            - none:  # Level 3 nesting
                - field: info.category
                  operator: "=="
                  value: keep
# Match: state = uploading AND (ratio >= 3.0 OR (completed > 30 days AND NOT keep category))

Use Cases:

  • Complex cleanup rules - Multiple criteria with fallbacks
  • Conditional seeding - Different strategies based on tracker type
  • Priority management - Tiered priority based on multiple factors
  • Smart categorization - Category selection with multiple decision paths

Performance Note: Nested conditions are evaluated depth-first. Place cheaper conditions (e.g., info.* fields) at outer levels when possible.

Operator Reference

Equality Operators

Operator Description Value Types Example
== Exact match (equals) string, number, boolean info.category == "movies"
!= Not equal string, number, boolean info.state != "error"

Comparison Operators

Operator Description Value Types Example
> Greater than number info.ratio > 2.0
< Less than number info.size < 1073741824
>= Greater than or equal number info.ratio >= 1.0
<= Less than or equal number info.progress <= 0.5
larger_than Greater than (human-readable sizes) string with units (KB, MB, GB, TB) info.size larger_than "10GB"
smaller_than Less than (human-readable sizes) string with units (KB, MB, GB, TB) info.size smaller_than "100MB"

Size Operators (v0.3.0+):

  • larger_than and smaller_than accept human-readable size strings
  • Supported units: KB, MB, GB, TB (case-insensitive)
  • Examples: "50GB", "100MB", "1TB", "500KB"

String Operators

Operator Description Case Sensitive Example
contains Substring match Yes info.name contains "1080p"
not_contains Does not contain Yes info.name not_contains "sample"
matches Regex pattern match Depends on regex info.name matches "(?i).*s\d{2}e\d{2}.*"

List Operators

Operator Description Example
in Value is in list info.state in ["error", "missingFiles"]
not_in Value is not in list info.category not_in ["keep", "seedbox"]

Time Operators

Operator Description Value Format Example
older_than Unix timestamp older than "N days" or "N hours" info.added_on older_than "30 days"
newer_than Unix timestamp newer than "N days" or "N hours" info.completion_on newer_than "7 days"

Time Value Formats:

  • Days: "7 days", "30 days", "1 day"
  • Hours: "12 hours", "48 hours", "1 hour"
  • Minutes: "30 minutes", "90 minutes", "1 minute"

Operator Behavior with None/Missing Values:

Operator Type Behavior when field is None/missing
!=, not_in, not_contains Returns true
All others Returns false

Collection Field Behavior:

For collection fields (trackers.*, files.*, peers.*, webseeds.*):

  • Operators check if ANY item in the collection matches
  • Returns true if at least one item matches

Examples:

# Equality
- field: info.category
  operator: ==
  value: "movies"

# Comparison
- field: info.ratio
  operator: ">="
  value: 2.0

# String contains
- field: info.name
  operator: contains
  value: "1080p"

# Regex (case-insensitive TV show pattern)
- field: info.name
  operator: matches
  value: '(?i).*s\d{2}e\d{2}.*'

# List membership
- field: info.state
  operator: in
  value: ["error", "missingFiles", "stalledDL"]

# Time-based (older than 30 days)
- field: info.added_on
  operator: older_than
  value: "30 days"

# Collection (ANY tracker contains ".private")
- field: trackers.url
  operator: contains
  value: ".private"

# Size comparison (human-readable, v0.3.0+)
- field: info.size
  operator: larger_than
  value: "50GB"

# Size comparison (human-readable, v0.3.0+)
- field: info.size
  operator: smaller_than
  value: "100MB"

🎯 qbt-rules

v0.3.0 | GitHub


📚 Getting Started

📖 Core Concepts

🔧 Configuration

🆘 Help & Support

🤝 Contributing


🆕 What's New (v0.3.0)

  • ✅ Unified CLI (qbt-rules)
  • ✅ Custom triggers
  • ✅ Trigger-agnostic mode
  • ✅ Size operators (50GB)

🔗 Quick Links

Clone this wiki locally