diff --git a/genshin/client/components/chronicle/starrail.py b/genshin/client/components/chronicle/starrail.py index 57cbedb6..0088d752 100644 --- a/genshin/client/components/chronicle/starrail.py +++ b/genshin/client/components/chronicle/starrail.py @@ -126,3 +126,15 @@ async def get_starrail_rogue( payload = dict(schedule_type=schedule_type, need_detail="true") data = await self._request_starrail_record("rogue", uid, lang=lang, payload=payload) return models.StarRailRogue(**data) + + async def get_starrail_pure_fiction( + self, + uid: typing.Optional[int] = None, + *, + previous: bool = False, + lang: typing.Optional[str] = None, + ) -> models.StarRailPureFiction: + """Get starrail pure fiction runs.""" + payload = dict(schedule_type=2 if previous else 1, need_all="true") + data = await self._request_starrail_record("challenge_story", uid, lang=lang, payload=payload) + return models.StarRailPureFiction(**data) diff --git a/genshin/models/starrail/chronicle/challenge.py b/genshin/models/starrail/chronicle/challenge.py index 18510312..d2ddd361 100644 --- a/genshin/models/starrail/chronicle/challenge.py +++ b/genshin/models/starrail/chronicle/challenge.py @@ -1,12 +1,28 @@ """Starrail chronicle challenge.""" -from typing import List +from typing import TYPE_CHECKING, Any, Dict, List + +if TYPE_CHECKING: + import pydantic.v1 as pydantic +else: + try: + import pydantic.v1 as pydantic + except ImportError: + import pydantic from genshin.models.model import Aliased, APIModel from genshin.models.starrail.character import FloorCharacter from .base import PartialTime -__all__ = ["FloorNode", "StarRailChallenge", "StarRailFloor"] +__all__ = [ + "FictionBuff", + "FictionFloor", + "FictionFloorNode", + "FloorNode", + "StarRailChallenge", + "StarRailFloor", + "StarRailPureFiction", +] class FloorNode(APIModel): @@ -40,3 +56,65 @@ class StarRailChallenge(APIModel): has_data: bool floors: List[StarRailFloor] = Aliased("all_floor_detail") + + +class FictionBuff(APIModel): + """Buff for a Pure Fiction floor.""" + + id: int + name: str = Aliased("name_mi18n") + description: str = Aliased("desc_mi18n") + icon: str + + +class FictionFloorNode(FloorNode): + """Node for a Pure Fiction floor.""" + + buff: FictionBuff + score: int + + +class FictionFloor(APIModel): + """Floor in a Pure Fiction challenge.""" + + id: int = Aliased("maze_id") + name: str + round_num: int + star_num: int + node_1: FictionFloorNode + node_2: FictionFloorNode + is_fast: bool + + @property + def score(self) -> int: + """Total score of the floor.""" + return self.node_1.score + self.node_2.score + + +class StarRailPureFiction(APIModel): + """Pure Fiction challenge in a season.""" + + name: str + season_id: int + begin_time: PartialTime + end_time: PartialTime + + total_stars: int = Aliased("star_num") + max_floor: str + total_battles: int = Aliased("battle_num") + has_data: bool + + floors: List[FictionFloor] = Aliased("all_floor_detail") + max_floor_id: int + + @pydantic.root_validator(pre=True) + def __unnest_groups(cls, values: Dict[str, Any]) -> Dict[str, Any]: + if "groups" in values and isinstance(values["groups"], List): + groups: List[Dict[str, Any]] = values["groups"] + if len(groups) > 0: + values["name"] = groups[0]["name_mi18n"] + values["season_id"] = groups[0]["schedule_id"] + values["begin_time"] = groups[0]["begin_time"] + values["end_time"] = groups[0]["end_time"] + + return values