From 758cc986bb6bc677bb4fa9daff42fd44529db8d5 Mon Sep 17 00:00:00 2001 From: Estrella Pan Date: Thu, 2 Jul 2026 14:47:22 +0200 Subject: [PATCH] fix(downloader): build qB rule filter as regex alternation, not char-join build_rss_rule joined the comma-separated filter string with '|' via str.join, which splits it into characters ('720,480' -> '7|2|0|,|4|8|0') instead of alternating whole terms ('720|480') the way every other filter site does with .replace(',', '|'). Latent since the rule dict was first written; low real-world impact (the download path uses add_torrent, not qB-native RSS rules) but the extracted helper is now correct. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_014w1Z6Nxy6XTRgkFXqPr9Zh --- backend/src/module/downloader/rules.py | 10 +++++++++- backend/src/test/test_download_client.py | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/backend/src/module/downloader/rules.py b/backend/src/module/downloader/rules.py index 4187b181..4d199e53 100644 --- a/backend/src/module/downloader/rules.py +++ b/backend/src/module/downloader/rules.py @@ -14,10 +14,18 @@ def build_rss_rule(data: Bangumi | BangumiUpdate, save_path: str) -> dict: affected_feeds = ( data.rss_link if isinstance(data.rss_link, str) else ",".join(data.rss_link) ) + # filter is a comma-separated string of regex terms; qB wants them as a + # single alternation. join() would split the string into characters + # ("720,480" -> "7|2|0|,|4|8|0"); replace keeps whole terms ("720|480"). + must_not_contain = ( + data.filter.replace(",", "|") + if isinstance(data.filter, str) + else "|".join(data.filter) + ) return { "enable": True, "mustContain": data.title_raw, - "mustNotContain": "|".join(data.filter), + "mustNotContain": must_not_contain, "useRegex": True, "episodeFilter": "", "smartFilter": False, diff --git a/backend/src/test/test_download_client.py b/backend/src/test/test_download_client.py index 0e1e0620..85d6a62c 100644 --- a/backend/src/test/test_download_client.py +++ b/backend/src/test/test_download_client.py @@ -123,8 +123,8 @@ class TestSetRule: call_kwargs = mock_qb_client.rss_set_rule.call_args[1] rule = call_kwargs["rule_def"] assert rule["mustContain"] == "Mushoku Tensei" - # filter string is joined char-by-char with "|" (this is how the code works) - assert rule["mustNotContain"] == "|".join("720,480") + # comma-separated filter terms become a regex alternation for qB + assert rule["mustNotContain"] == "720|480" assert rule["enable"] is True assert "Season 2" in rule["savePath"]