Skip to content

Commit cb15b71

Browse files
committed
refactor(subscribe): unify best_version episode upgrade logic and always track downloads in note
- Simplify and centralize logic for filtering TV episodes during best_version (wash) mode, ensuring only episodes with strictly higher priority are considered for upgrade. - Always update subscribe.note with downloaded episodes regardless of best_version state, ensuring download history is reliably tracked and available for all subscription modes. - Remove redundant episode_group field from subscribe dict output. - Refactor search: remove multi-page search logic, streamline concurrent site search for both sync and async paths, and update progress reporting accordingly. - Remove obsolete tests for allowed_episodes propagation and note tracking, as logic is now unified and simplified.
1 parent 9319b47 commit cb15b71

3 files changed

Lines changed: 77 additions & 4 deletions

File tree

app/chain/search.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,6 @@ def __do_parallel_filter(torrent_list: List[TorrentInfo]) -> List[TorrentInfo]:
882882

883883
# 开始匹配
884884
_match_torrents = []
885-
torrenthelper = TorrentHelper()
886885
try:
887886
# 英文标题应该在别名/原标题中,不需要再匹配
888887
logger.info(f"开始匹配结果 标题:{mediainfo.title},原标题:{mediainfo.original_title},别名:{mediainfo.names}")
@@ -916,7 +915,7 @@ def __do_parallel_filter(torrent_list: List[TorrentInfo]) -> List[TorrentInfo]:
916915
continue
917916

918917
# 比对种子
919-
if torrenthelper.match_torrent(mediainfo=mediainfo,
918+
if TorrentHelper.match_torrent(mediainfo=mediainfo,
920919
torrent_meta=torrent_meta,
921920
torrent=torrent):
922921
# 匹配成功
@@ -950,7 +949,7 @@ def __do_parallel_filter(torrent_list: List[TorrentInfo]) -> List[TorrentInfo]:
950949
# 排序
951950
progress.update(value=99,
952951
text=f'正在对 {len(contexts)} 个资源进行排序,请稍候...')
953-
contexts = torrenthelper.sort_torrents(contexts)
952+
contexts = TorrentHelper.sort_torrents(contexts)
954953

955954
# 结束进度
956955
logger.info(f'搜索完成,共 {len(contexts)} 个资源')

app/chain/subscribe.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1441,7 +1441,7 @@ def match(self, torrents: Dict[str, List[Context]]):
14411441
not torrent_mediainfo.tmdb_id and not torrent_mediainfo.douban_id):
14421442
logger.debug(
14431443
f'{torrent_info.site_name} - {torrent_info.title} 重新识别失败,尝试通过标题匹配...')
1444-
if torrenthelper.match_torrent(mediainfo=mediainfo,
1444+
if TorrentHelper.match_torrent(mediainfo=mediainfo,
14451445
torrent_meta=torrent_meta,
14461446
torrent=torrent_info):
14471447
# 匹配成功

tests/test_subscribe_chain.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ def decorator(func):
9292

9393
return decorator
9494

95+
@staticmethod
96+
def add_event_listener(*args, **kwargs):
97+
"""兼容模块导入时注册配置变更监听。"""
98+
return None
99+
95100
event_module.eventmanager = _EventManager()
96101
event_module.Event = SimpleNamespace
97102

@@ -266,6 +271,8 @@ def set(self, *args, **kwargs):
266271
assert spec and spec.loader
267272
spec.loader.exec_module(module)
268273
module._injected_modules = injected_modules
274+
for injected_name in injected_modules:
275+
sys.modules.pop(injected_name, None)
269276
return module, module.SubscribeChain
270277

271278

@@ -313,6 +320,73 @@ def _build_download(priority, selected_episodes=None, meta_episodes=None):
313320
meta_info=SimpleNamespace(season_list=[1], episode_list=meta_episodes or []),
314321
)
315322

323+
def test_match_title_fallback_calls_torrent_match_from_class(self):
324+
"""确保标题兜底匹配不依赖 TorrentHelper 实例绑定。"""
325+
326+
class _ReachedTitleMatch(Exception):
327+
"""标记测试已经进入标题匹配函数体。"""
328+
329+
class _PlainTorrentHelper:
330+
"""模拟未声明 staticmethod 的历史 TorrentHelper 形态。"""
331+
332+
def match_torrent(mediainfo, torrent_meta, torrent):
333+
"""标记类级调用已经正确进入匹配逻辑。"""
334+
raise _ReachedTitleMatch
335+
336+
def filter_torrent(self, *args, **kwargs):
337+
"""保持订阅匹配后续过滤流程可继续执行。"""
338+
return True
339+
340+
subscribe = self._build_subscribe(
341+
best_version=0,
342+
custom_words=None,
343+
doubanid=None,
344+
episode_group=None,
345+
sites=[],
346+
tmdbid=1,
347+
)
348+
mediainfo = SimpleNamespace(
349+
clear=lambda: None,
350+
douban_id=None,
351+
title_year="Test Show (2026)",
352+
tmdb_id=1,
353+
type=MediaType.TV,
354+
)
355+
context = SimpleNamespace(
356+
media_info=None,
357+
media_recognize_fail_count=3,
358+
meta_info=SimpleNamespace(
359+
begin_season=1,
360+
episode_list=[],
361+
org_string="Test Show",
362+
season_list=[1],
363+
),
364+
torrent_info=SimpleNamespace(
365+
description="",
366+
site=1,
367+
site_name="TestSite",
368+
title="Test Show S01",
369+
),
370+
)
371+
372+
class _SubscribeOper:
373+
"""提供单条订阅,避免依赖真实数据库。"""
374+
375+
def list(self, *args, **kwargs):
376+
"""返回当前测试构造的订阅列表。"""
377+
return [subscribe]
378+
379+
chain = SubscribeChain()
380+
chain.recognize_media = lambda **kwargs: mediainfo
381+
chain.check_and_handle_existing_media = lambda **kwargs: (False, {})
382+
383+
with patch.object(SUBSCRIBE_CHAIN_MODULE, "SubscribeOper", _SubscribeOper), patch.object(
384+
SUBSCRIBE_CHAIN_MODULE,
385+
"TorrentHelper",
386+
_PlainTorrentHelper,
387+
), self.assertRaises(_ReachedTitleMatch):
388+
chain.match({"test.example": [context]})
389+
316390
def test_get_episode_priority_falls_back_to_current_priority(self):
317391
subscribe = self._build_subscribe(current_priority=80, episode_priority=None)
318392

0 commit comments

Comments
 (0)