diff --git a/simnet/client/components/chronicle/genshin.py b/simnet/client/components/chronicle/genshin.py index 90581c4..1c6ba9a 100644 --- a/simnet/client/components/chronicle/genshin.py +++ b/simnet/client/components/chronicle/genshin.py @@ -5,6 +5,7 @@ from simnet.errors import DataNotPublic, BadRequest from simnet.models.genshin.chronicle.abyss import SpiralAbyss, SpiralAbyssPair from simnet.models.genshin.chronicle.achievement import GenshinAchievementInfo +from simnet.models.genshin.chronicle.act_calendar import GenshinActCalendar from simnet.models.genshin.chronicle.character_detail import GenshinCharacterListInfo, GenshinDetailCharacters from simnet.models.genshin.chronicle.characters import Character from simnet.models.genshin.chronicle.img_theater import ImgTheater @@ -380,3 +381,18 @@ async def get_genshin_achievement_info( """ data = await self._request_genshin_record("achievement", player_id, method="POST", lang=lang) return GenshinAchievementInfo(**data) + + async def get_genshin_act_calendar( + self, player_id: Optional[int] = None, *, lang: Optional[str] = None + ) -> GenshinActCalendar: + """Get genshin act calendar. + + Args: + player_id (Optional[int], optional): The player ID. Defaults to None. + lang (Optional[str], optional): The language of the data. Defaults to None. + + Returns: + GenshinActCalendar: The requested act calendar info. + """ + data = await self._request_genshin_record("act_calendar", player_id, method="POST", lang=lang) + return GenshinActCalendar(**data) diff --git a/simnet/models/genshin/chronicle/act_calendar.py b/simnet/models/genshin/chronicle/act_calendar.py new file mode 100644 index 0000000..2186797 --- /dev/null +++ b/simnet/models/genshin/chronicle/act_calendar.py @@ -0,0 +1,72 @@ +from datetime import datetime, timedelta +from typing import List + +from simnet.models.base import APIModel +from simnet.models.genshin.character import BaseCharacter + + +class EquipListItem(BaseCharacter): + """A model representing an equipment item in the Genshin act calendar.""" + + wiki_url: str + + +class AvatarListItem(BaseCharacter): + """A model representing an avatar item in the Genshin act calendar.""" + + is_invisible: bool = False + + +class CardPoolListItem(APIModel): + """A model representing an item in the card pool list in the Genshin act calendar.""" + + pool_id: int + version_name: str + pool_name: str + pool_type: int + avatars: List[AvatarListItem] + weapon: List[EquipListItem] + start_timestamp: datetime + end_timestamp: datetime + jump_url: str + pool_status: int + countdown_seconds: timedelta + + +class RewardItem(APIModel): + """A model representing a reward item in the Genshin act calendar.""" + + item_id: int + name: str + icon: str + wiki_url: str + num: int + rarity: str + homepage_show: bool + + +class ActListItem(APIModel): + """A model representing an item in the Genshin act calendar.""" + + id: int + name: str + type: str + start_timestamp: datetime + end_timestamp: datetime + desc: str + strategy: str + countdown_seconds: timedelta + status: int + reward_list: List[RewardItem] + is_finished: bool + + +class GenshinActCalendar(APIModel): + """A model representing the StarRail act calendar.""" + + avatar_card_pool_list: List[CardPoolListItem] + weapon_card_pool_list: List[CardPoolListItem] + mixed_card_pool_list: List[CardPoolListItem] + + act_list: List[ActListItem] + fixed_act_list: List[ActListItem] diff --git a/simnet/models/genshin/chronicle/img_theater.py b/simnet/models/genshin/chronicle/img_theater.py index 5920037..5c75a0a 100644 --- a/simnet/models/genshin/chronicle/img_theater.py +++ b/simnet/models/genshin/chronicle/img_theater.py @@ -1,6 +1,7 @@ import datetime import enum import typing +from typing import Optional from pydantic import Field @@ -171,10 +172,10 @@ class ImgTheaterFightStaticAvatar(BaseCharacter): class ImgTheaterFightStatic(APIModel): - max_defeat_avatar: ImgTheaterFightStaticAvatar - max_damage_avatar: ImgTheaterFightStaticAvatar - max_take_damage_avatar: ImgTheaterFightStaticAvatar - total_coin_consumed: ImgTheaterFightStaticAvatar + max_defeat_avatar: Optional[ImgTheaterFightStaticAvatar] + max_damage_avatar: Optional[ImgTheaterFightStaticAvatar] + max_take_damage_avatar: Optional[ImgTheaterFightStaticAvatar] + total_coin_consumed: Optional[ImgTheaterFightStaticAvatar] shortest_avatar_list: typing.Sequence[ImgTheaterFightStaticAvatar] total_use_time: int is_show_battle_stats: bool diff --git a/tests/test_genshin_battle_chronicle_client.py b/tests/test_genshin_battle_chronicle_client.py index e9f31d4..84444c9 100644 --- a/tests/test_genshin_battle_chronicle_client.py +++ b/tests/test_genshin_battle_chronicle_client.py @@ -90,3 +90,8 @@ async def test_get_genshin_character_detail(genshin_client: GenshinBattleChronic async def test_get_genshin_achievement_info(genshin_client: GenshinBattleChronicleClient): data = await genshin_client.get_genshin_achievement_info() assert data + + @staticmethod + async def test_get_genshin_act_calendar(genshin_client: GenshinBattleChronicleClient): + data = await genshin_client.get_genshin_act_calendar() + assert data