fix(download): apply custom words to torrent episodes (#6234)

This commit is contained in:
jxxghp
2026-08-09 16:32:12 +08:00
parent e6d7d57e6f
commit 15c73240ac
4 changed files with 74 additions and 5 deletions

View File

@@ -1097,6 +1097,7 @@ class DownloadChain(ChainBase):
"""
# 已下载的项目
downloaded_list: List[Context] = []
custom_word_list = custom_words.splitlines() if custom_words else None
def __update_seasons(_mid: Union[int, str], _need: list, _current: list) -> list:
"""
@@ -1357,7 +1358,10 @@ class DownloadChain(ChainBase):
if isinstance(content, str):
logger.warn(f"{meta.org_string} 下载地址是磁力链,无法确定种子文件集数")
continue
torrent_episodes = TorrentHelper().get_torrent_episodes(torrent_files)
torrent_episodes = TorrentHelper().get_torrent_episodes(
torrent_files,
custom_words=custom_word_list,
)
logger.info(f"{meta.org_string} 解析种子文件集数为 {torrent_episodes}")
if not torrent_episodes:
continue
@@ -1586,7 +1590,10 @@ class DownloadChain(ChainBase):
logger.warn(f"{meta.org_string} 下载地址是磁力链,无法解析种子文件集数")
continue
# 种子全部集
torrent_episodes = TorrentHelper().get_torrent_episodes(torrent_files)
torrent_episodes = TorrentHelper().get_torrent_episodes(
torrent_files,
custom_words=custom_word_list,
)
logger.info(f"{torrent.site_name} - {meta.org_string} 解析种子文件集数:{torrent_episodes}")
# 选中的集
selected_episodes = set(torrent_episodes).intersection(effective_need)

View File

@@ -366,9 +366,13 @@ class TorrentHelper:
return result
@staticmethod
def get_torrent_episodes(files: list) -> list:
def get_torrent_episodes(files: list, custom_words: Optional[List[str]] = None) -> list:
"""
从种子的文件清单中获取所有集数
:param files: 种子文件清单
:param custom_words: 当前下载来源的临时自定义识别词
:return: 识别到的全部集数
"""
episodes = []
for file in files:
@@ -378,7 +382,7 @@ class TorrentHelper:
if not file_path.suffix or file_path.suffix.lower() not in settings.RMT_MEDIAEXT:
continue
# 只使用文件名识别
meta = MetaInfo(file_path.name)
meta = MetaInfo(file_path.name, custom_words=custom_words)
if not meta.begin_episode:
continue
episodes = list(set(episodes).union(set(meta.episode_list)))

View File

@@ -426,6 +426,7 @@ class _FakeBatchTorrentHelper:
"""
episodes = []
received_custom_words = None
def sort_torrents(self, contexts):
"""
@@ -452,7 +453,8 @@ class _FakeBatchTorrentHelper:
results.append(context)
return results
def get_torrent_episodes(self, _files):
def get_torrent_episodes(self, _files, custom_words=None):
type(self).received_custom_words = custom_words
return list(self.episodes)
@@ -675,6 +677,47 @@ def test_batch_download_threads_custom_words_to_download_single(monkeypatch):
assert chain.download_single.call_args.kwargs["custom_words"] == custom_words
def test_batch_download_applies_custom_words_to_torrent_file_episodes(monkeypatch):
"""订阅识别词须用于种子文件集数解析,确保跨季映射后能选中缺失集。"""
_FakeBatchTorrentHelper.episodes = [170]
_FakeBatchTorrentHelper.received_custom_words = None
monkeypatch.setattr(download_module, "TorrentHelper", _FakeBatchTorrentHelper)
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
chain = DownloadChain.__new__(DownloadChain)
chain.download_torrent = MagicMock(
return_value=(b"torrent-content", "", ["A.Will.Eternal.S04E05.mkv"]),
)
chain.download_single = MagicMock(return_value="hash")
context = _build_tv_context()
no_exists = {
1: {
1: NotExistMediaInfo(
season=1,
episodes=[170],
total_episode=200,
start_episode=155,
)
}
}
custom_words = (
"A.Will.Eternal.S04 => 一念永恒{[tmdbid=107371;type=tv]}S01 "
"&& S01 <> 2160p >> EP+165"
)
downloads, lefts = chain.batch_download(
contexts=[context],
no_exists=no_exists,
custom_words=custom_words,
)
assert downloads == [context]
assert lefts == {}
assert _FakeBatchTorrentHelper.received_custom_words == [custom_words]
assert chain.download_single.call_args.kwargs["episodes"] == {170}
def test_download_single_records_failure_cooldown_when_downloader_rejects(monkeypatch):
"""
下载器拒绝种子且没有返回 hash 时,应记录资源级失败冷却。

View File

@@ -314,6 +314,21 @@ def test_custom_words_replace_then_episode_offset():
assert meta.apply_words == custom_words
def test_get_torrent_episodes_applies_custom_words():
"""种子文件集数解析应使用订阅识别词完成跨季集数映射。"""
custom_words = [
"A.Will.Eternal.S04 => 一念永恒{[tmdbid=107371;type=tv]}S01 "
"&& S01 <> 2160p >> EP+165"
]
episodes = TorrentHelper.get_torrent_episodes(
["A.Will.Eternal.S04E05.2026.2160p.WEB-DL.mkv"],
custom_words=custom_words,
)
assert episodes == [170]
def test_custom_words_episode_offset_supports_multiplication_expression():
"""测试集数偏移表达式支持乘法和连续运算。"""
custom_words = [