mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-22 00:32:50 +08:00
feat: 识别文件类型:音乐
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
from app.core.music import MusicInfo
|
||||
from app.core.context import MusicInfo
|
||||
from app.helper.audio import AudioMetadataHelper
|
||||
|
||||
|
||||
def test_read_audio_metadata_maps_easy_tags(monkeypatch):
|
||||
"""音频标签和技术参数应映射为 MusicMeta。"""
|
||||
"""音频标签和技术参数应映射为 MetaMusic。"""
|
||||
audio = SimpleNamespace(
|
||||
tags={
|
||||
"title": ["Get Lucky"],
|
||||
|
||||
@@ -2,8 +2,8 @@ from unittest.mock import AsyncMock, Mock, patch
|
||||
|
||||
from app.api.endpoints.media import recognize_file, scrape
|
||||
from app.core.context import Context, MediaInfo
|
||||
from app.core.meta import MetaBase
|
||||
from app.core.music import MusicInfo, MusicMeta
|
||||
from app.core.meta import MetaBase, MetaMusic
|
||||
from app.core.context import MusicInfo
|
||||
from app.schemas import FileItem, MediaType
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ def test_recognize_file_routes_audio_to_music_chain() -> None:
|
||||
music_chain = Mock()
|
||||
music_chain.async_recognize_by_path = AsyncMock(
|
||||
return_value=(
|
||||
MusicMeta(title="晴天", artists=["周杰伦"]),
|
||||
MetaMusic(title="晴天", artists=["周杰伦"]),
|
||||
MusicInfo(
|
||||
source="musicbrainz",
|
||||
media_id="977e6978-139d-425c-bb98-6b0c62d1e45e",
|
||||
|
||||
@@ -4,6 +4,7 @@ from types import SimpleNamespace
|
||||
from unittest.mock import patch
|
||||
|
||||
from app.core.metainfo import MetaInfo, MetaInfoPath, find_metainfo
|
||||
from app.core.meta import MetaBase, MetaMusic
|
||||
from app.core.meta.metaanime import MetaAnime
|
||||
from app.helper.torrent import TorrentHelper
|
||||
from app.schemas.types import MediaType
|
||||
@@ -172,6 +173,53 @@ def test_python_metainfo_fallback_preserves_xxx_movie_title():
|
||||
assert meta.audio_encode == "DDP 5.1"
|
||||
|
||||
|
||||
def test_metainfo_routes_audio_filename_to_music():
|
||||
"""音频文件名应直接走音乐分支,不再进入影视季集解析。"""
|
||||
meta = MetaInfo("周杰伦 - 晴天.flac")
|
||||
|
||||
assert isinstance(meta, MetaMusic)
|
||||
assert isinstance(meta, MetaBase)
|
||||
assert meta.type == MediaType.MUSIC
|
||||
assert meta.org_string == "周杰伦 - 晴天.flac"
|
||||
assert meta.title == "周杰伦 - 晴天"
|
||||
assert meta.audio_format == "FLAC"
|
||||
# 音乐没有季集信息,兼容通用访问
|
||||
assert meta.season is None
|
||||
assert meta.episode is None
|
||||
assert meta.apply_words == []
|
||||
|
||||
|
||||
def test_metainfo_routes_audio_path_to_music_without_parent_merge():
|
||||
"""音频路径应直接构造音乐元数据,不与父目录季集合并。"""
|
||||
meta = MetaInfoPath(Path("/music/叶惠美/周杰伦 - 晴天.flac"))
|
||||
|
||||
assert isinstance(meta, MetaMusic)
|
||||
assert meta.type == MediaType.MUSIC
|
||||
assert meta.org_string == "周杰伦 - 晴天.flac"
|
||||
assert meta.title == "周杰伦 - 晴天"
|
||||
assert meta.audio_format == "FLAC"
|
||||
|
||||
|
||||
def test_metainfo_keeps_video_path_for_non_audio_files():
|
||||
"""非音频文件应继续走影视识别链,不受音频路由影响。"""
|
||||
meta = MetaInfoPath(Path("/movies/Inception (2010)/Inception.2010.1080p.mkv"))
|
||||
|
||||
assert not isinstance(meta, MetaMusic)
|
||||
assert meta.type != MediaType.MUSIC
|
||||
|
||||
|
||||
def test_metainfo_music_round_trip_preserves_fields():
|
||||
"""音频解析结果字典往返后应保留音乐字段。"""
|
||||
meta = MetaInfoPath(Path("/music/周杰伦 - 晴天.flac"))
|
||||
payload = meta.to_dict()
|
||||
restored = MetaMusic.from_dict(payload)
|
||||
|
||||
assert restored.type == MediaType.MUSIC
|
||||
assert restored.title == "周杰伦 - 晴天"
|
||||
assert restored.audio_format == "FLAC"
|
||||
assert payload["type"] == "音乐"
|
||||
|
||||
|
||||
def test_python_subtitle_episode_range_fin_with_chinese_season():
|
||||
"""Python 兜底解析应识别副标题中 [01-26Fin] 格式的集数范围(#6103)。"""
|
||||
with patch("app.core.metainfo.rust_accel.parse_metainfo", return_value=None):
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from app.chain.music import MusicChain
|
||||
from app.core.music import MusicAlbumInfo, MusicArtistInfo, MusicInfo, MusicMeta
|
||||
from app.core.meta import MetaMusic
|
||||
from app.core.context import MusicAlbumInfo, MusicArtistInfo, MusicInfo
|
||||
|
||||
|
||||
def test_parse_query_supports_artist_title_format():
|
||||
@@ -156,7 +157,7 @@ def test_async_chart_applies_music_explore_filters(monkeypatch):
|
||||
|
||||
def test_select_path_candidate_prefers_matching_audio_tags():
|
||||
"""文件识别应优先选择标题、艺术家和专辑均匹配的 MusicBrainz 候选。"""
|
||||
meta = MusicMeta(title="晴天", artists=["周杰伦"], album="叶惠美")
|
||||
meta = MetaMusic(title="晴天", artists=["周杰伦"], album="叶惠美")
|
||||
candidates = [
|
||||
MusicInfo(source="musicbrainz", media_id="1", title="晴天", artists=["其他歌手"]),
|
||||
MusicInfo(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from app.core.context import Context, MediaInfo
|
||||
from app.core.music import MusicInfo, MusicMeta
|
||||
from app.core.meta import MetaMusic
|
||||
from app.core.context import MusicInfo
|
||||
from app.schemas.context import Context as ContextSchema
|
||||
from app.schemas.context import MediaInfo as MediaInfoSchema
|
||||
from app.schemas.music import MusicInfo as MusicInfoSchema
|
||||
@@ -16,8 +17,8 @@ def test_media_type_supports_music_agent_conversion():
|
||||
|
||||
|
||||
def test_music_meta_round_trip_preserves_list_isolation():
|
||||
"""MusicMeta 字典往返后应保留字段且不共享可变列表。"""
|
||||
meta = MusicMeta(
|
||||
"""MetaMusic 字典往返后应保留字段且不共享可变列表。"""
|
||||
meta = MetaMusic(
|
||||
org_string="Jay Chou - Common Jasmin Orange",
|
||||
title="七里香",
|
||||
artists=["周杰伦"],
|
||||
@@ -27,7 +28,7 @@ def test_music_meta_round_trip_preserves_list_isolation():
|
||||
)
|
||||
|
||||
payload = meta.to_dict()
|
||||
restored = MusicMeta.from_dict(payload)
|
||||
restored = MetaMusic.from_dict(payload)
|
||||
restored.artists.append("Jay Chou")
|
||||
|
||||
assert payload["type"] == "音乐"
|
||||
@@ -62,7 +63,7 @@ def test_music_info_serializes_shared_media_display_fields():
|
||||
def test_core_context_serializes_music_models_without_video_fields():
|
||||
"""核心 Context 应使用既有外层结构序列化音乐对象。"""
|
||||
context = Context(
|
||||
meta_info=MusicMeta(title="七里香", artists=["周杰伦"]),
|
||||
meta_info=MetaMusic(title="七里香", artists=["周杰伦"]),
|
||||
media_info=MusicInfo(
|
||||
source="musicbrainz",
|
||||
media_id="release-1",
|
||||
|
||||
@@ -3,7 +3,7 @@ from unittest.mock import Mock, patch
|
||||
from app.api.endpoints.download import download
|
||||
from app.chain.download import DownloadChain
|
||||
from app.chain.music import MusicChain
|
||||
from app.core.music import MusicInfo
|
||||
from app.core.context import MusicInfo
|
||||
from app.schemas.context import TorrentInfo
|
||||
from app.schemas.music import MusicInfo as MusicInfoSchema
|
||||
from app.schemas.types import MediaType
|
||||
@@ -50,7 +50,7 @@ def test_download_note_keeps_versioned_music_context():
|
||||
|
||||
|
||||
def test_download_endpoint_builds_music_context():
|
||||
"""现有添加下载接口应使用 MusicInfo 和 MusicMeta 构造音乐上下文。"""
|
||||
"""现有添加下载接口应使用 MusicInfo 和 MetaMusic 构造音乐上下文。"""
|
||||
chain = Mock()
|
||||
chain.download_single.return_value = "hash-1"
|
||||
current_user = Mock(name="admin")
|
||||
|
||||
@@ -14,7 +14,7 @@ from app.api.endpoints.music import (
|
||||
recognize_music,
|
||||
search_music,
|
||||
)
|
||||
from app.core.music import MusicAlbumInfo, MusicArtistInfo, MusicInfo, MusicRelease
|
||||
from app.core.context import MusicAlbumInfo, MusicArtistInfo, MusicInfo, MusicRelease
|
||||
from app.schemas.music import MusicRecognizeRequest
|
||||
|
||||
|
||||
|
||||
114
tests/test_music_recognize_routing.py
Normal file
114
tests/test_music_recognize_routing.py
Normal file
@@ -0,0 +1,114 @@
|
||||
"""音乐识别统一入口路由测试。
|
||||
|
||||
覆盖 MediaChain 同步/异步 ``recognize_by_meta`` 与 ``recognize_by_path`` 按
|
||||
``MetaMusic`` 路由到 ``MusicChain``,以及 ``MusicChain.recognize_by_meta`` 自身的
|
||||
详情、搜索匹配与离线兜底分支。
|
||||
"""
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
from unittest.mock import AsyncMock, Mock, patch
|
||||
|
||||
from app.chain.media import MediaChain
|
||||
from app.chain.music import MusicChain
|
||||
from app.core.context import MusicInfo
|
||||
from app.core.meta import MetaMusic
|
||||
from app.schemas.types import MediaType
|
||||
|
||||
|
||||
def _music_info() -> MusicInfo:
|
||||
"""构造带远端身份的标准音乐信息,用于断言路由返回值。"""
|
||||
return MusicInfo(
|
||||
source="musicbrainz",
|
||||
media_id="recording-1",
|
||||
title="晴天",
|
||||
artists=["周杰伦"],
|
||||
album="叶惠美",
|
||||
year=2003,
|
||||
)
|
||||
|
||||
|
||||
def test_media_chain_recognize_by_meta_routes_metamusic_to_musicchain():
|
||||
"""MetaMusic 应绕过影视识别链,直接交给 MusicChain.recognize_by_meta。"""
|
||||
meta = MetaMusic(title="晴天", artists=["周杰伦"])
|
||||
expected = _music_info()
|
||||
music_chain = Mock()
|
||||
music_chain.recognize_by_meta = Mock(return_value=expected)
|
||||
|
||||
with patch("app.chain.music.MusicChain", return_value=music_chain):
|
||||
result = MediaChain().recognize_by_meta(meta, source="musicbrainz")
|
||||
|
||||
music_chain.recognize_by_meta.assert_called_once_with(meta, source="musicbrainz")
|
||||
assert result is expected
|
||||
|
||||
|
||||
def test_media_chain_async_recognize_by_meta_routes_metamusic_to_musicchain():
|
||||
"""异步识别同样应把 MetaMusic 路由到 MusicChain.async_recognize_by_meta。"""
|
||||
meta = MetaMusic(title="晴天", artists=["周杰伦"])
|
||||
expected = _music_info()
|
||||
music_chain = Mock()
|
||||
music_chain.async_recognize_by_meta = AsyncMock(return_value=expected)
|
||||
|
||||
async def runner():
|
||||
with patch("app.chain.music.MusicChain", return_value=music_chain):
|
||||
return await MediaChain().async_recognize_by_meta(meta, source="musicbrainz")
|
||||
|
||||
result = asyncio.run(runner())
|
||||
music_chain.async_recognize_by_meta.assert_awaited_once_with(meta, source="musicbrainz")
|
||||
assert result is expected
|
||||
|
||||
|
||||
def test_media_chain_recognize_by_path_routes_audio_file_to_musicchain():
|
||||
"""音频文件路径应经 MetaInfoPath 构造 MetaMusic 并路由到音乐识别链。"""
|
||||
expected = _music_info()
|
||||
music_chain = Mock()
|
||||
music_chain.recognize_by_meta = Mock(return_value=expected)
|
||||
|
||||
with patch("app.chain.music.MusicChain", return_value=music_chain):
|
||||
context = MediaChain().recognize_by_path("/music/周杰伦 - 晴天.flac")
|
||||
|
||||
routed_meta = music_chain.recognize_by_meta.call_args.args[0]
|
||||
assert isinstance(routed_meta, MetaMusic)
|
||||
assert context.media_info is expected
|
||||
assert isinstance(context.meta_info, MetaMusic)
|
||||
|
||||
|
||||
def test_music_chain_recognize_by_meta_uses_detail_when_meta_has_identity(monkeypatch):
|
||||
"""meta 携带 source+media_id 时应走详情分支,不再触发搜索。"""
|
||||
chain = MusicChain()
|
||||
meta = MetaMusic(title="晴天", media_source="musicbrainz", media_id="recording-1")
|
||||
expected = _music_info()
|
||||
monkeypatch.setattr(chain, "recognize", Mock(return_value=expected))
|
||||
search_mock = Mock(return_value=[])
|
||||
monkeypatch.setattr(chain, "run_module", search_mock)
|
||||
|
||||
result = chain.recognize_by_meta(meta, source="musicbrainz")
|
||||
|
||||
chain.recognize.assert_called_once_with("musicbrainz", "recording-1")
|
||||
search_mock.assert_not_called()
|
||||
assert result is expected
|
||||
|
||||
|
||||
def test_music_chain_recognize_by_meta_matches_search_candidate(monkeypatch):
|
||||
"""无身份时应按标题搜索并选择匹配候选。"""
|
||||
chain = MusicChain()
|
||||
meta = MetaMusic(title="晴天", artists=["周杰伦"], album="叶惠美")
|
||||
candidate = _music_info()
|
||||
monkeypatch.setattr(chain, "run_module", Mock(return_value=[candidate]))
|
||||
|
||||
result = chain.recognize_by_meta(meta)
|
||||
|
||||
assert result is candidate
|
||||
|
||||
|
||||
def test_music_chain_recognize_by_meta_falls_back_to_offline_when_no_match(monkeypatch):
|
||||
"""搜索无候选时应返回离线兜底,且兜底结果不带远端 source。"""
|
||||
chain = MusicChain()
|
||||
meta = MetaMusic(title="未知曲目", artists=["未知艺术家"])
|
||||
monkeypatch.setattr(chain, "run_module", Mock(return_value=[]))
|
||||
|
||||
result = chain.recognize_by_meta(meta)
|
||||
|
||||
assert result is not None
|
||||
assert result.title == "未知曲目"
|
||||
# 离线兜底不携带远端来源,订阅等场景据此判定未真实命中
|
||||
assert result.source is None
|
||||
@@ -1,7 +1,8 @@
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from app.chain.search import SearchChain
|
||||
from app.core.music import MusicInfo, MusicMeta
|
||||
from app.core.meta import MetaMusic
|
||||
from app.core.context import MusicInfo
|
||||
from app.schemas.context import TorrentInfo
|
||||
from app.schemas.types import MediaType
|
||||
|
||||
@@ -38,7 +39,7 @@ def test_music_context_builder_keeps_only_music_category():
|
||||
|
||||
assert len(contexts) == 1
|
||||
assert contexts[0].media_info is music
|
||||
assert isinstance(contexts[0].meta_info, MusicMeta)
|
||||
assert isinstance(contexts[0].meta_info, MetaMusic)
|
||||
assert contexts[0].meta_info.media_id == "recording-1"
|
||||
assert contexts[0].torrent_info.category == MediaType.MUSIC.value
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@ from unittest.mock import Mock, patch
|
||||
|
||||
from app.chain.subscribe import SubscribeChain, build_subscribe_meta
|
||||
from app.core.context import Context, TorrentInfo
|
||||
from app.core.music import MusicInfo, MusicMeta
|
||||
from app.core.meta import MetaMusic
|
||||
from app.core.context import MusicInfo
|
||||
from app.schemas.types import MediaType
|
||||
|
||||
|
||||
@@ -56,10 +57,10 @@ def _subscribe() -> SimpleNamespace:
|
||||
|
||||
|
||||
def test_build_subscribe_meta_returns_music_meta():
|
||||
"""音乐订阅应构造 MusicMeta,而不是交给影视标题解析器。"""
|
||||
"""音乐订阅应构造 MetaMusic,而不是交给影视标题解析器。"""
|
||||
meta = build_subscribe_meta(_subscribe())
|
||||
|
||||
assert isinstance(meta, MusicMeta)
|
||||
assert isinstance(meta, MetaMusic)
|
||||
assert meta.type == MediaType.MUSIC
|
||||
assert meta.media_id == "recording-1"
|
||||
assert meta.original_name == "晴天"
|
||||
@@ -96,7 +97,7 @@ def test_music_subscribe_reuses_search_download_and_finish_flow():
|
||||
rule_groups=[],
|
||||
)
|
||||
assert context.media_info is target
|
||||
assert isinstance(context.meta_info, MusicMeta)
|
||||
assert isinstance(context.meta_info, MetaMusic)
|
||||
assert context.meta_info.org_string == "周杰伦 - 叶惠美 FLAC"
|
||||
download_chain.batch_download.assert_called_once()
|
||||
chain.finish_subscribe_or_not.assert_called_once()
|
||||
@@ -121,3 +122,56 @@ def test_music_subscribe_ignores_non_music_category():
|
||||
chain._search_music_subscribe(subscribe)
|
||||
|
||||
download_chain.assert_not_called()
|
||||
|
||||
|
||||
def test_subscribe_add_music_uses_unified_recognize_by_meta():
|
||||
"""音乐订阅新增应走统一 recognize_by_meta,并把媒体身份落到 MetaMusic 上。"""
|
||||
target = _music_info()
|
||||
media_chain = Mock()
|
||||
media_chain.recognize_by_meta = Mock(return_value=target)
|
||||
subscribe_oper = Mock()
|
||||
subscribe_oper.add.return_value = (1, "")
|
||||
|
||||
with patch("app.chain.subscribe.MediaChain", return_value=media_chain), \
|
||||
patch("app.chain.subscribe.SubscribeOper", return_value=subscribe_oper), \
|
||||
patch("app.chain.subscribe.MoviePilotServerHelper"), \
|
||||
patch("app.chain.subscribe.eventmanager"):
|
||||
sid, err_msg = SubscribeChain().add(
|
||||
title="周杰伦 - 晴天",
|
||||
year="2003",
|
||||
mtype=MediaType.MUSIC,
|
||||
media_source="musicbrainz",
|
||||
media_id="recording-1",
|
||||
message=False,
|
||||
)
|
||||
|
||||
assert sid == 1
|
||||
assert err_msg == ""
|
||||
media_chain.recognize_by_meta.assert_called_once()
|
||||
routed_meta = media_chain.recognize_by_meta.call_args.args[0]
|
||||
assert isinstance(routed_meta, MetaMusic)
|
||||
# 媒体身份落到 meta,供统一识别的详情分支复用
|
||||
assert routed_meta.media_id == "recording-1"
|
||||
assert media_chain.recognize_by_meta.call_args.kwargs["source"] == "musicbrainz"
|
||||
|
||||
|
||||
def test_subscribe_add_music_fails_fast_on_offline_fallback():
|
||||
"""统一识别返回离线兜底(无远端 source)时订阅应直接失败,不写入数据库。"""
|
||||
offline = MusicInfo(title="未知曲目", artists=["未知艺术家"])
|
||||
media_chain = Mock()
|
||||
media_chain.recognize_by_meta = Mock(return_value=offline)
|
||||
subscribe_oper = Mock()
|
||||
subscribe_oper.add.return_value = (1, "")
|
||||
|
||||
with patch("app.chain.subscribe.MediaChain", return_value=media_chain), \
|
||||
patch("app.chain.subscribe.SubscribeOper", return_value=subscribe_oper):
|
||||
sid, err_msg = SubscribeChain().add(
|
||||
title="未知曲目",
|
||||
year=None,
|
||||
mtype=MediaType.MUSIC,
|
||||
message=False,
|
||||
)
|
||||
|
||||
assert sid is None
|
||||
assert err_msg == "未识别到媒体信息"
|
||||
subscribe_oper.add.assert_not_called()
|
||||
|
||||
@@ -2,7 +2,8 @@ import asyncio
|
||||
from unittest.mock import AsyncMock, Mock, patch
|
||||
|
||||
from app.chain.torrents import TorrentsChain
|
||||
from app.core.music import MusicInfo, MusicMeta
|
||||
from app.core.meta import MetaMusic
|
||||
from app.core.context import MusicInfo
|
||||
from app.schemas.types import MediaType
|
||||
|
||||
|
||||
@@ -60,7 +61,7 @@ def test_music_cache_context_uses_music_models():
|
||||
result = chain.refresh(stype="spider", sites=[1])
|
||||
|
||||
context = result["example.com"][0]
|
||||
assert isinstance(context.meta_info, MusicMeta)
|
||||
assert isinstance(context.meta_info, MetaMusic)
|
||||
assert isinstance(context.media_info, MusicInfo)
|
||||
assert context.meta_info.artists == ["Daft Punk"]
|
||||
assert context.media_info.title == "Get Lucky"
|
||||
|
||||
@@ -4,14 +4,15 @@ from types import SimpleNamespace
|
||||
from app.chain.music import MusicChain
|
||||
from app.chain.transfer import JobManager, TransferChain
|
||||
from app.core.config import settings
|
||||
from app.core.music import MusicInfo, MusicMeta
|
||||
from app.core.meta import MetaMusic
|
||||
from app.core.context import MusicInfo
|
||||
from app.helper.message import TemplateHelper
|
||||
from app.schemas.file import FileItem
|
||||
from app.schemas.transfer import TransferTask
|
||||
from app.schemas.types import MediaType
|
||||
|
||||
|
||||
def _music_context() -> tuple[MusicMeta, MusicInfo]:
|
||||
def _music_context() -> tuple[MetaMusic, MusicInfo]:
|
||||
"""构造整理测试使用的音乐元数据和媒体信息。"""
|
||||
info = MusicInfo(
|
||||
source="musicbrainz",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from app.core.music import MusicMeta
|
||||
from app.core.meta import MetaMusic
|
||||
from app.modules.musicbrainz import MusicBrainzModule
|
||||
from app.core.config import settings
|
||||
|
||||
@@ -12,7 +12,7 @@ def test_musicbrainz_cover_domains_are_allowed_by_image_proxy():
|
||||
def test_build_query_uses_structured_music_fields():
|
||||
"""MusicBrainz 查询应同时使用歌曲、艺术家和专辑条件。"""
|
||||
query = MusicBrainzModule._build_query(
|
||||
MusicMeta(
|
||||
MetaMusic(
|
||||
title='Love "Story"',
|
||||
artists=["Taylor Swift"],
|
||||
album="Fearless",
|
||||
@@ -76,7 +76,7 @@ def test_search_music_normalizes_candidates(monkeypatch):
|
||||
},
|
||||
)
|
||||
|
||||
results = module.search_music(MusicMeta(title="晴天"), limit=5)
|
||||
results = module.search_music(MetaMusic(title="晴天"), limit=5)
|
||||
|
||||
assert len(results) == 1
|
||||
assert results[0].title == "晴天"
|
||||
|
||||
@@ -5,7 +5,7 @@ from unittest.mock import AsyncMock, patch
|
||||
import pytest
|
||||
|
||||
from app.chain.recommend import RecommendChain
|
||||
from app.core.music import MusicInfo
|
||||
from app.core.context import MusicInfo
|
||||
from app.core.cache import TTLCache
|
||||
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ def _load_subscribe_chain_class():
|
||||
context_module.TorrentInfo = SimpleNamespace
|
||||
context_module.Context = SimpleNamespace
|
||||
context_module.MediaInfo = SimpleNamespace
|
||||
context_module.MusicInfo = SimpleNamespace
|
||||
|
||||
event_module = ensure_module("app.core.event", types.ModuleType("app.core.event"))
|
||||
|
||||
@@ -106,6 +107,7 @@ def _load_subscribe_chain_class():
|
||||
|
||||
meta_module = ensure_module("app.core.meta", types.ModuleType("app.core.meta"))
|
||||
meta_module.MetaBase = SimpleNamespace
|
||||
meta_module.MetaMusic = SimpleNamespace
|
||||
|
||||
metainfo_module = ensure_module("app.core.metainfo", types.ModuleType("app.core.metainfo"))
|
||||
|
||||
@@ -349,6 +351,7 @@ def _load_subscribe_chain_class():
|
||||
"app.chain.download": "DownloadChain",
|
||||
"app.chain.media": "MediaChain",
|
||||
"app.chain.mediaserver": "MediaServerChain",
|
||||
"app.chain.music": "MusicChain",
|
||||
"app.chain.search": "SearchChain",
|
||||
"app.chain.tmdb": "TmdbChain",
|
||||
"app.chain.torrents": "TorrentsChain",
|
||||
|
||||
@@ -8,7 +8,7 @@ import pytest
|
||||
from app.db.models.subscribe import Subscribe
|
||||
from app.db.models.subscribehistory import SubscribeHistory
|
||||
from app.db.subscribe_oper import SubscribeOper
|
||||
from app.core.music import MusicInfo
|
||||
from app.core.context import MusicInfo
|
||||
from app.schemas.types import MediaType
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user