mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-28 19:47:41 +08:00
fix(subscribe): map v2 tmdbid source to media_id (#6460)
This commit is contained in:
@@ -7,7 +7,7 @@ from typing import Any, Optional, Protocol
|
|||||||
from app.domain.context import MediaInfo
|
from app.domain.context import MediaInfo
|
||||||
from app.domain.meta.metabase import MetaBase
|
from app.domain.meta.metabase import MetaBase
|
||||||
from app.schemas.media import resolve_media_identity
|
from app.schemas.media import resolve_media_identity
|
||||||
from app.schemas.types import MediaType
|
from app.schemas.types import MediaSource, MediaType
|
||||||
from app.schemas.workflow import Subscribe as SubscribeView
|
from app.schemas.workflow import Subscribe as SubscribeView
|
||||||
|
|
||||||
|
|
||||||
@@ -85,6 +85,14 @@ class SubscriptionQueryService:
|
|||||||
"media_id",
|
"media_id",
|
||||||
"music_type",
|
"music_type",
|
||||||
}
|
}
|
||||||
|
_LEGACY_ID_FIELDS: tuple[tuple[str, MediaSource], ...] = (
|
||||||
|
("tmdbid", MediaSource.TMDB),
|
||||||
|
("doubanid", MediaSource.Douban),
|
||||||
|
("bangumiid", MediaSource.Bangumi),
|
||||||
|
("anilistid", MediaSource.AniList),
|
||||||
|
("imdbid", MediaSource.IMDb),
|
||||||
|
("tvdbid", MediaSource.TVDB),
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -199,6 +207,30 @@ class SubscriptionQueryService:
|
|||||||
episode_group=mediainfo.episode_group,
|
episode_group=mediainfo.episode_group,
|
||||||
))
|
))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _has_media_identity(cls, identity: dict[str, Any]) -> bool:
|
||||||
|
"""判断来源关键字是否已带成对的媒体身份。"""
|
||||||
|
media_id = identity.get("media_id")
|
||||||
|
return bool(identity.get("media_source")) and media_id not in (
|
||||||
|
None,
|
||||||
|
"",
|
||||||
|
0,
|
||||||
|
"0",
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _legacy_media_identity(cls, source_keyword: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
"""把 v2 订阅来源里的 tmdbid/doubanid 等补成 media_source + media_id。"""
|
||||||
|
for field, source in cls._LEGACY_ID_FIELDS:
|
||||||
|
raw = source_keyword.get(field)
|
||||||
|
if raw in (None, "", 0, "0"):
|
||||||
|
continue
|
||||||
|
return {
|
||||||
|
"media_source": source,
|
||||||
|
"media_id": str(raw),
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
|
||||||
def get_by_source(self, source_keyword: Optional[dict]) -> Optional[Any]:
|
def get_by_source(self, source_keyword: Optional[dict]) -> Optional[Any]:
|
||||||
"""从已解析来源关键字筛出稳定身份字段并读取订阅。"""
|
"""从已解析来源关键字筛出稳定身份字段并读取订阅。"""
|
||||||
if not source_keyword:
|
if not source_keyword:
|
||||||
@@ -208,6 +240,10 @@ class SubscriptionQueryService:
|
|||||||
for key, value in source_keyword.items()
|
for key, value in source_keyword.items()
|
||||||
if key in self._SOURCE_FIELDS
|
if key in self._SOURCE_FIELDS
|
||||||
}
|
}
|
||||||
|
if not self._has_media_identity(identity):
|
||||||
|
identity.update(self._legacy_media_identity(source_keyword))
|
||||||
|
if not identity.get("type") or not self._has_media_identity(identity):
|
||||||
|
return None
|
||||||
return self._repository.get_by(**identity)
|
return self._repository.get_by(**identity)
|
||||||
|
|
||||||
def has_music(self, searchable_states: str) -> bool:
|
def has_music(self, searchable_states: str) -> bool:
|
||||||
|
|||||||
@@ -63,6 +63,45 @@ def test_subscription_query_service_filters_source_and_music_state() -> None:
|
|||||||
repository.list.assert_called_once_with("R,P")
|
repository.list.assert_called_once_with("R,P")
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_by_source_upgrades_legacy_tmdbid_identity() -> None:
|
||||||
|
"""v2 下载记录只有 tmdbid 时,应补成 themoviedb + media_id 再查订阅。"""
|
||||||
|
repository = Mock()
|
||||||
|
expected = SimpleNamespace(id=22)
|
||||||
|
repository.get_by.return_value = expected
|
||||||
|
service = SubscriptionQueryService(repository)
|
||||||
|
|
||||||
|
result = service.get_by_source({
|
||||||
|
"id": 22,
|
||||||
|
"name": "阿滋漫画大王",
|
||||||
|
"type": MediaType.TV.value,
|
||||||
|
"season": 1,
|
||||||
|
"tmdbid": 12143,
|
||||||
|
"imdbid": "tt0339955",
|
||||||
|
"tvdbid": 79077,
|
||||||
|
})
|
||||||
|
|
||||||
|
assert result is expected
|
||||||
|
repository.get_by.assert_called_once_with(
|
||||||
|
type=MediaType.TV.value,
|
||||||
|
season=1,
|
||||||
|
media_source=MediaSource.TMDB,
|
||||||
|
media_id="12143",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_by_source_skips_incomplete_legacy_identity() -> None:
|
||||||
|
"""来源既无 media_id 也无旧 tmdbid 时,不得把半对身份传给仓储。"""
|
||||||
|
repository = Mock()
|
||||||
|
service = SubscriptionQueryService(repository)
|
||||||
|
|
||||||
|
assert service.get_by_source({
|
||||||
|
"type": MediaType.TV.value,
|
||||||
|
"season": 1,
|
||||||
|
"name": "Demo",
|
||||||
|
}) is None
|
||||||
|
repository.get_by.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
def test_subscribe_chain_facade_delegates_three_query_slices() -> None:
|
def test_subscribe_chain_facade_delegates_three_query_slices() -> None:
|
||||||
"""SubscribeChain 保持三个公开方法签名并仅负责来源解析和结果转发。"""
|
"""SubscribeChain 保持三个公开方法签名并仅负责来源解析和结果转发。"""
|
||||||
service = Mock()
|
service = Mock()
|
||||||
|
|||||||
Reference in New Issue
Block a user