mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 23:47:41 +08:00
fix(music): separate album and recording subscriptions
This commit is contained in:
@@ -2,7 +2,7 @@ from types import SimpleNamespace
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from app.chain.subscribe import SubscribeChain, build_subscribe_meta
|
||||
from app.core.context import MUSIC_ENTITY_ALBUM, Context, TorrentInfo
|
||||
from app.core.context import MUSIC_ENTITY_ALBUM, MUSIC_ENTITY_RECORDING, Context, TorrentInfo
|
||||
from app.core.meta import MetaMusic
|
||||
from app.core.context import MusicInfo
|
||||
from app.schemas.types import MediaType
|
||||
@@ -97,7 +97,7 @@ def test_music_subscribe_reuses_search_download_and_finish_flow():
|
||||
chain._search_music_subscribe(subscribe)
|
||||
|
||||
search_chain.search_by_title.assert_called_once_with(
|
||||
title="周杰伦 叶惠美",
|
||||
title="周杰伦 晴天",
|
||||
sites=[],
|
||||
mtype=MediaType.MUSIC,
|
||||
rule_groups=[],
|
||||
@@ -253,6 +253,47 @@ def test_album_subscription_finishes_only_after_confirmed_full_pack():
|
||||
) is True
|
||||
|
||||
|
||||
def test_music_subscribe_target_validation_enforces_entity_semantics():
|
||||
"""单曲无需专辑曲目数,专辑必须有总曲目数,艺术家和实体错配均不可订阅。"""
|
||||
recording = _music_info()
|
||||
recording.total_tracks = 11
|
||||
album = MusicInfo(
|
||||
source="musicbrainz",
|
||||
media_id="release-group-1",
|
||||
music_type=MUSIC_ENTITY_ALBUM,
|
||||
title="叶惠美",
|
||||
album="叶惠美",
|
||||
total_tracks=11,
|
||||
)
|
||||
|
||||
assert SubscribeChain._validate_music_subscribe_target(
|
||||
recording, MUSIC_ENTITY_RECORDING
|
||||
) is None
|
||||
assert SubscribeChain._validate_music_subscribe_target(album, MUSIC_ENTITY_ALBUM) is None
|
||||
assert "类型不匹配" in (
|
||||
SubscribeChain._validate_music_subscribe_target(album, MUSIC_ENTITY_RECORDING) or ""
|
||||
)
|
||||
album.total_tracks = None
|
||||
assert "总曲目数未知" in (
|
||||
SubscribeChain._validate_music_subscribe_target(album, MUSIC_ENTITY_ALBUM) or ""
|
||||
)
|
||||
assert "仅支持单曲或专辑" in (
|
||||
SubscribeChain._validate_music_subscribe_target(recording, "artist") or ""
|
||||
)
|
||||
|
||||
|
||||
def test_recording_target_sync_clears_stale_album_track_count():
|
||||
"""旧单曲订阅若误存所属专辑曲目数,刷新元数据时应主动清空。"""
|
||||
subscribe = _subscribe(total_tracks=11)
|
||||
subscribe_oper = Mock()
|
||||
|
||||
with patch("app.chain.subscribe.SubscribeOper", return_value=subscribe_oper):
|
||||
SubscribeChain._sync_music_subscribe_target(subscribe, _music_info())
|
||||
|
||||
subscribe_oper.update.assert_called_once_with(subscribe.id, {"total_tracks": None})
|
||||
assert subscribe.total_tracks is None
|
||||
|
||||
|
||||
def test_subscribe_add_music_uses_unified_recognize_by_meta():
|
||||
"""音乐订阅新增应走统一 recognize_by_meta,并把媒体身份落到 MetaMusic 上。"""
|
||||
target = _music_info()
|
||||
@@ -284,6 +325,29 @@ def test_subscribe_add_music_uses_unified_recognize_by_meta():
|
||||
assert media_chain.recognize_by_meta.call_args.kwargs["source"] == "musicbrainz"
|
||||
|
||||
|
||||
def test_subscribe_add_rejects_music_entity_mismatch_before_database_write():
|
||||
"""请求专辑却识别为单曲时必须中止,不能创建完成语义错误的订阅。"""
|
||||
media_chain = Mock()
|
||||
media_chain.recognize_by_meta.return_value = _music_info()
|
||||
subscribe_oper = Mock()
|
||||
|
||||
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="2003",
|
||||
mtype=MediaType.MUSIC,
|
||||
media_source="musicbrainz",
|
||||
media_id="recording-1",
|
||||
music_type=MUSIC_ENTITY_ALBUM,
|
||||
message=False,
|
||||
)
|
||||
|
||||
assert sid is None
|
||||
assert "类型不匹配" in err_msg
|
||||
subscribe_oper.add.assert_not_called()
|
||||
|
||||
|
||||
def test_subscribe_add_music_fails_fast_on_offline_fallback():
|
||||
"""统一识别返回离线兜底(无远端 source)时订阅应直接失败,不写入数据库。"""
|
||||
offline = MusicInfo(title="未知曲目", artists=["未知艺术家"])
|
||||
@@ -304,3 +368,39 @@ def test_subscribe_add_music_fails_fast_on_offline_fallback():
|
||||
assert sid is None
|
||||
assert err_msg == "未识别到媒体信息"
|
||||
subscribe_oper.add.assert_not_called()
|
||||
|
||||
|
||||
def test_follow_preserves_album_entity_and_track_count():
|
||||
"""Follow 专辑分享不得走影视标题解析,并须保留整专完成判定字段。"""
|
||||
share = {
|
||||
"share_uid": "follow-user",
|
||||
"name": "叶惠美",
|
||||
"type": MediaType.MUSIC.value,
|
||||
"year": "2003",
|
||||
"media_source": "musicbrainz",
|
||||
"media_id": "release-group-1",
|
||||
"music_type": MUSIC_ENTITY_ALBUM,
|
||||
"total_tracks": 11,
|
||||
"filter_groups": [],
|
||||
}
|
||||
subscribe_oper = Mock()
|
||||
subscribe_oper.exists.return_value = False
|
||||
subscribe_oper.exist_history.return_value = False
|
||||
system_config = Mock()
|
||||
system_config.get.return_value = ["follow-user"]
|
||||
|
||||
with patch("app.chain.subscribe.SubscribeOper", return_value=subscribe_oper), \
|
||||
patch("app.chain.subscribe.SystemConfigOper", return_value=system_config), \
|
||||
patch(
|
||||
"app.chain.subscribe.MoviePilotServerHelper.get_subscribe_shares",
|
||||
return_value=[share],
|
||||
), \
|
||||
patch("app.chain.subscribe.MetaInfo") as video_meta, \
|
||||
patch.object(SubscribeChain, "add", return_value=(1, "")) as add:
|
||||
SubscribeChain.follow()
|
||||
|
||||
video_meta.assert_not_called()
|
||||
assert subscribe_oper.exists.call_args.kwargs["music_type"] == MUSIC_ENTITY_ALBUM
|
||||
assert subscribe_oper.exist_history.call_args.kwargs["music_type"] == MUSIC_ENTITY_ALBUM
|
||||
assert add.call_args.kwargs["music_type"] == MUSIC_ENTITY_ALBUM
|
||||
assert add.call_args.kwargs["total_tracks"] == 11
|
||||
|
||||
Reference in New Issue
Block a user