diff --git a/app/modules/bangumi/__init__.py b/app/modules/bangumi/__init__.py index 6bf1ed56..7983e333 100644 --- a/app/modules/bangumi/__init__.py +++ b/app/modules/bangumi/__init__.py @@ -241,14 +241,7 @@ class BangumiModule(_ModuleBase): """ personinfo = self.bangumiapi.person_detail(person_id) if personinfo: - return schemas.MediaPerson(source='bangumi', **{ - "id": personinfo.get("id"), - "name": personinfo.get("name"), - "images": personinfo.get("images"), - "biography": personinfo.get("summary"), - "birthday": personinfo.get("birth_day"), - "gender": personinfo.get("gender") - }) + return self._build_person_detail(personinfo) return None async def async_bangumi_person_detail(self, person_id: int) -> Optional[schemas.MediaPerson]: @@ -258,16 +251,36 @@ class BangumiModule(_ModuleBase): """ personinfo = await self.bangumiapi.async_person_detail(person_id) if personinfo: - return schemas.MediaPerson(source='bangumi', **{ - "id": personinfo.get("id"), - "name": personinfo.get("name"), - "images": personinfo.get("images"), - "biography": personinfo.get("summary"), - "birthday": personinfo.get("birth_day"), - "gender": personinfo.get("gender") - }) + return self._build_person_detail(personinfo) return None + @classmethod + def _build_person_detail(cls, personinfo: dict) -> schemas.MediaPerson: + """ + 构造Bangumi人物详情信息。 + :param personinfo: Bangumi人物详情接口返回数据 + :return: 媒体人物信息 + """ + return schemas.MediaPerson(source='bangumi', **{ + "id": personinfo.get("id"), + "name": personinfo.get("name"), + "images": personinfo.get("images"), + "biography": personinfo.get("summary"), + "birthday": cls._normalize_optional_string(personinfo.get("birth_day")), + "gender": personinfo.get("gender") + }) + + @staticmethod + def _normalize_optional_string(value: object) -> Optional[str]: + """ + 规范化Bangumi接口中可能返回非字符串的可选文本字段。 + :param value: 原始字段值 + :return: 字符串字段值或None + """ + if value is None: + return None + return str(value) + def bangumi_person_credits(self, person_id: int) -> List[MediaInfo]: """ 根据TMDBID查询人物参演作品 diff --git a/tests/test_bangumi_module.py b/tests/test_bangumi_module.py new file mode 100644 index 00000000..2d785cef --- /dev/null +++ b/tests/test_bangumi_module.py @@ -0,0 +1,70 @@ +import asyncio + +from app.modules.bangumi import BangumiModule + + +class _FakeBangumiApi: + """ + 测试用Bangumi API客户端。 + """ + + def __init__(self, personinfo: dict): + """ + 初始化测试用人物详情数据。 + :param personinfo: 人物详情接口返回数据 + """ + self.personinfo = personinfo + + def person_detail(self, person_id: int) -> dict: + """ + 返回同步人物详情数据。 + :param person_id: 人物ID + :return: 人物详情接口返回数据 + """ + return self.personinfo + + async def async_person_detail(self, person_id: int) -> dict: + """ + 返回异步人物详情数据。 + :param person_id: 人物ID + :return: 人物详情接口返回数据 + """ + return self.personinfo + + +def test_bangumi_person_detail_normalizes_numeric_birthday(): + """ + Bangumi同步人物详情应兼容数字生日字段。 + """ + module = BangumiModule() + module.bangumiapi = _FakeBangumiApi({ + "id": 1001, + "name": "测试人物", + "images": {"large": "https://example.com/person.jpg"}, + "summary": "测试简介", + "birth_day": 22, + "gender": 1, + }) + + person = module.bangumi_person_detail(1001) + + assert person.birthday == "22" + + +def test_async_bangumi_person_detail_normalizes_numeric_birthday(): + """ + Bangumi异步人物详情应兼容数字生日字段。 + """ + module = BangumiModule() + module.bangumiapi = _FakeBangumiApi({ + "id": 1002, + "name": "测试异步人物", + "images": {"large": "https://example.com/async-person.jpg"}, + "summary": "测试异步简介", + "birth_day": 19, + "gender": 2, + }) + + person = asyncio.run(module.async_bangumi_person_detail(1002)) + + assert person.birthday == "19"