fix(subscribe): map v2 tmdbid source to media_id (#6460)

This commit is contained in:
ngcat
2026-08-26 06:43:01 +08:00
committed by GitHub
parent c0222ee7d1
commit a79e00f1e9
2 changed files with 76 additions and 1 deletions
+37 -1
View File
@@ -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:
+39
View File
@@ -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()