fix(subscribe): 修复 RSS 媒体 ID 误识别跳过 (#6266)

This commit is contained in:
Yang Feng
2026-08-10 17:55:46 +08:00
committed by GitHub
parent 5acd8ab514
commit 16840c6767
2 changed files with 273 additions and 7 deletions

View File

@@ -0,0 +1,184 @@
from types import SimpleNamespace
from app.chain.subscribe import SubscribeChain
from app.core.context import Context, MediaInfo, TorrentInfo
from app.schemas.types import MediaType
def _target_media(tmdb_id=106449, douban_id=None) -> MediaInfo:
"""构造订阅目标媒体。"""
return MediaInfo(
title="凡人修仙传",
original_title="凡人修仙传",
names=["A Record Of A Mortals Journey To Immortality"],
type=MediaType.TV,
year="2020",
season_years={1: "2020"},
tmdb_id=tmdb_id,
douban_id=douban_id,
)
def _candidate_media(tmdb_id=285479, douban_id=None) -> MediaInfo:
"""构造由 RSS 标题推断出的候选媒体。"""
return MediaInfo(
title="凡人修仙传",
type=MediaType.TV,
year="2020",
tmdb_id=tmdb_id,
douban_id=douban_id,
)
def _torrent_meta(*, en_name="A Record Of A Mortals Journey To Immortality", tmdbid=None):
"""构造不触发外部识别的标题解析结果。"""
return SimpleNamespace(
tmdbid=tmdbid,
doubanid=None,
bangumiid=None,
anilistid=None,
media_source="themoviedb" if tmdbid else None,
media_id=str(tmdbid) if tmdbid else None,
cn_name="",
en_name=en_name,
type=MediaType.TV,
year=None,
org_string=f"{en_name} S01E186 2160p WEB-DL",
)
def _context(meta, candidate, torrent) -> Context:
"""构造 RSS 候选上下文。"""
return Context(
meta_info=meta,
media_info=candidate,
torrent_info=torrent,
resource_source="rss",
match_source="tmdbid",
candidate_recognized=True,
media_info_is_target=False,
)
def _reconcile(target, candidate, meta, torrent, context):
"""调用订阅链的候选媒体冲突复核。"""
return SubscribeChain._SubscribeChain__reconcile_candidate_media(
target_mediainfo=target,
candidate_mediainfo=candidate,
torrent_meta=meta,
torrent_info=torrent,
context=context,
)
def test_inferred_tmdb_conflict_falls_back_to_strict_alias_match():
"""标题推断到重复 TMDB 条目时应允许订阅目标别名复核。"""
target = _target_media()
candidate = _candidate_media()
meta = _torrent_meta()
torrent = TorrentInfo(
title="A Record Of A Mortals Journey To Immortality S01E186 2160p WEB-DL",
site_name="测试站点",
category=MediaType.TV.value,
)
context = _context(meta, candidate, torrent)
result = _reconcile(target, candidate, meta, torrent, context)
assert result is target
assert context.media_info is target
assert context.match_source == "title"
assert context.candidate_recognized is False
assert context.media_info_is_target is True
def test_inferred_tmdb_conflict_rejects_nonmatching_title():
"""ID 冲突且标题和别名不匹配时应继续拒绝候选。"""
target = _target_media()
candidate = _candidate_media()
meta = _torrent_meta(en_name="Different Series")
torrent = TorrentInfo(
title="Different Series S01E186 2160p WEB-DL",
site_name="测试站点",
category=MediaType.TV.value,
)
context = _context(meta, candidate, torrent)
assert _reconcile(target, candidate, meta, torrent, context) is None
assert context.media_info is candidate
assert context.match_source == "tmdbid"
assert context.candidate_recognized is True
assert context.media_info_is_target is False
def test_inferred_douban_conflict_falls_back_to_strict_alias_match():
"""豆瓣 ID 推断冲突时应使用同一套严格标题复核。"""
target = _target_media(tmdb_id=None, douban_id="30170816")
candidate = _candidate_media(tmdb_id=None, douban_id="36612345")
meta = _torrent_meta()
torrent = TorrentInfo(
title="A Record Of A Mortals Journey To Immortality S01E186 2160p WEB-DL",
site_name="测试站点",
category=MediaType.TV.value,
)
context = _context(meta, candidate, torrent)
result = _reconcile(target, candidate, meta, torrent, context)
assert result is target
assert context.media_info is target
assert context.match_source == "title"
def test_explicit_tmdb_identity_keeps_strict_conflict_rejection():
"""标题显式携带媒体 ID 时不得被标题别名覆盖。"""
target = _target_media()
candidate = _candidate_media()
meta = _torrent_meta(tmdbid=285479)
torrent = TorrentInfo(
title="A Record Of A Mortals Journey To Immortality S01E186 {tmdbid=285479}",
site_name="测试站点",
category=MediaType.TV.value,
)
context = _context(meta, candidate, torrent)
assert _reconcile(target, candidate, meta, torrent, context) is None
assert context.media_info is candidate
assert context.match_source == "tmdbid"
def test_conflict_rejects_target_without_same_source_identity():
"""订阅目标缺少候选同来源 ID 时不得用标题跨来源放行。"""
target = _target_media(tmdb_id=None)
candidate = _candidate_media()
meta = _torrent_meta()
torrent = TorrentInfo(
title="A Record Of A Mortals Journey To Immortality S01E186",
site_name="测试站点",
category=MediaType.TV.value,
)
context = _context(meta, candidate, torrent)
assert _reconcile(target, candidate, meta, torrent, context) is None
assert context.media_info is candidate
def test_matching_media_id_preserves_candidate_identity():
"""媒体 ID 原本一致时应保持候选识别上下文。"""
target = _target_media()
candidate = _candidate_media(tmdb_id=106449)
meta = _torrent_meta()
torrent = TorrentInfo(
title="A Record Of A Mortals Journey To Immortality S01E186",
site_name="测试站点",
category=MediaType.TV.value,
)
context = _context(meta, candidate, torrent)
result = _reconcile(target, candidate, meta, torrent, context)
assert result is candidate
assert context.media_info is candidate
assert context.match_source == "tmdbid"
assert context.candidate_recognized is True
assert context.media_info_is_target is False