mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 23:47:41 +08:00
refactor: use injected eventmanager in chain instance methods
This commit is contained in:
@@ -961,7 +961,7 @@ class DownloadChain(ChainBase):
|
|||||||
downloader=downloader,
|
downloader=downloader,
|
||||||
origin=source,
|
origin=source,
|
||||||
)
|
)
|
||||||
event = eventmanager.send_event(ChainEventType.ResourceSelection, event_data)
|
event = self.eventmanager.send_event(ChainEventType.ResourceSelection, event_data)
|
||||||
if event and event.event_data:
|
if event and event.event_data:
|
||||||
event_data = event.event_data
|
event_data = event.event_data
|
||||||
if event_data.updated and event_data.updated_contexts is not None:
|
if event_data.updated and event_data.updated_contexts is not None:
|
||||||
|
|||||||
+13
-11
@@ -19,7 +19,7 @@ from app.domain.context import (
|
|||||||
MusicArtistInfo,
|
MusicArtistInfo,
|
||||||
MusicInfo,
|
MusicInfo,
|
||||||
)
|
)
|
||||||
from app.runtime.events import eventmanager, Event
|
from app.runtime.events import Event
|
||||||
from app.domain.meta.metabase import MetaBase
|
from app.domain.meta.metabase import MetaBase
|
||||||
from app.domain.meta.metamusic import MetaMusic
|
from app.domain.meta.metamusic import MetaMusic
|
||||||
from app.domain.metainfo import MetaInfo, MetaInfoPath
|
from app.domain.metainfo import MetaInfo, MetaInfoPath
|
||||||
@@ -450,8 +450,8 @@ class MediaChain(ChainBase, metaclass=Singleton):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def select_recognize_source(
|
def select_recognize_source(
|
||||||
|
self,
|
||||||
log_name: str, log_context: str, native_fn, plugin_fn,
|
log_name: str, log_context: str, native_fn, plugin_fn,
|
||||||
is_recognized=None,
|
is_recognized=None,
|
||||||
plugin_event: ChainEventType = ChainEventType.NameRecognize,
|
plugin_event: ChainEventType = ChainEventType.NameRecognize,
|
||||||
@@ -470,7 +470,8 @@ class MediaChain(ChainBase, metaclass=Singleton):
|
|||||||
if is_recognized is None:
|
if is_recognized is None:
|
||||||
is_recognized = lambda result: bool(result)
|
is_recognized = lambda result: bool(result)
|
||||||
mediainfo = None
|
mediainfo = None
|
||||||
plugin_available = eventmanager.check(plugin_event)
|
# 插件可用性检查走注入的事件管理器,避免链实例直连全局单例
|
||||||
|
plugin_available = self.eventmanager.check(plugin_event)
|
||||||
if get_chain_runtime_config_snapshot().recognize_plugin_first and plugin_available:
|
if get_chain_runtime_config_snapshot().recognize_plugin_first and plugin_available:
|
||||||
# 插件优先
|
# 插件优先
|
||||||
logger.info(f"插件识别优先模式已开启。请求辅助识别,标题:{log_name} ...")
|
logger.info(f"插件识别优先模式已开启。请求辅助识别,标题:{log_name} ...")
|
||||||
@@ -758,7 +759,7 @@ class MediaChain(ChainBase, metaclass=Singleton):
|
|||||||
music_type=music_type,
|
music_type=music_type,
|
||||||
)
|
)
|
||||||
# 发送请求事件,等待结果
|
# 发送请求事件,等待结果
|
||||||
result: Event = eventmanager.send_event(
|
result: Event = self.eventmanager.send_event(
|
||||||
ChainEventType.NameRecognize,
|
ChainEventType.NameRecognize,
|
||||||
{
|
{
|
||||||
"title": title,
|
"title": title,
|
||||||
@@ -820,7 +821,7 @@ class MediaChain(ChainBase, metaclass=Singleton):
|
|||||||
:param music_type: 音乐实体类型
|
:param music_type: 音乐实体类型
|
||||||
"""
|
"""
|
||||||
# 发送音乐名称识别事件,等待插件返回标题要素
|
# 发送音乐名称识别事件,等待插件返回标题要素
|
||||||
result: Event = eventmanager.send_event(
|
result: Event = self.eventmanager.send_event(
|
||||||
ChainEventType.MusicNameRecognize,
|
ChainEventType.MusicNameRecognize,
|
||||||
{
|
{
|
||||||
"title": title,
|
"title": title,
|
||||||
@@ -1507,14 +1508,14 @@ class MediaChain(ChainBase, metaclass=Singleton):
|
|||||||
media_id=media_id,
|
media_id=media_id,
|
||||||
target_media_source=target_source,
|
target_media_source=target_source,
|
||||||
)
|
)
|
||||||
event = eventmanager.send_event(
|
event = self.eventmanager.send_event(
|
||||||
ChainEventType.MediaRecognizeConvert, event_data,
|
ChainEventType.MediaRecognizeConvert, event_data,
|
||||||
)
|
)
|
||||||
return event_data.media_dict if event and event_data.media_dict else None
|
return event_data.media_dict if event and event_data.media_dict else None
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def async_select_recognize_source(
|
async def async_select_recognize_source(
|
||||||
|
self,
|
||||||
log_name: str, log_context: str, native_fn, plugin_fn,
|
log_name: str, log_context: str, native_fn, plugin_fn,
|
||||||
is_recognized=None,
|
is_recognized=None,
|
||||||
plugin_event: ChainEventType = ChainEventType.NameRecognize,
|
plugin_event: ChainEventType = ChainEventType.NameRecognize,
|
||||||
@@ -1532,7 +1533,8 @@ class MediaChain(ChainBase, metaclass=Singleton):
|
|||||||
if is_recognized is None:
|
if is_recognized is None:
|
||||||
is_recognized = lambda result: bool(result)
|
is_recognized = lambda result: bool(result)
|
||||||
mediainfo = None
|
mediainfo = None
|
||||||
plugin_available = eventmanager.check(plugin_event)
|
# 插件可用性检查走注入的事件管理器,避免链实例直连全局单例
|
||||||
|
plugin_available = self.eventmanager.check(plugin_event)
|
||||||
if get_chain_runtime_config_snapshot().recognize_plugin_first and plugin_available:
|
if get_chain_runtime_config_snapshot().recognize_plugin_first and plugin_available:
|
||||||
# 插件优先
|
# 插件优先
|
||||||
logger.info(f"插件优先模式已开启。请求辅助识别,标题:{log_name} ...")
|
logger.info(f"插件优先模式已开启。请求辅助识别,标题:{log_name} ...")
|
||||||
@@ -1696,7 +1698,7 @@ class MediaChain(ChainBase, metaclass=Singleton):
|
|||||||
music_type=music_type,
|
music_type=music_type,
|
||||||
)
|
)
|
||||||
# 发送请求事件,等待结果
|
# 发送请求事件,等待结果
|
||||||
result: Event = await eventmanager.async_send_event(
|
result: Event = await self.eventmanager.async_send_event(
|
||||||
ChainEventType.NameRecognize,
|
ChainEventType.NameRecognize,
|
||||||
{
|
{
|
||||||
"title": title,
|
"title": title,
|
||||||
@@ -1758,7 +1760,7 @@ class MediaChain(ChainBase, metaclass=Singleton):
|
|||||||
:param music_type: 音乐实体类型
|
:param music_type: 音乐实体类型
|
||||||
"""
|
"""
|
||||||
# 发送音乐名称识别事件,等待插件返回标题要素
|
# 发送音乐名称识别事件,等待插件返回标题要素
|
||||||
result: Event = await eventmanager.async_send_event(
|
result: Event = await self.eventmanager.async_send_event(
|
||||||
ChainEventType.MusicNameRecognize,
|
ChainEventType.MusicNameRecognize,
|
||||||
{
|
{
|
||||||
"title": title,
|
"title": title,
|
||||||
@@ -2053,7 +2055,7 @@ class MediaChain(ChainBase, metaclass=Singleton):
|
|||||||
media_id=media_id,
|
media_id=media_id,
|
||||||
target_media_source=target_source,
|
target_media_source=target_source,
|
||||||
)
|
)
|
||||||
event = await eventmanager.async_send_event(
|
event = await self.eventmanager.async_send_event(
|
||||||
ChainEventType.MediaRecognizeConvert, event_data,
|
ChainEventType.MediaRecognizeConvert, event_data,
|
||||||
)
|
)
|
||||||
return event_data.media_dict if event and event_data.media_dict else None
|
return event_data.media_dict if event and event_data.media_dict else None
|
||||||
|
|||||||
+3
-3
@@ -74,7 +74,7 @@ class SiteChain(InteractionChainMixin, ChainBase):
|
|||||||
payload=userdata.model_dump(),
|
payload=userdata.model_dump(),
|
||||||
)
|
)
|
||||||
# 发送事件
|
# 发送事件
|
||||||
eventmanager.send_event(EventType.SiteRefreshed, {
|
self.eventmanager.send_event(EventType.SiteRefreshed, {
|
||||||
"site_id": site.get("id")
|
"site_id": site.get("id")
|
||||||
})
|
})
|
||||||
self._post_site_messages(site=site, userdata=userdata)
|
self._post_site_messages(site=site, userdata=userdata)
|
||||||
@@ -163,7 +163,7 @@ class SiteChain(InteractionChainMixin, ChainBase):
|
|||||||
data={"total": total_num, "finished": index},
|
data={"total": total_num, "finished": index},
|
||||||
)
|
)
|
||||||
if any_site_updated:
|
if any_site_updated:
|
||||||
eventmanager.send_event(EventType.SiteRefreshed, {
|
self.eventmanager.send_event(EventType.SiteRefreshed, {
|
||||||
"site_id": "*"
|
"site_id": "*"
|
||||||
})
|
})
|
||||||
if progress_callback:
|
if progress_callback:
|
||||||
@@ -461,7 +461,7 @@ class SiteChain(InteractionChainMixin, ChainBase):
|
|||||||
|
|
||||||
# 通知站点更新
|
# 通知站点更新
|
||||||
if indexer:
|
if indexer:
|
||||||
eventmanager.send_event(EventType.SiteUpdated, {
|
self.eventmanager.send_event(EventType.SiteUpdated, {
|
||||||
"domain": domain,
|
"domain": domain,
|
||||||
})
|
})
|
||||||
if progress_callback:
|
if progress_callback:
|
||||||
|
|||||||
@@ -934,7 +934,7 @@ class SubscribeChain(MusicSubscribeMixin, InteractionChainMixin, ChainBase):
|
|||||||
"""同步执行提交后消息、事件和统计,异常不再触碰数据库事务。"""
|
"""同步执行提交后消息、事件和统计,异常不再触碰数据库事务。"""
|
||||||
if context.notification:
|
if context.notification:
|
||||||
self.post_message(_SchemaMessage.model_validate(context.notification))
|
self.post_message(_SchemaMessage.model_validate(context.notification))
|
||||||
eventmanager.send_event(EventType.SubscribeAdded, {
|
self.eventmanager.send_event(EventType.SubscribeAdded, {
|
||||||
"subscribe_id": subscribe_id,
|
"subscribe_id": subscribe_id,
|
||||||
"idempotency_key": (
|
"idempotency_key": (
|
||||||
f"subscribe.added:{subscribe_id}:"
|
f"subscribe.added:{subscribe_id}:"
|
||||||
@@ -958,7 +958,7 @@ class SubscribeChain(MusicSubscribeMixin, InteractionChainMixin, ChainBase):
|
|||||||
await self.async_post_message(
|
await self.async_post_message(
|
||||||
_SchemaMessage.model_validate(context.notification)
|
_SchemaMessage.model_validate(context.notification)
|
||||||
)
|
)
|
||||||
await eventmanager.async_send_event(EventType.SubscribeAdded, {
|
await self.eventmanager.async_send_event(EventType.SubscribeAdded, {
|
||||||
"subscribe_id": subscribe_id,
|
"subscribe_id": subscribe_id,
|
||||||
"idempotency_key": (
|
"idempotency_key": (
|
||||||
f"subscribe.added:{subscribe_id}:"
|
f"subscribe.added:{subscribe_id}:"
|
||||||
@@ -3112,7 +3112,7 @@ class SubscribeChain(MusicSubscribeMixin, InteractionChainMixin, ChainBase):
|
|||||||
if subscribe.state == "P":
|
if subscribe.state == "P":
|
||||||
return
|
return
|
||||||
# 发送订阅完成判定事件,在写入 DB 前,允许外部据完结策略否决本次自动完成
|
# 发送订阅完成判定事件,在写入 DB 前,允许外部据完结策略否决本次自动完成
|
||||||
completion_event = eventmanager.send_event(
|
completion_event = self.eventmanager.send_event(
|
||||||
ChainEventType.SubscribeCompletionCheck,
|
ChainEventType.SubscribeCompletionCheck,
|
||||||
SubscribeCompletionCheckEventData(subscribe=subscribe, mediainfo=mediainfo, meta=meta))
|
SubscribeCompletionCheckEventData(subscribe=subscribe, mediainfo=mediainfo, meta=meta))
|
||||||
if completion_event and completion_event.event_data:
|
if completion_event and completion_event.event_data:
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ from app.chain.storage import StorageChain
|
|||||||
from app.chain.tmdb import TmdbChain
|
from app.chain.tmdb import TmdbChain
|
||||||
from app.runtime.config import global_vars
|
from app.runtime.config import global_vars
|
||||||
from app.domain.context import MediaInfo, MusicInfo, TorrentInfo
|
from app.domain.context import MediaInfo, MusicInfo, TorrentInfo
|
||||||
from app.runtime.events import eventmanager
|
|
||||||
from app.domain.meta.metabase import MetaBase
|
from app.domain.meta.metabase import MetaBase
|
||||||
from app.domain.meta.metamusic import MetaMusic
|
from app.domain.meta.metamusic import MetaMusic
|
||||||
from app.domain.metainfo import MetaInfoPath
|
from app.domain.metainfo import MetaInfoPath
|
||||||
@@ -1487,7 +1486,7 @@ class TransferChain(FileFilterMixin, ScrapeBatchMixin, EpisodeFormatMixin, Histo
|
|||||||
source_event_data = StorageOperSelectionEventData(
|
source_event_data = StorageOperSelectionEventData(
|
||||||
storage=task.fileitem.storage,
|
storage=task.fileitem.storage,
|
||||||
)
|
)
|
||||||
source_event = eventmanager.send_event(
|
source_event = self.eventmanager.send_event(
|
||||||
ChainEventType.StorageOperSelection, source_event_data
|
ChainEventType.StorageOperSelection, source_event_data
|
||||||
)
|
)
|
||||||
# 使用事件返回的上下文数据
|
# 使用事件返回的上下文数据
|
||||||
@@ -1503,7 +1502,7 @@ class TransferChain(FileFilterMixin, ScrapeBatchMixin, EpisodeFormatMixin, Histo
|
|||||||
target_event_data = StorageOperSelectionEventData(
|
target_event_data = StorageOperSelectionEventData(
|
||||||
storage=task.target_storage,
|
storage=task.target_storage,
|
||||||
)
|
)
|
||||||
target_event = eventmanager.send_event(
|
target_event = self.eventmanager.send_event(
|
||||||
ChainEventType.StorageOperSelection, target_event_data
|
ChainEventType.StorageOperSelection, target_event_data
|
||||||
)
|
)
|
||||||
# 使用事件返回的上下文数据
|
# 使用事件返回的上下文数据
|
||||||
|
|||||||
@@ -108,7 +108,8 @@ def test_media_identity_conversion_rejects_invalid_pair_without_plugin_handler()
|
|||||||
media_source=MediaSource.Bangumi,
|
media_source=MediaSource.Bangumi,
|
||||||
media_id="0",
|
media_id="0",
|
||||||
) is None
|
) is None
|
||||||
with patch("app.chain.media.eventmanager.send_event", return_value=None):
|
# 无插件处理器:注入返回空的 eventmanager 桩
|
||||||
|
chain.eventmanager = Mock(send_event=Mock(return_value=None))
|
||||||
assert MediaChain.convert_media_identity(
|
assert MediaChain.convert_media_identity(
|
||||||
chain,
|
chain,
|
||||||
target_source=MediaSource.TheAudioDB,
|
target_source=MediaSource.TheAudioDB,
|
||||||
@@ -129,7 +130,8 @@ def test_media_identity_conversion_dispatches_plugin_source() -> None:
|
|||||||
event_data.media_dict.update(result)
|
event_data.media_dict.update(result)
|
||||||
return Mock(event_data=event_data)
|
return Mock(event_data=event_data)
|
||||||
|
|
||||||
with patch("app.chain.media.eventmanager.send_event", side_effect=handle_event):
|
# 事件经注入的 eventmanager 发送,测试桩直接提供实例依赖
|
||||||
|
chain.eventmanager = Mock(send_event=Mock(side_effect=handle_event))
|
||||||
converted = MediaChain.convert_media_identity(
|
converted = MediaChain.convert_media_identity(
|
||||||
chain,
|
chain,
|
||||||
target_source=MediaSource.TMDB,
|
target_source=MediaSource.TMDB,
|
||||||
@@ -211,10 +213,8 @@ def test_async_media_identity_conversion_dispatches_plugin_source() -> None:
|
|||||||
event_data.media_dict.update(result)
|
event_data.media_dict.update(result)
|
||||||
return Mock(event_data=event_data)
|
return Mock(event_data=event_data)
|
||||||
|
|
||||||
with patch(
|
# 事件经注入的 eventmanager 发送,测试桩直接提供实例依赖
|
||||||
"app.chain.media.eventmanager.async_send_event",
|
chain.eventmanager = Mock(async_send_event=AsyncMock(side_effect=handle_event))
|
||||||
new=AsyncMock(side_effect=handle_event),
|
|
||||||
):
|
|
||||||
converted = asyncio.run(MediaChain.async_convert_media_identity(
|
converted = asyncio.run(MediaChain.async_convert_media_identity(
|
||||||
chain,
|
chain,
|
||||||
target_source=MediaSource.Douban,
|
target_source=MediaSource.Douban,
|
||||||
|
|||||||
@@ -558,6 +558,8 @@ def test_batch_download_rejects_complete_coverage_when_files_do_not_cover_target
|
|||||||
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
||||||
|
|
||||||
chain = DownloadChain.__new__(DownloadChain)
|
chain = DownloadChain.__new__(DownloadChain)
|
||||||
|
chain.eventmanager = MagicMock()
|
||||||
|
chain.eventmanager.send_event.return_value = None
|
||||||
chain.download_torrent = MagicMock(return_value=(b"torrent-content", "", ["demo.mkv"]))
|
chain.download_torrent = MagicMock(return_value=(b"torrent-content", "", ["demo.mkv"]))
|
||||||
chain.download_single = MagicMock(return_value="hash")
|
chain.download_single = MagicMock(return_value="hash")
|
||||||
|
|
||||||
@@ -588,6 +590,8 @@ def test_batch_download_preserves_special_season_zero(monkeypatch):
|
|||||||
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
||||||
|
|
||||||
chain = DownloadChain.__new__(DownloadChain)
|
chain = DownloadChain.__new__(DownloadChain)
|
||||||
|
chain.eventmanager = MagicMock()
|
||||||
|
chain.eventmanager.send_event.return_value = None
|
||||||
chain.download_torrent = MagicMock(return_value=(b"torrent-content", "", ["demo.mkv"]))
|
chain.download_torrent = MagicMock(return_value=(b"torrent-content", "", ["demo.mkv"]))
|
||||||
chain.download_single = MagicMock(return_value="hash")
|
chain.download_single = MagicMock(return_value="hash")
|
||||||
|
|
||||||
@@ -623,6 +627,8 @@ def test_batch_download_rejects_complete_coverage_when_only_missing_episodes_mat
|
|||||||
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
||||||
|
|
||||||
chain = DownloadChain.__new__(DownloadChain)
|
chain = DownloadChain.__new__(DownloadChain)
|
||||||
|
chain.eventmanager = MagicMock()
|
||||||
|
chain.eventmanager.send_event.return_value = None
|
||||||
chain.download_torrent = MagicMock(return_value=(b"torrent-content", "", ["demo.mkv"]))
|
chain.download_torrent = MagicMock(return_value=(b"torrent-content", "", ["demo.mkv"]))
|
||||||
chain.download_single = MagicMock(return_value="hash")
|
chain.download_single = MagicMock(return_value="hash")
|
||||||
|
|
||||||
@@ -655,6 +661,8 @@ def test_batch_download_tries_next_episode_candidate_when_first_download_fails(m
|
|||||||
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
||||||
|
|
||||||
chain = DownloadChain.__new__(DownloadChain)
|
chain = DownloadChain.__new__(DownloadChain)
|
||||||
|
chain.eventmanager = MagicMock()
|
||||||
|
chain.eventmanager.send_event.return_value = None
|
||||||
chain.download_single = MagicMock(side_effect=[None, "hash"])
|
chain.download_single = MagicMock(side_effect=[None, "hash"])
|
||||||
|
|
||||||
first_context = _build_tv_context(episode_list=[1])
|
first_context = _build_tv_context(episode_list=[1])
|
||||||
@@ -692,6 +700,8 @@ def test_batch_download_does_not_download_duplicate_movie_after_success(monkeypa
|
|||||||
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
||||||
|
|
||||||
chain = DownloadChain.__new__(DownloadChain)
|
chain = DownloadChain.__new__(DownloadChain)
|
||||||
|
chain.eventmanager = MagicMock()
|
||||||
|
chain.eventmanager.send_event.return_value = None
|
||||||
chain.download_single = MagicMock(return_value="hash")
|
chain.download_single = MagicMock(return_value="hash")
|
||||||
|
|
||||||
first_context = SimpleNamespace(
|
first_context = SimpleNamespace(
|
||||||
@@ -720,6 +730,8 @@ def test_batch_download_threads_custom_words_to_download_single(monkeypatch):
|
|||||||
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
||||||
|
|
||||||
chain = DownloadChain.__new__(DownloadChain)
|
chain = DownloadChain.__new__(DownloadChain)
|
||||||
|
chain.eventmanager = MagicMock()
|
||||||
|
chain.eventmanager.send_event.return_value = None
|
||||||
chain.download_single = MagicMock(return_value="hash")
|
chain.download_single = MagicMock(return_value="hash")
|
||||||
|
|
||||||
context = SimpleNamespace(
|
context = SimpleNamespace(
|
||||||
@@ -744,6 +756,8 @@ def test_batch_download_applies_custom_words_to_torrent_file_episodes(monkeypatc
|
|||||||
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
||||||
|
|
||||||
chain = DownloadChain.__new__(DownloadChain)
|
chain = DownloadChain.__new__(DownloadChain)
|
||||||
|
chain.eventmanager = MagicMock()
|
||||||
|
chain.eventmanager.send_event.return_value = None
|
||||||
chain.download_torrent = MagicMock(
|
chain.download_torrent = MagicMock(
|
||||||
return_value=(b"torrent-content", "", ["A.Will.Eternal.S04E05.mkv"]),
|
return_value=(b"torrent-content", "", ["A.Will.Eternal.S04E05.mkv"]),
|
||||||
)
|
)
|
||||||
@@ -807,6 +821,8 @@ def test_download_single_records_failure_cooldown_when_downloader_rejects(monkey
|
|||||||
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
||||||
|
|
||||||
chain = DownloadChain.__new__(DownloadChain)
|
chain = DownloadChain.__new__(DownloadChain)
|
||||||
|
chain.eventmanager = MagicMock()
|
||||||
|
chain.eventmanager.send_event.return_value = None
|
||||||
error_msg = "添加种子任务失败:无法读取种子文件"
|
error_msg = "添加种子任务失败:无法读取种子文件"
|
||||||
chain.download = MagicMock(return_value=("qb", None, "Original", error_msg))
|
chain.download = MagicMock(return_value=("qb", None, "Original", error_msg))
|
||||||
chain.post_message = MagicMock()
|
chain.post_message = MagicMock()
|
||||||
@@ -943,6 +959,8 @@ def test_batch_download_skips_failed_subscription_resource_and_tries_next(monkey
|
|||||||
)
|
)
|
||||||
|
|
||||||
chain = DownloadChain.__new__(DownloadChain)
|
chain = DownloadChain.__new__(DownloadChain)
|
||||||
|
chain.eventmanager = MagicMock()
|
||||||
|
chain.eventmanager.send_event.return_value = None
|
||||||
chain.download_single = MagicMock(return_value="hash")
|
chain.download_single = MagicMock(return_value="hash")
|
||||||
|
|
||||||
downloads, lefts = chain.batch_download(
|
downloads, lefts = chain.batch_download(
|
||||||
@@ -965,6 +983,8 @@ def test_batch_download_accepts_complete_coverage_when_files_cover_target_range(
|
|||||||
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
||||||
|
|
||||||
chain = DownloadChain.__new__(DownloadChain)
|
chain = DownloadChain.__new__(DownloadChain)
|
||||||
|
chain.eventmanager = MagicMock()
|
||||||
|
chain.eventmanager.send_event.return_value = None
|
||||||
chain.download_torrent = MagicMock(return_value=(b"torrent-content", "", ["demo.mkv"]))
|
chain.download_torrent = MagicMock(return_value=(b"torrent-content", "", ["demo.mkv"]))
|
||||||
chain.download_single = MagicMock(return_value="hash")
|
chain.download_single = MagicMock(return_value="hash")
|
||||||
|
|
||||||
@@ -997,6 +1017,8 @@ def test_batch_download_rejects_complete_coverage_when_files_have_same_count_but
|
|||||||
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
||||||
|
|
||||||
chain = DownloadChain.__new__(DownloadChain)
|
chain = DownloadChain.__new__(DownloadChain)
|
||||||
|
chain.eventmanager = MagicMock()
|
||||||
|
chain.eventmanager.send_event.return_value = None
|
||||||
chain.download_torrent = MagicMock(return_value=(b"torrent-content", "", ["demo.mkv"]))
|
chain.download_torrent = MagicMock(return_value=(b"torrent-content", "", ["demo.mkv"]))
|
||||||
chain.download_single = MagicMock(return_value="hash")
|
chain.download_single = MagicMock(return_value="hash")
|
||||||
|
|
||||||
@@ -1029,6 +1051,8 @@ def test_batch_download_accepts_complete_coverage_when_title_episodes_cover_targ
|
|||||||
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
||||||
|
|
||||||
chain = DownloadChain.__new__(DownloadChain)
|
chain = DownloadChain.__new__(DownloadChain)
|
||||||
|
chain.eventmanager = MagicMock()
|
||||||
|
chain.eventmanager.send_event.return_value = None
|
||||||
chain.download_torrent = MagicMock()
|
chain.download_torrent = MagicMock()
|
||||||
chain.download_single = MagicMock(return_value="hash")
|
chain.download_single = MagicMock(return_value="hash")
|
||||||
|
|
||||||
@@ -1062,6 +1086,8 @@ def test_batch_download_rejects_complete_coverage_when_title_episodes_are_partia
|
|||||||
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
||||||
|
|
||||||
chain = DownloadChain.__new__(DownloadChain)
|
chain = DownloadChain.__new__(DownloadChain)
|
||||||
|
chain.eventmanager = MagicMock()
|
||||||
|
chain.eventmanager.send_event.return_value = None
|
||||||
chain.download_torrent = MagicMock()
|
chain.download_torrent = MagicMock()
|
||||||
chain.download_single = MagicMock(return_value="hash")
|
chain.download_single = MagicMock(return_value="hash")
|
||||||
|
|
||||||
@@ -1095,6 +1121,8 @@ def test_batch_download_complete_coverage_ignores_allowed_episode_narrowing(monk
|
|||||||
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
||||||
|
|
||||||
chain = DownloadChain.__new__(DownloadChain)
|
chain = DownloadChain.__new__(DownloadChain)
|
||||||
|
chain.eventmanager = MagicMock()
|
||||||
|
chain.eventmanager.send_event.return_value = None
|
||||||
chain.download_torrent = MagicMock()
|
chain.download_torrent = MagicMock()
|
||||||
chain.download_single = MagicMock(return_value="hash")
|
chain.download_single = MagicMock(return_value="hash")
|
||||||
|
|
||||||
@@ -1129,6 +1157,8 @@ def test_batch_download_keeps_count_check_without_complete_coverage(monkeypatch)
|
|||||||
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
monkeypatch.setattr(download_module.eventmanager, "send_event", lambda *args, **kwargs: None)
|
||||||
|
|
||||||
chain = DownloadChain.__new__(DownloadChain)
|
chain = DownloadChain.__new__(DownloadChain)
|
||||||
|
chain.eventmanager = MagicMock()
|
||||||
|
chain.eventmanager.send_event.return_value = None
|
||||||
chain.download_torrent = MagicMock(return_value=(b"torrent-content", "", ["demo.mkv"]))
|
chain.download_torrent = MagicMock(return_value=(b"torrent-content", "", ["demo.mkv"]))
|
||||||
chain.download_single = MagicMock(return_value="hash")
|
chain.download_single = MagicMock(return_value="hash")
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
与 ChainBase 媒体识别插件补充(MediaRecognize / MusicMediaRecognize 链式事件)。
|
与 ChainBase 媒体识别插件补充(MediaRecognize / MusicMediaRecognize 链式事件)。
|
||||||
"""
|
"""
|
||||||
import asyncio
|
import asyncio
|
||||||
from unittest.mock import AsyncMock, Mock, patch
|
from unittest.mock import AsyncMock, MagicMock, Mock, patch
|
||||||
|
|
||||||
from app.chain import ChainBase
|
from app.chain import ChainBase
|
||||||
from app.chain.media import MediaChain
|
from app.chain.media import MediaChain
|
||||||
@@ -66,9 +66,11 @@ def test_music_recognize_help_sends_event_and_rematches(monkeypatch):
|
|||||||
"album": "叶惠美",
|
"album": "叶惠美",
|
||||||
"year": "2003",
|
"year": "2003",
|
||||||
})
|
})
|
||||||
with patch("app.chain.media.eventmanager") as em:
|
# 事件经注入的 eventmanager 发送,直接替换实例依赖并保留断言能力
|
||||||
|
em = MagicMock()
|
||||||
em.check.return_value = True
|
em.check.return_value = True
|
||||||
em.send_event.return_value = event
|
em.send_event.return_value = event
|
||||||
|
monkeypatch.setattr(chain, "eventmanager", em)
|
||||||
result = chain.recognize_by_meta(meta, media_source="musicbrainz")
|
result = chain.recognize_by_meta(meta, media_source="musicbrainz")
|
||||||
|
|
||||||
assert result is remote
|
assert result is remote
|
||||||
@@ -101,8 +103,9 @@ def test_music_recognize_keeps_fallback_without_plugin(monkeypatch):
|
|||||||
fallback = _fallback_music(title="未知曲目")
|
fallback = _fallback_music(title="未知曲目")
|
||||||
monkeypatch.setattr(chain, "recognize_media", Mock(return_value=fallback))
|
monkeypatch.setattr(chain, "recognize_media", Mock(return_value=fallback))
|
||||||
|
|
||||||
with patch("app.chain.media.eventmanager") as em:
|
em = MagicMock()
|
||||||
em.check.return_value = False
|
em.check.return_value = False
|
||||||
|
monkeypatch.setattr(chain, "eventmanager", em)
|
||||||
result = chain.recognize_by_meta(meta)
|
result = chain.recognize_by_meta(meta)
|
||||||
|
|
||||||
assert result is fallback
|
assert result is fallback
|
||||||
@@ -122,9 +125,10 @@ def test_music_recognize_help_same_elements_keeps_fallback(monkeypatch):
|
|||||||
"name": "晴天",
|
"name": "晴天",
|
||||||
"artist": "周杰伦",
|
"artist": "周杰伦",
|
||||||
})
|
})
|
||||||
with patch("app.chain.media.eventmanager") as em:
|
em = MagicMock()
|
||||||
em.check.return_value = True
|
em.check.return_value = True
|
||||||
em.send_event.return_value = event
|
em.send_event.return_value = event
|
||||||
|
monkeypatch.setattr(chain, "eventmanager", em)
|
||||||
result = chain.recognize_by_meta(meta)
|
result = chain.recognize_by_meta(meta)
|
||||||
|
|
||||||
assert result is fallback
|
assert result is fallback
|
||||||
@@ -143,9 +147,10 @@ def test_music_recognize_help_keeps_fallback_when_rematch_fails(monkeypatch):
|
|||||||
"name": "另一个晴天",
|
"name": "另一个晴天",
|
||||||
"artist": "未知艺术家",
|
"artist": "未知艺术家",
|
||||||
})
|
})
|
||||||
with patch("app.chain.media.eventmanager") as em:
|
em = MagicMock()
|
||||||
em.check.return_value = True
|
em.check.return_value = True
|
||||||
em.send_event.return_value = event
|
em.send_event.return_value = event
|
||||||
|
monkeypatch.setattr(chain, "eventmanager", em)
|
||||||
result = chain.recognize_by_meta(meta)
|
result = chain.recognize_by_meta(meta)
|
||||||
|
|
||||||
assert result is fallback
|
assert result is fallback
|
||||||
@@ -169,9 +174,11 @@ def test_async_music_recognize_help(monkeypatch):
|
|||||||
"name": "晴天",
|
"name": "晴天",
|
||||||
"artist": "周杰伦",
|
"artist": "周杰伦",
|
||||||
})
|
})
|
||||||
with patch("app.chain.media.eventmanager") as em:
|
# 事件经注入的 eventmanager 发送,直接替换实例依赖并保留断言能力
|
||||||
|
em = MagicMock()
|
||||||
em.check.return_value = True
|
em.check.return_value = True
|
||||||
em.async_send_event = AsyncMock(return_value=event)
|
em.async_send_event = AsyncMock(return_value=event)
|
||||||
|
monkeypatch.setattr(chain, "eventmanager", em)
|
||||||
result = asyncio.run(chain.async_recognize_by_meta(meta))
|
result = asyncio.run(chain.async_recognize_by_meta(meta))
|
||||||
|
|
||||||
assert result is remote
|
assert result is remote
|
||||||
@@ -193,10 +200,11 @@ def test_plugin_first_keeps_fallback_when_help_unidentified(monkeypatch):
|
|||||||
"title": "晴天",
|
"title": "晴天",
|
||||||
"name": "另一个晴天",
|
"name": "另一个晴天",
|
||||||
})
|
})
|
||||||
with patch("app.chain.media.eventmanager") as em, \
|
em = MagicMock()
|
||||||
patch("app.runtime.config.settings.RECOGNIZE_PLUGIN_FIRST", True):
|
|
||||||
em.check.return_value = True
|
em.check.return_value = True
|
||||||
em.send_event.return_value = event
|
em.send_event.return_value = event
|
||||||
|
monkeypatch.setattr(chain, "eventmanager", em)
|
||||||
|
with patch("app.runtime.config.settings.RECOGNIZE_PLUGIN_FIRST", True):
|
||||||
result = chain.recognize_by_meta(meta)
|
result = chain.recognize_by_meta(meta)
|
||||||
|
|
||||||
assert result is fallback
|
assert result is fallback
|
||||||
|
|||||||
Reference in New Issue
Block a user