Skip to content

Frequently Asked Questions

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

General Questions

Q: What is qBittorrent Automation?

A: qBittorrent Automation is a Python-based rules engine that automates torrent management tasks through the qBittorrent Web API. It allows you to define YAML-based rules that automatically categorize, tag, pause, resume, delete, and manage torrents based on conditions you specify.

Q: Why not use qBittorrent's built-in RSS automation?

A: qBittorrent's RSS automation only works for adding new torrents based on RSS feeds. This system provides:

  • Management of existing torrents based on conditions
  • Multiple trigger types (manual, scheduled, webhooks)
  • Complex condition logic (AND/OR/NOT groups)
  • Access to all torrent fields and metadata
  • Idempotent actions that won't repeat unnecessarily
  • Dry-run mode for safe testing

Q: Does this work with qBittorrent v4.x?

A: This system is designed for qBittorrent Web API v5.0+ which introduced breaking changes (e.g., pausestop, resumestart). If you're using qBittorrent v4.x, you'll need to modify the API client to use the old endpoint names.

Q: Is this safe to run on my existing torrents?

A: Yes! The system has several safety features:

  • Dry-run mode (--dry-run) shows what would happen without making changes
  • Idempotent actions skip if torrent already in desired state
  • File-order execution allows predictable rule evaluation
  • Comprehensive logging with trace mode for debugging
  • stop_on_match prevents multiple rules from affecting the same torrent

Q: Can I run this on Windows?

A: Yes! The system is Python-based and works on Windows, Linux, and macOS. You'll need Python 3.8+ and the required dependencies (requests, pyyaml).

Configuration Questions

Q: Where should I put my config files?

A: By default, the system looks for:

  • config/config.yml - Connection and global settings
  • config/rules.yml - Your automation rules

You can override these with --config and --rules flags.

Q: How do I use environment variables in config files?

A: Use ${VARIABLE_NAME} syntax:

qbittorrent:
  username: ${QB_USERNAME}
  password: ${QB_PASSWORD}

The system expands these at runtime using os.environ.

Q: Can I have multiple rule files?

A: Currently, the system loads a single rules file. However, you can organize rules within the file using YAML comments and logical grouping:

# ===== Content Organization =====
- name: "Categorize movies"
  # ...

# ===== Cleanup =====
- name: "Remove old torrents"
  # ...

Q: What happens if qBittorrent is unreachable?

A: The system will raise a ConnectionError and exit. For scheduled triggers, ensure you have proper error handling in your cron job or systemd timer.

Q: How do I enable trace logging?

A: Use the --trace flag:

python triggers/manual.py --trace

This logs all API calls, field accesses, and condition evaluations.

Field & Condition Questions

Q: How do I know what fields are available?

A: See the Available Fields section (§7) for complete tables. You can also:

  1. Enable --trace mode to see all field accesses
  2. Check qBittorrent Web API documentation
  3. Use /api/v2/torrents/info to see raw torrent data

Q: What's the difference between info.size and info.total_size?

A:

  • info.size - Total size of the torrent (all files)
  • info.total_size - Same as info.size (alias in qBittorrent API)

Both return the same value in bytes.

Q: Why is my files.* condition not working?

A: files.* is a collection field - it returns a list. Operators check if ANY item in the list matches:

# This checks if ANY file name contains "sample"
- field: files.name
  operator: contains
  value: "sample"

If you need to check ALL files, use a none condition with the inverse:

# This ensures NO file is larger than 1GB
conditions:
  none:
    - field: files.size
      operator: ">"
      value: 1073741824

Q: How do I check if a torrent has NO tags?

A: Check if the tags string is empty:

conditions:
  all:
    - field: info.tags
      operator: "=="
      value: ""

Q: Can I use regex in conditions?

A: Yes! Use the matches operator:

- field: info.name
  operator: matches
  value: '(?i).*[Ss]\d{2}[Ee]\d{2}.*'  # TV show pattern

Use (?i) for case-insensitive matching.

Q: How do older_than and newer_than work?

A: These operators compare Unix timestamps against a relative time in seconds:

# Torrents added more than 7 days ago
- field: info.added_on
  operator: older_than
  value: 604800  # 7 days in seconds

# Torrents completed less than 24 hours ago
- field: info.completion_on
  operator: newer_than
  value: 86400  # 24 hours in seconds

Q: What does info.state return?

A: The current state string, one of:

  • downloading - Actively downloading
  • uploading - Actively seeding
  • pausedDL - Paused while incomplete
  • pausedUP - Paused after completion
  • stalledDL - No download progress
  • stalledUP - No upload activity
  • checkingUP - Checking files after completion
  • checkingDL - Checking files while incomplete
  • error - Torrent has errors
  • missingFiles - Files missing on disk
  • forcedUP - Force seeding
  • forcedDL - Force downloading

Trigger Questions

Q: How often do scheduled triggers run?

A: Scheduled triggers use cron expressions. You control the schedule:

# Every hour
schedule: "0 * * * *"

# Every day at 3 AM
schedule: "0 3 * * *"

# Every Monday at 9 AM
schedule: "0 9 * * 1"

Then run triggers/scheduled.py in your cron or systemd timer.

Q: Can I test scheduled rules without waiting?

A: Yes! Use manual trigger with dry-run:

python triggers/manual.py --dry-run

This evaluates all enabled rules immediately.

Q: How do webhooks work?

A: Set up qBittorrent to call your webhook server when torrents are added or completed:

  1. Run the webhook listener:
python triggers/on_added.py --port 8081
  1. Configure qBittorrent to POST to http://your-server:8081/webhook when torrents are added

  2. Rules with trigger: on_added will be evaluated for the specific torrent

Q: Can I filter which torrents a trigger processes?

A: Yes! Use the filter section in trigger conditions:

conditions:
  trigger: manual
  filter:
    category: "Movies"  # Only process Movies category
    state: "downloading"  # Only downloading torrents
  all:
    - field: info.ratio
      operator: "<"
      value: 1.0

Q: What's the difference between manual.py and scheduled.py?

A:

  • manual.py - Run on-demand, processes all torrents matching rules (useful for testing or one-time bulk operations)
  • scheduled.py - Same as manual but designed to be run by cron/systemd timer at regular intervals

Both use trigger: manual or trigger: scheduled in rules.

Action Questions

Q: Will stop action pause a torrent that's already paused?

A: No - actions are idempotent. The system checks the current state:

if torrent["state"] in ["pausedUP", "pausedDL"]:
    logger.info(f"Torrent already stopped, skipping")
    return

Q: What's the difference between start and force_start?

A:

  • start - Resume normal downloading/seeding (respects queue limits)
  • force_start - Force the torrent to start regardless of queue limits (useful for private trackers or low-seeded content)

Q: Does delete_torrent remove files from disk?

A: Only if you specify delete_files: true:

actions:
  - type: delete_torrent
    params:
      delete_files: true  # Remove from disk

If false or omitted, only removes from qBittorrent (files stay on disk).

Q: Can I set multiple tags at once?

A: Yes! Use set_tags:

actions:
  - type: set_tags
    params:
      tags: "movies,hd,private"

This replaces all existing tags. To add tags while keeping existing ones, use add_tag.

Q: How do I remove all tags?

A: Use set_tags with an empty string:

actions:
  - type: set_tags
    params:
      tags: ""

Q: What does limit: -1 mean for upload/download limits?

A: -1 means unlimited (removes any speed limit).

Q: Can I run multiple actions for the same torrent?

A: Yes! Actions execute in order:

actions:
  - type: set_category
    params:
      category: "Movies"
  - type: add_tag
    params:
      tag: "auto-categorized"
  - type: stop

All three actions will execute if conditions match.

Performance Questions

Q: How many API calls does the system make?

A: The system optimizes API calls through caching:

Per-Trigger API Calls:

  1. Initial torrent list fetch (1 call)
  2. Per-torrent metadata fetches (only if fields accessed):
    • trackers.*/api/v2/torrents/trackers (1 call per torrent)
    • files.*/api/v2/torrents/files (1 call per torrent)
    • properties.*/api/v2/torrents/properties (1 call per torrent)
    • peers.*/api/v2/sync/torrentPeers (1 call per torrent)
    • webseeds.*/api/v2/torrents/webseeds (1 call per torrent)

Example: If you have 100 torrents and rules only check info.* fields, that's 1 API call total. If rules also check trackers.url, that's 1 + 100 = 101 calls.

Q: How can I reduce API calls?

A: Optimize your rules:

  1. Use filters to limit torrents processed:
conditions:
  filter:
    category: "Movies"  # Only fetch Movies category
  1. Avoid expensive fields if possible:

    • info.* - Free (included in main list)
    • trackers.*, files.*, properties.* - Expensive (1 call per torrent)
  2. Use stop_on_match: true to prevent redundant rule evaluation:

- name: "First matching rule"
  stop_on_match: true

Q: Can I run this on a system with 10,000+ torrents?

A: Yes, but optimize carefully:

  1. Use aggressive filtering:
filter:
  state: "downloading"  # Process only active torrents
  1. Avoid expensive fields in high-frequency rules

  2. Run scheduled triggers less frequently (every 6-12 hours instead of hourly)

  3. Consider breaking rules into multiple files run at different intervals

Q: How long does execution take?

A: Depends on:

  • Number of torrents
  • Number of rules
  • Fields accessed
  • Network latency to qBittorrent

Typical performance:

  • 100 torrents, simple rules (info.* only): < 1 second
  • 100 torrents, complex rules (all fields): 5-10 seconds
  • 1000 torrents, simple rules: 2-5 seconds
  • 1000 torrents, complex rules: 30-60 seconds

Use --trace to see timing breakdowns.

Error & Troubleshooting Questions

Q: I'm getting 401 Unauthorized errors

A: Check your credentials in config/config.yml:

qbittorrent:
  username: "admin"
  password: "your_password"

Also verify qBittorrent Web UI authentication is enabled.

Q: Rules aren't matching torrents I expect

A: Enable --trace mode to see condition evaluation:

python triggers/manual.py --trace

Look for lines like:

[TRACE] Evaluating condition: info.ratio >= 2.0
[TRACE] Result: False (actual value: 1.5)

Q: Getting KeyError when accessing fields

A: Not all fields exist for all torrents. The system handles missing fields gracefully:

# If field doesn't exist, comparison returns False

Check that you're using correct field names from the Available Fields table.

Q: schedule trigger isn't running

A: Scheduled triggers don't run automatically - you need to set up cron or systemd timer:

Cron example:

0 * * * * cd /path/to/qbittorrent-automation && python triggers/scheduled.py

Q: Webhook server won't start

A: Check port availability:

# Linux: Check if port 8081 is in use
sudo netstat -tulpn | grep 8081

# Free the port or use a different one
python triggers/on_added.py --port 8082

Q: Changes aren't applying to torrents

A: Check:

  1. Dry-run mode: Are you using --dry-run? Remove it to apply changes.
  2. Idempotency: Action may be skipped if torrent already in desired state (check logs)
  3. Conditions: Rule may not be matching (use --trace)
  4. stop_on_match: Earlier rule may have matched first

Docker & Deployment Questions

Q: Can I run this in Docker?

A: Yes! Example Dockerfile:

FROM python:3.11-slim

WORKDIR /app

# Install dependencies
RUN pip install requests pyyaml

# Copy application
COPY lib/ /app/lib/
COPY triggers/ /app/triggers/
COPY config/ /app/config/

# Run scheduled trigger every hour
CMD ["sh", "-c", "while true; do python triggers/scheduled.py; sleep 3600; done"]

Q: How do I deploy with systemd?

A: Create a service file and timer:

/etc/systemd/system/qbittorrent-automation.service:

[Unit]
Description=qBittorrent Automation
After=network.target

[Service]
Type=oneshot
WorkingDirectory=/opt/qbittorrent-automation
ExecStart=/usr/bin/python3 triggers/scheduled.py
User=qbittorrent

/etc/systemd/system/qbittorrent-automation.timer:

[Unit]
Description=Run qBittorrent Automation hourly

[Timer]
OnCalendar=hourly
Persistent=true

[Install]
WantedBy=timers.target

Enable and start:

sudo systemctl enable qbittorrent-automation.timer
sudo systemctl start qbittorrent-automation.timer

Q: Can I run multiple instances?

A: Yes, but ensure they don't conflict:

  1. Use different rule files:
python triggers/manual.py --rules config/rules-cleanup.yml
python triggers/manual.py --rules config/rules-categorization.yml
  1. Or use different trigger types (manual, scheduled, webhooks) simultaneously

Q: How do I integrate with Sonarr/Radarr?

A: Use the on_added webhook trigger:

  1. Run webhook server:
python triggers/on_added.py --port 8081
  1. Configure Sonarr/Radarr to send webhook to your server after adding torrents to qBittorrent

  2. Create rules with trigger: on_added to auto-categorize/tag based on naming patterns

🎯 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