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

> Understand qBittorrent's RSS autodownloader with this guide. Learn how feed parsing and filtering automatically download torrents, saving you time and effort. Master RSS automation today.

- Repository: [qBittorrent project/qBittorrent](https://github.com/qbittorrent/qBittorrent)
- Tags: deep-dive
- Published: 2026-05-05

---

**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`](https://github.com/qbittorrent/qBittorrent/blob/main/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:

```cpp
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`](https://github.com/qbittorrent/qBittorrent/blob/main/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., `&nbsp;`, `&euro;`) 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:

```cpp
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`](https://github.com/qbittorrent/qBittorrent/blob/main/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:

```cpp
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:

```cpp
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

```cpp
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**:

```cpp
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`](https://github.com/qbittorrent/qBittorrent/blob/main/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:

```http
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++:

```cpp
#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`](https://github.com/qbittorrent/qBittorrent/blob/main/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`](https://github.com/qbittorrent/qBittorrent/blob/main/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`](https://github.com/qbittorrent/qBittorrent/blob/main/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`](https://github.com/qbittorrent/qBittorrent/blob/main/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.