From dfa524e199300d6fb64d633a97d46ef7f39d65ac Mon Sep 17 00:00:00 2001 From: seriaati Date: Thu, 26 Sep 2024 15:05:13 +0800 Subject: [PATCH] Add ZZZ diary models and methods --- genshin/client/components/chronicle/base.py | 3 + genshin/client/components/chronicle/zzz.py | 52 +++++++++- genshin/client/routes.py | 2 + genshin/models/zzz/chronicle/__init__.py | 1 + genshin/models/zzz/chronicle/month_info.py | 101 ++++++++++++++++++++ 5 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 genshin/models/zzz/chronicle/month_info.py diff --git a/genshin/client/components/chronicle/base.py b/genshin/client/components/chronicle/base.py index a9c34e01..b3fabf7d 100644 --- a/genshin/client/components/chronicle/base.py +++ b/genshin/client/components/chronicle/base.py @@ -45,11 +45,14 @@ async def request_game_record( region: typing.Optional[types.Region] = None, game: typing.Optional[types.Game] = None, is_card_wapi: bool = False, + is_nap_ledger: bool = False, **kwargs: typing.Any, ) -> typing.Mapping[str, typing.Any]: """Make a request towards the game record endpoint.""" if is_card_wapi: base_url = routes.CARD_WAPI_URL.get_url(region or self.region) + elif is_nap_ledger: + base_url = routes.NAP_LEDGER_URL.get_url() else: game = game or self.default_game if game is None: diff --git a/genshin/client/components/chronicle/zzz.py b/genshin/client/components/chronicle/zzz.py index bf1d7c4d..3bdad304 100644 --- a/genshin/client/components/chronicle/zzz.py +++ b/genshin/client/components/chronicle/zzz.py @@ -22,13 +22,26 @@ async def _request_zzz_record( lang: typing.Optional[str] = None, payload: typing.Optional[typing.Mapping[str, typing.Any]] = None, cache: bool = False, + is_nap_ledger: bool = False, ) -> typing.Mapping[str, typing.Any]: """Get an arbitrary ZZZ object.""" payload = dict(payload or {}) original_payload = payload.copy() uid = uid or await self._get_uid(types.Game.ZZZ) - payload = dict(role_id=uid, server=utility.recognize_zzz_server(uid), **payload) + + if is_nap_ledger: + payload = { + "uid": uid, + "region": utility.recognize_zzz_server(uid), + **payload, + } + else: + payload = { + "role_id": uid, + "server": utility.recognize_zzz_server(uid), + **payload, + } data, params = None, None if method == "POST": @@ -54,6 +67,7 @@ async def _request_zzz_record( params=params, data=data, cache=cache_key, + is_nap_ledger=is_nap_ledger, ) async def get_zzz_notes( @@ -78,6 +92,42 @@ async def get_zzz_notes( return models.ZZZNotes(**data) + async def get_zzz_diary( + self, + uid: typing.Optional[int] = None, + *, + month: typing.Optional[str] = None, + lang: typing.Optional[str] = None, + ) -> models.ZZZDiary: + """Get ZZZ inter-knot monthly earning data.""" + data = await self._request_zzz_record( + "month_info", uid, lang=lang, payload={"month": month or ""}, is_nap_ledger=True + ) + return models.ZZZDiary(**data) + + async def get_zzz_diary_detail( + self, + month: str, + *, + type: models.ZZZCurrencyType, + page: int = 1, + page_size: int = 20, + uid: typing.Optional[int] = None, + lang: typing.Optional[str] = None, + ) -> models.ZZZDiaryDetail: + """Get ZZZ inter-knot monthly earning data.""" + if not month: + raise ValueError("month is required.") + + data = await self._request_zzz_record( + "month_detail", + uid, + lang=lang, + payload={"month": month, "current_page": page, "type": type.value, "page_size": page_size}, + is_nap_ledger=True, + ) + return models.ZZZDiaryDetail(**data) + async def get_zzz_user( self, uid: typing.Optional[int] = None, diff --git a/genshin/client/routes.py b/genshin/client/routes.py index 46a5c73d..e2bc17f5 100644 --- a/genshin/client/routes.py +++ b/genshin/client/routes.py @@ -152,6 +152,8 @@ def get_url(self, region: types.Region, game: types.Game) -> yarl.URL: nap="https://api-takumi-record.mihoyo.com/event/game_record_zzz/api/zzz", ), ) +NAP_LEDGER_URL = Route("https://sg-public-api.hoyolab.com/event/nap_ledger") + CARD_WAPI_URL = InternationalRoute( overseas="https://bbs-api-os.hoyolab.com/game_record/card/wapi", chinese="https://api-takumi-record.mihoyo.com/game_record/app/card/wapi", diff --git a/genshin/models/zzz/chronicle/__init__.py b/genshin/models/zzz/chronicle/__init__.py index 3e5e3912..328e1e17 100644 --- a/genshin/models/zzz/chronicle/__init__.py +++ b/genshin/models/zzz/chronicle/__init__.py @@ -3,3 +3,4 @@ from .challenge import * from .notes import * from .stats import * +from .month_info import * diff --git a/genshin/models/zzz/chronicle/month_info.py b/genshin/models/zzz/chronicle/month_info.py new file mode 100644 index 00000000..a6206f08 --- /dev/null +++ b/genshin/models/zzz/chronicle/month_info.py @@ -0,0 +1,101 @@ +from enum import Enum +import typing +from genshin.models.model import APIModel, Aliased, DateTimeField + +__all__ = ( + "PolychromeIncomeType", + "PolychromeIncome", + "ZZZCurrencyType", + "ZZZIncomeCurrency", + "IncomeData", + "ZZZDiaryPlayerInfo", + "ZZZDiary", + "ZZZDiaryDetailItem", + "ZZZDiaryDetail", +) + + +class PolychromeIncomeType(Enum): + """Polychrome income type enum.""" + + DAILY = "daily_activity_rewards" + DEVELOPMENT = "growth_rewards" + SHIYU_DEFENSE = "shiyu_rewards" + MAIL = "mail_rewards" + HOLLOW_ZERO = "hollow_rewards" + EVENT = "event_rewards" + OTHER = "other_rewards" + + +class PolychromeIncome(APIModel): + """Polychrome income model.""" + + source: PolychromeIncomeType = Aliased("action") + num: int + percent: int + + +class ZZZCurrencyType(Enum): + """Currency type enum.""" + + POLYCHROME = "PolychromesData" + MASTER_TAPE = "MatserTapeData" + BOOPONS = "BooponsData" + + +class ZZZIncomeCurrency(APIModel): + """Currency model.""" + + type: ZZZCurrencyType = Aliased("data_type") + num: int = Aliased("count") + name: str = Aliased("data_name") + + +class IncomeData(APIModel): + """Income model.""" + + currencies: typing.Sequence[ZZZIncomeCurrency] = Aliased("list") + polychrome_incomes: typing.Sequence[PolychromeIncome] = Aliased("income_components") + + +class ZZZDiaryPlayerInfo(APIModel): + """Player info model.""" + + nickname: str + avatar_url: str = Aliased("avatar") + + +class ZZZDiary(APIModel): + """ZZZ monthly earnings model.""" + + uid: int + region: str + current_month: str + data_month: str + + income: IncomeData = Aliased("month_data") + month_options: typing.Sequence[str] = Aliased("optional_month") + player: ZZZDiaryPlayerInfo = Aliased("role_info") + + +class ZZZDiaryDetailItem(APIModel): + """ZZZ monthly earning detail item model.""" + + id: str + source: PolychromeIncomeType = Aliased("action") + time: DateTimeField + num: int + + +class ZZZDiaryDetail(APIModel): + """ZZZ monthly earning detail model.""" + + uid: int + region: str + data_month: str + current_page: int + total: int + items: typing.Sequence[ZZZDiaryDetailItem] = Aliased("list") + + currency_name: str = Aliased("data_name") + currency_type: ZZZCurrencyType = Aliased("data_type")