mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-06-05 23:49:54 +08:00
fix: align media recognition fallback and shared reporting
Route title and path lookups through the fallback-aware entrypoints so auxiliary matches can reuse pre-assist keywords without forcing image fetches in lightweight flows. Also reduce noisy agent shutdown logging during cleanup.
This commit is contained in:
@@ -13,6 +13,8 @@ sys.modules.setdefault("psutil", ModuleType("psutil"))
|
||||
from app.chain import ChainBase
|
||||
from app.core.context import MediaInfo
|
||||
from app.core.meta import MetaBase
|
||||
from app.core.metainfo import MetaInfo
|
||||
from app.chain.media import MediaChain
|
||||
from app.helper.recognize import MediaRecognizeShareHelper
|
||||
from app.schemas.types import MediaType
|
||||
|
||||
@@ -21,6 +23,7 @@ class TestMediaRecognizeShare(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.chain = ChainBase()
|
||||
cls.media_chain = MediaChain()
|
||||
|
||||
@staticmethod
|
||||
def _build_meta(name: str, media_type: MediaType = MediaType.UNKNOWN) -> MetaBase:
|
||||
@@ -204,6 +207,114 @@ class TestMediaRecognizeShare(unittest.TestCase):
|
||||
self.assertEqual(query_params["keyword"], "未应用识别词的名称")
|
||||
self.assertEqual(report_payload["keyword"], "未应用识别词的名称")
|
||||
|
||||
def test_query_and_report_can_use_distinct_keyword_meta(self):
|
||||
"""
|
||||
共享识别应允许用原始关键字上报,同时保留辅助识别后的年份/季信息。
|
||||
"""
|
||||
helper = MediaRecognizeShareHelper()
|
||||
meta = self._build_meta("辅助识别后的名称", MediaType.TV)
|
||||
meta.year = "2024"
|
||||
meta.begin_season = 2
|
||||
|
||||
keyword_meta = self._build_meta("辅助识别前的名称", MediaType.UNKNOWN)
|
||||
keyword_meta.original_name = "辅助识别前的名称"
|
||||
|
||||
mediainfo = MediaInfo(
|
||||
title="测试剧集",
|
||||
year="2024",
|
||||
tmdb_id=401,
|
||||
type=MediaType.TV,
|
||||
season=2,
|
||||
)
|
||||
|
||||
query_params = helper._build_query_params(
|
||||
meta=meta,
|
||||
mtype=None,
|
||||
keyword_meta=keyword_meta,
|
||||
)
|
||||
report_payload = helper._build_report_payload(
|
||||
meta=meta,
|
||||
mediainfo=mediainfo,
|
||||
keyword_meta=keyword_meta,
|
||||
)
|
||||
|
||||
self.assertEqual(query_params["keyword"], "辅助识别前的名称")
|
||||
self.assertEqual(query_params["year"], "2024")
|
||||
self.assertEqual(query_params["season"], 2)
|
||||
self.assertEqual(report_payload["keyword"], "辅助识别前的名称")
|
||||
self.assertEqual(report_payload["year"], "2024")
|
||||
self.assertEqual(report_payload["season"], 2)
|
||||
|
||||
def test_report_shared_result_with_distinct_keyword_meta(self):
|
||||
"""
|
||||
辅助识别成功后应按辅助前名称上报共享结果。
|
||||
"""
|
||||
meta = self._build_meta("辅助识别后的名称", MediaType.TV)
|
||||
meta.year = "2024"
|
||||
meta.begin_season = 1
|
||||
share_meta = self._build_meta("辅助识别前的名称", MediaType.UNKNOWN)
|
||||
share_meta.original_name = "辅助识别前的名称"
|
||||
mediainfo = MediaInfo(title="测试剧集", year="2024", tmdb_id=402, type=MediaType.TV)
|
||||
|
||||
with patch.object(self.chain, "run_module", return_value=mediainfo), patch(
|
||||
"app.chain.MediaRecognizeShareHelper.report",
|
||||
return_value=True,
|
||||
) as report_mock:
|
||||
result = self.chain.recognize_media(meta=meta, share_meta=share_meta, cache=False)
|
||||
|
||||
self.assertIs(result, mediainfo)
|
||||
report_mock.assert_called_once_with(
|
||||
meta=meta,
|
||||
mediainfo=mediainfo,
|
||||
keyword_meta=share_meta,
|
||||
)
|
||||
|
||||
def test_query_shared_result_with_distinct_keyword_meta(self):
|
||||
"""
|
||||
本地识别失败后应按辅助前名称回查共享结果。
|
||||
"""
|
||||
meta = self._build_meta("辅助识别后的名称", MediaType.TV)
|
||||
meta.year = "2024"
|
||||
share_meta = self._build_meta("辅助识别前的名称", MediaType.UNKNOWN)
|
||||
share_meta.original_name = "辅助识别前的名称"
|
||||
shared_media = MediaInfo(title="测试剧集", year="2024", tmdb_id=403, type=MediaType.TV)
|
||||
|
||||
with patch.object(
|
||||
self.chain,
|
||||
"run_module",
|
||||
side_effect=[None, shared_media],
|
||||
), patch(
|
||||
"app.chain.MediaRecognizeShareHelper.query",
|
||||
return_value={"type": "tv", "tmdbid": 403, "season": 1},
|
||||
) as query_mock, patch(
|
||||
"app.chain.MediaRecognizeShareHelper.to_recognize_params",
|
||||
return_value={
|
||||
"mtype": MediaType.TV,
|
||||
"tmdbid": 403,
|
||||
"doubanid": None,
|
||||
"bangumiid": None,
|
||||
"season": 1,
|
||||
},
|
||||
), patch(
|
||||
"app.chain.MediaRecognizeShareHelper.report",
|
||||
return_value=False,
|
||||
), patch.object(
|
||||
self.chain,
|
||||
"_update_local_recognize_cache",
|
||||
):
|
||||
result = self.chain.recognize_media(
|
||||
meta=meta,
|
||||
share_meta=share_meta,
|
||||
cache=False,
|
||||
)
|
||||
|
||||
self.assertIs(result, shared_media)
|
||||
query_mock.assert_called_once_with(
|
||||
meta=meta,
|
||||
mtype=None,
|
||||
keyword_meta=share_meta,
|
||||
)
|
||||
|
||||
def test_skip_report_when_local_recognize_hits_cache(self):
|
||||
"""
|
||||
本地识别命中缓存时不应上报共享识别
|
||||
@@ -255,6 +366,80 @@ class TestMediaRecognizeShare(unittest.TestCase):
|
||||
report_mock.assert_not_awaited()
|
||||
query_mock.assert_not_awaited()
|
||||
|
||||
def test_recognize_by_meta_can_skip_obtain_images(self):
|
||||
"""
|
||||
标题识别可显式关闭图片拉取。
|
||||
"""
|
||||
meta = MetaInfo("测试电影")
|
||||
mediainfo = MediaInfo(title="测试电影", year="2024", tmdb_id=404, type=MediaType.MOVIE)
|
||||
|
||||
with patch.object(
|
||||
self.media_chain,
|
||||
"recognize_media",
|
||||
return_value=mediainfo,
|
||||
) as recognize_mock, patch.object(
|
||||
self.media_chain,
|
||||
"obtain_images",
|
||||
) as obtain_images_mock:
|
||||
result = self.media_chain.recognize_by_meta(meta, obtain_images=False)
|
||||
|
||||
self.assertIs(result, mediainfo)
|
||||
recognize_mock.assert_called_once()
|
||||
obtain_images_mock.assert_not_called()
|
||||
|
||||
def test_recognize_by_meta_reports_with_original_keyword_after_plugin_help(self):
|
||||
"""
|
||||
辅助识别后应继续使用辅助前关键字进行共享上报。
|
||||
"""
|
||||
meta = MetaInfo("辅助前名称")
|
||||
plugin_media = MediaInfo(title="辅助后名称", year="2024", tmdb_id=405, type=MediaType.TV)
|
||||
|
||||
with patch.object(
|
||||
self.media_chain,
|
||||
"select_recognize_source",
|
||||
side_effect=lambda **kwargs: kwargs["plugin_fn"](),
|
||||
), patch.object(
|
||||
self.media_chain,
|
||||
"recognize_help",
|
||||
return_value=plugin_media,
|
||||
) as recognize_help_mock, patch.object(
|
||||
self.media_chain,
|
||||
"obtain_images",
|
||||
):
|
||||
result = self.media_chain.recognize_by_meta(meta, obtain_images=False)
|
||||
|
||||
self.assertIs(result, plugin_media)
|
||||
self.assertEqual(recognize_help_mock.call_args.kwargs["share_meta"].name, "辅助前名称")
|
||||
|
||||
def test_async_recognize_by_meta_can_skip_obtain_images(self):
|
||||
"""
|
||||
异步标题识别可显式关闭图片拉取。
|
||||
"""
|
||||
meta = MetaInfo("测试异步电影")
|
||||
mediainfo = MediaInfo(title="测试异步电影", year="2025", tmdb_id=406, type=MediaType.MOVIE)
|
||||
|
||||
async def runner():
|
||||
with patch.object(
|
||||
self.media_chain,
|
||||
"async_recognize_media",
|
||||
AsyncMock(return_value=mediainfo),
|
||||
) as recognize_mock, patch.object(
|
||||
self.media_chain,
|
||||
"async_obtain_images",
|
||||
AsyncMock(),
|
||||
) as obtain_images_mock:
|
||||
result = await self.media_chain.async_recognize_by_meta(
|
||||
meta,
|
||||
obtain_images=False,
|
||||
)
|
||||
return result, recognize_mock, obtain_images_mock
|
||||
|
||||
result, recognize_mock, obtain_images_mock = asyncio.run(runner())
|
||||
|
||||
self.assertIs(result, mediainfo)
|
||||
recognize_mock.assert_awaited_once()
|
||||
obtain_images_mock.assert_not_awaited()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user