How qBittorrent's RSS Autodownloader Works: Feed Parsing and Filtering Explained

qBittorrent's RSS autodownloader uses a three-stage pipeline where RSS::Feed downloads and parses XML into articles, RSS::AutoDownloader evaluates new articles against AutoDownloadRule filters, and matching torrents are automatically added via the AddTorrentManager.

The qBittorrent RSS autodownloader automates torrent acquisition by monitoring RSS and Atom feeds, applying user-defined filtering rules, and downloading matching content without manual intervention. According to the qbittorrent/qBittorrent source code, the implementation relies on a modular C++ architecture that separates feed management, XML parsing, and rule-based matching across the src/base/rss/ directory.

Feed Download and XML Parsing

The RSS::Feed class (src/base/rss/rss_feed.cpp) represents a single RSS subscription and handles the complete download-to-parse lifecycle. When a feed refresh is triggered via Feed::refresh(), the system registers a sequential download service to ensure only one request is active per URL at a time:

Net::DownloadManager::instance()->registerSequentialService(
      Net::ServiceID::fromURL(m_url), m_session->fetchDelay());
// src/base/rss/rss_feed.cpp#L106

On completion, Feed::handleDownloadFinished() receives the raw XML and forwards it to the RSS::Parser (src/base/rss/rss_parser.cpp). This parser uses QXmlStreamReader for streaming XML processing and includes a custom XmlStreamEntityResolver to decode common HTML entities (e.g.,  , €) that appear in feed titles【1†src/base/rss/rss_parser.cpp#L46-L56】.

The parser extracts key fields from each <item> or <entry> element and stores them in a QVariantHash:

  • Article::KeyTitle – the decoded article title
  • Article::KeyId – the globally unique identifier (GUID) for deduplication
  • Article::KeyTorrentURL – the torrent URL extracted from <enclosure> or link elements ending in .torrent

Article Storage and New Article Detection

After parsing completes, Feed::handleParsingFinished() iterates through the results and calls addArticle() for each entry (src/base/rss/rss_feed.cpp#L190-L199). This method creates an RSS::Article instance and inserts it into two internal structures:

  • m_articles – a hash map indexed by GUID for O(1) deduplication
  • m_articlesByDate – an ordered list for chronological display

If the article is genuinely new and unread, the feed emits the newArticle signal:

emit newArticle(article);
// src/base/rss/rss_feed.cpp#L221

This signal is the primary trigger for the auto-downloader workflow.

Auto-Downloader Processing and Rule Matching

The RSS::AutoDownloader class (src/base/rss/rss_autodownloader.cpp) connects to the newArticle signal during construction. When handleNewArticle() receives a new article, it validates that the article is unread and contains a torrent URL before queuing a processing job:

if (!article->isRead() && !article->torrentUrl().isEmpty())
    addJobForArticle(article);
// src/base/rss/rss_autodownloader.cpp#L17-L20

Jobs are processed sequentially by processJob(), which evaluates each job against every enabled RSS::AutoDownloadRule in priority order. A rule matches only when all conditions are satisfied:

if (!rule.isEnabled())               continue;
if (!rule.feedURLs().contains(job->feedURL)) continue;
if (!rule.accepts(job->articleData)) continue;
// src/base/rss/rss_autodownloadrule.cpp#L95-L102

The matching logic resides in AutoDownloadRule::matches() (src/base/rss/rss_autodownloadrule.cpp#L90-L105). This method performs several checks on the article title:

  • Must-contain / must-not-contain – simple substring search or regular expression if useRegex is enabled
  • Smart episode filter – predefined patterns matching season/episode formats (e.g., s01e01, 01x01, dates) compiled via AutoDownloader::computeSmartFilterRegex()
  • Episode filter – user-defined regular expression for specific matching
bool AutoDownloadRule::matches(const QVariantHash &articleData) const
{
    const QString title = articleData.value(Article::KeyTitle).toString();
    if (!matchesMustContainExpression(title))        return false;
    if (!matchesMustNotContainExpression(title))     return false;
    if (useSmartFilter() && !matchesSmartEpisodeFilter(title)) return false;
    if (useRegex() && !matchesExpression(title, episodeFilter())) return false;
    return true;
}

Torrent Addition and Post-Processing

When a rule matches, the auto-downloader immediately marks the article as read to prevent duplicate downloads, then delegates to the AddTorrentManager:

app()->addTorrentManager()->addTorrent(torrentURL, rule.addTorrentParams());
// src/base/rss/rss_autodownloader.cpp#L11-L13

The AddTorrentParams structure contains the rule's configured save path, category, tags, and other torrent options. If the URL points to a .torrent file rather than a magnet link, the downloader registers a waiting job (m_waitingJobs) and defers marking the article read until the download succeeds or fails (handleTorrentAdded() / handleAddTorrentFailed()).

Configuration and Persistence

Rules are serialized to JSON in the download_rules.json file via AutoDownloader::store() and reloaded at startup via load(). Each feed's articles are persisted as individual JSON files (<uid>.json) by Feed::store(), preserving read/unread states across application restarts.

You can programmatically add rules via the Web API:

POST /api/v2/rss/rules/addRule HTTP/1.1
Content-Type: application/json

{
  "ruleName": "MySeries",
  "ruleDefinition": {
    "mustContain": "MySeries",
    "mustNotContain": "Trailer",
    "feedURLs": ["https://example.com/rss.xml"],
    "useSmartFilter": true,
    "episodeFilter": "",
    "addTorrentParams": {
      "savePath": "/downloads/Series",
      "category": "Series"
    }
  }
}

Or via C++:

#include "base/rss/rss_autodownloadrule.h"
#include "base/rss/rss_autodownloader.h"

RSS::AutoDownloadRule rule(u"MySeries"_s);
rule.setEnabled(true);
rule.setFeedURLs({u"https://example.com/rss.xml"_s});
rule.setMustContain(u"MySeries"_s);
rule.setMustNotContain(u"Trailer"_s);
rule.setUseSmartFilter(true);
rule.setAddTorrentParams({
    .savePath = Path(u"/downloads/Series"_s),
    .category = u"Series"_s
});

RSS::AutoDownloader::instance()->setRule(rule);

Summary

  • RSS::Feed handles sequential downloads and XML parsing using QXmlStreamReader with HTML entity resolution.
  • Parsed articles are stored in hash maps and ordered lists, emitting newArticle signals for unread entries with torrent URLs.
  • RSS::AutoDownloader queues processing jobs and evaluates them against RSS::AutoDownloadRule objects using must-contain strings, regex patterns, and smart episode filters.
  • Matching torrents are passed to AddTorrentManager with parameterized download settings, with waiting jobs tracking direct file downloads.
  • Rules persist as JSON (download_rules.json) and integrate with the Web API for external automation.

Frequently Asked Questions

How does qBittorrent handle special characters and HTML entities in RSS feed titles?

The RSS::Parser (src/base/rss/rss_parser.cpp) implements a custom XmlStreamEntityResolver that maps common HTML entities like &nbsp; and &euro; to their Unicode equivalents during the QXmlStreamReader processing. This ensures that article titles containing these entities are correctly decoded before being stored in the Article object and evaluated by filtering rules.

What is the smart episode filter in qBittorrent's RSS autodownloader?

The smart episode filter is a predefined pattern matcher that recognizes standard television episode naming conventions including s01e01, 01x01, and date-based formats. The regex patterns are compiled centrally by AutoDownloader::computeSmartFilterRegex() in src/base/rss/rss_autodownloader.cpp and applied during AutoDownloadRule::matches() to automatically identify episode releases without requiring manual regex configuration.

How are RSS auto-download rules stored and persisted?

Rules are serialized to a JSON file named download_rules.json in the qBittorrent configuration directory via AutoDownloader::store(). Each rule stores its must-contain patterns, feed URLs, torrent parameters, and enabled state. The system also maintains legacy QSettings support for upgrading older installations. Feed articles themselves are stored as individual <uid>.json files to preserve read/unread status across restarts.

Can qBittorrent download torrents from RSS feeds that require authentication?

The download mechanism uses qBittorrent's global Net::DownloadManager, which respects the application's proxy and authentication settings. However, per-feed credentials must be embedded in the URL (e.g., https://user:pass@example.com/rss.xml) when the feed is added, as the RSS subsystem does not implement separate credential stores beyond the standard HTTP authentication handling provided by the underlying network stack.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →