From a322c4c3752433e60b5739550ee07d4058f2caad Mon Sep 17 00:00:00 2001 From: jxxghp Date: Mon, 10 Aug 2026 21:41:04 +0800 Subject: [PATCH] =?UTF-8?q?feat(media):=20=E5=AA=92=E4=BD=93=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E8=A1=A5=E5=85=85=20TVDB=20slug=20=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8D=20TheTvDb=20=E6=95=B0=E5=AD=97=20ID?= =?UTF-8?q?=20=E9=93=BE=E6=8E=A5=20404?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TVDB 已弃用数字 ID 直达 URL,仅 slug 形式可访问。详情接口在电视剧有 TVDB ID 时通过轻量 get_series 接口获取 slug,并随 MediaInfo 合并下发。Closes jxxghp/MoviePilot-Frontend#643 --- app/api/endpoints/media.py | 5 +++++ app/chain/__init__.py | 8 ++++++++ app/chain/media.py | 2 +- app/core/context.py | 7 +++++++ app/modules/thetvdb/__init__.py | 15 +++++++++++++++ app/schemas/context.py | 2 ++ 6 files changed, 38 insertions(+), 1 deletion(-) diff --git a/app/api/endpoints/media.py b/app/api/endpoints/media.py index 85c4cb080..c3d921077 100644 --- a/app/api/endpoints/media.py +++ b/app/api/endpoints/media.py @@ -521,6 +521,11 @@ async def detail( # 识别 if mediainfo: await mediachain.async_obtain_images(mediainfo) + # 电视剧且有 TVDB ID 时,补充获取 slug 用于构建 TheTvDb 直达链接 + if mediainfo.type == MediaType.TV and mediainfo.tvdb_id and not mediainfo.tvdb_slug: + slug = mediachain.tvdb_slug(mediainfo.tvdb_id) + if slug: + mediainfo.tvdb_slug = slug return mediainfo.to_dict() return schemas.MediaInfo() diff --git a/app/chain/__init__.py b/app/chain/__init__.py index 91ed6112d..1fb9d483b 100644 --- a/app/chain/__init__.py +++ b/app/chain/__init__.py @@ -1040,6 +1040,14 @@ class ChainBase(metaclass=ABCMeta): """ return self.run_module("tvdb_info", tvdbid=tvdbid) + def tvdb_slug(self, tvdbid: int) -> Optional[str]: + """ + 获取TVDB剧集 slug(别名),用于构建 TheTvDb 直达链接。 + :param tvdbid: int + :return: slug 字符串 + """ + return self.run_module("tvdb_slug", tvdbid=tvdbid) + def tmdb_info( self, tmdbid: int, mtype: MediaType, season: Optional[int] = None ) -> Optional[dict]: diff --git a/app/chain/media.py b/app/chain/media.py index 4da8f6775..71dc64c6b 100644 --- a/app/chain/media.py +++ b/app/chain/media.py @@ -707,7 +707,7 @@ class MediaChain(ChainBase, ConfigReloadMixin, metaclass=Singleton): mediainfo.category = tmdb_media.category if not mediainfo.genre_ids: mediainfo.genre_ids = list(tmdb_media.genre_ids or []) - for field in ("imdb_id", "tvdb_id", "collection_id"): + for field in ("imdb_id", "tvdb_id", "tvdb_slug", "collection_id"): if not getattr(mediainfo, field, None): setattr(mediainfo, field, getattr(tmdb_media, field, None)) return mediainfo diff --git a/app/core/context.py b/app/core/context.py index 8f51324e4..4cdab1cfb 100644 --- a/app/core/context.py +++ b/app/core/context.py @@ -206,6 +206,11 @@ class MusicInfo: """音乐不使用 TVDB ID,兼容现有下载历史字段。""" return None + @property + def tvdb_slug(self) -> None: + """音乐不使用 TVDB Slug,兼容现有字段。""" + return None + @property def douban_id(self) -> None: """音乐不使用豆瓣 ID,兼容现有下载历史字段。""" @@ -888,6 +893,8 @@ class MediaInfo: imdb_id: str = None # TVDB ID tvdb_id: int = None + # TVDB Slug(别名,用于构建 TheTvDb 直达链接) + tvdb_slug: str = None # 豆瓣ID douban_id: str = None # Bangumi ID diff --git a/app/modules/thetvdb/__init__.py b/app/modules/thetvdb/__init__.py index d7d9baa53..d8065c5f0 100644 --- a/app/modules/thetvdb/__init__.py +++ b/app/modules/thetvdb/__init__.py @@ -143,6 +143,21 @@ class TheTvDbModule(_ModuleBase): logger.error(f"获取TVDB信息失败: {str(err)}") return None + def tvdb_slug(self, tvdbid: int) -> Optional[str]: + """ + 获取TVDB剧集的 slug(别名),用于构建 TheTvDb 直达链接。 + :param tvdbid: int + :return: slug 字符串,如 "speed-and-love" + """ + try: + result = self._handle_tvdb_call("get_series", tvdbid) + if result and isinstance(result, dict): + return result.get("slug") + return None + except Exception as err: + logger.error(f"获取TVDB slug 失败: {str(err)}") + return None + def search_tvdb(self, title: str) -> list: """ 用标题搜索TVDB剧集 diff --git a/app/schemas/context.py b/app/schemas/context.py index 7e20e8d45..1099906f9 100644 --- a/app/schemas/context.py +++ b/app/schemas/context.py @@ -105,6 +105,8 @@ class MediaInfo(BaseModel): imdb_id: Optional[str] = None # TVDB ID tvdb_id: Optional[int] = None + # TVDB Slug(别名,用于构建 TheTvDb 直达链接) + tvdb_slug: Optional[str] = None # 豆瓣ID douban_id: Optional[str] = None # Bangumi ID