support aapi

This commit is contained in:
omg-xtao 2023-07-23 17:41:26 +08:00 committed by GitHub
parent 2e50bf2081
commit d3b3a4b62e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 164 additions and 11 deletions

View File

@ -24,6 +24,7 @@ class BaseChronicleClient(BaseClient):
async def request_game_record( async def request_game_record(
self, self,
endpoint: str, endpoint: str,
endpoint_type: str = "api",
data: Optional[Any] = None, data: Optional[Any] = None,
params: Optional[QueryParamTypes] = None, params: Optional[QueryParamTypes] = None,
lang: Optional[str] = None, lang: Optional[str] = None,
@ -34,6 +35,7 @@ class BaseChronicleClient(BaseClient):
Args: Args:
endpoint (str): The endpoint to send the request to. endpoint (str): The endpoint to send the request to.
endpoint_type (str, optional): The type of endpoint to send the request to.
data (Optional[Any], optional): The request payload. data (Optional[Any], optional): The request payload.
params (Optional[QueryParamTypes], optional): The query parameters for the request. params (Optional[QueryParamTypes], optional): The query parameters for the request.
lang (Optional[str], optional): The language for the response. lang (Optional[str], optional): The language for the response.
@ -51,7 +53,7 @@ class BaseChronicleClient(BaseClient):
base_url = RECORD_URL.get_url(region or self.region) base_url = RECORD_URL.get_url(region or self.region)
if game: if game:
base_url = base_url / game.value / "api" base_url = base_url / game.value / endpoint_type
url = base_url / endpoint url = base_url / endpoint
new_ds = self.region == Region.CHINESE new_ds = self.region == Region.CHINESE

View File

@ -2,17 +2,17 @@ import asyncio
from typing import Optional, Any, List, Dict from typing import Optional, Any, List, Dict
from simnet.client.components.chronicle.base import BaseChronicleClient from simnet.client.components.chronicle.base import BaseChronicleClient
from simnet.errors import DataNotPublic, BadRequest from simnet.errors import DataNotPublic, BadRequest, RegionNotSupported
from simnet.models.genshin.chronicle.abyss import SpiralAbyss, SpiralAbyssPair from simnet.models.genshin.chronicle.abyss import SpiralAbyss, SpiralAbyssPair
from simnet.models.genshin.chronicle.characters import Character from simnet.models.genshin.chronicle.characters import Character
from simnet.models.genshin.chronicle.notes import Notes from simnet.models.genshin.chronicle.notes import Notes, NotesWidget
from simnet.models.genshin.chronicle.stats import ( from simnet.models.genshin.chronicle.stats import (
PartialGenshinUserStats, PartialGenshinUserStats,
GenshinUserStats, GenshinUserStats,
FullGenshinUserStats, FullGenshinUserStats,
) )
from simnet.models.lab.record import RecordCard from simnet.models.lab.record import RecordCard
from simnet.utils.enum_ import Game from simnet.utils.enum_ import Game, Region
from simnet.utils.player import recognize_genshin_server, recognize_region from simnet.utils.player import recognize_genshin_server, recognize_region
__all__ = ("GenshinBattleChronicleClient",) __all__ = ("GenshinBattleChronicleClient",)
@ -30,6 +30,7 @@ class GenshinBattleChronicleClient(BaseChronicleClient):
endpoint: str, endpoint: str,
player_id: Optional[int] = None, player_id: Optional[int] = None,
method: str = "GET", method: str = "GET",
endpoint_type: str = "api",
lang: Optional[str] = None, lang: Optional[str] = None,
payload: Optional[Dict[str, Any]] = None, payload: Optional[Dict[str, Any]] = None,
): ):
@ -37,6 +38,7 @@ class GenshinBattleChronicleClient(BaseChronicleClient):
Args: Args:
endpoint (str): The endpoint of the object to retrieve. endpoint (str): The endpoint of the object to retrieve.
endpoint_type (str, optional): The type of endpoint to send the request to.
player_id (Optional[int], optional): The player ID. Defaults to None. player_id (Optional[int], optional): The player ID. Defaults to None.
method (str, optional): The HTTP method to use. Defaults to "GET". method (str, optional): The HTTP method to use. Defaults to "GET".
lang (Optional[str], optional): The language of the data. Defaults to None. lang (Optional[str], optional): The language of the data. Defaults to None.
@ -68,6 +70,7 @@ class GenshinBattleChronicleClient(BaseChronicleClient):
return await self.request_game_record( return await self.request_game_record(
endpoint, endpoint,
endpoint_type=endpoint_type,
lang=lang, lang=lang,
game=Game.GENSHIN, game=Game.GENSHIN,
region=recognize_region(player_id, game=Game.GENSHIN), region=recognize_region(player_id, game=Game.GENSHIN),
@ -172,7 +175,7 @@ class GenshinBattleChronicleClient(BaseChronicleClient):
autoauth (bool, optional): Whether to automatically authenticate the user. Defaults to True. autoauth (bool, optional): Whether to automatically authenticate the user. Defaults to True.
Returns: Returns:
StarRailNote: The requested real-time notes. Notes: The requested real-time notes.
Raises: Raises:
BadRequest: If the request is invalid. BadRequest: If the request is invalid.
@ -258,3 +261,32 @@ class GenshinBattleChronicleClient(BaseChronicleClient):
return record_card return record_card
return None return None
async def get_genshin_notes_by_stoken(
self,
lang: Optional[str] = None,
) -> NotesWidget:
"""Get Genshin's real-time notes.
Args:
lang (Optional[str], optional): The language of the data. Defaults to None.
Returns:
NotesWidget: The requested real-time notes.
Raises:
RegionNotSupported: If the region is not supported.
BadRequest: If the request is invalid.
"""
if self.region == Region.OVERSEAS:
raise RegionNotSupported("Notes widget is not supported in overseas region.")
stoken = self.cookies.get("stoken")
if stoken is None:
raise ValueError("stoken not found in cookies.")
stuid = self.cookies.get("stuid")
if stuid is None and self.account_id is None:
raise ValueError("account_id or stuid not found")
if self.account_id is not None and stuid is None:
self.cookies.set("stuid", str(self.account_id))
data = await self._request_genshin_record("widget/v2", endpoint_type="aapi", lang=lang)
return NotesWidget(**data)

View File

@ -2,16 +2,16 @@ import asyncio
from typing import Optional, Mapping, Dict, Any from typing import Optional, Mapping, Dict, Any
from simnet.client.components.chronicle.base import BaseChronicleClient from simnet.client.components.chronicle.base import BaseChronicleClient
from simnet.errors import BadRequest, DataNotPublic from simnet.errors import BadRequest, DataNotPublic, RegionNotSupported
from simnet.models.lab.record import RecordCard from simnet.models.lab.record import RecordCard
from simnet.models.starrail.chronicle.activity import StarRailActivity from simnet.models.starrail.chronicle.activity import StarRailActivity
from simnet.models.starrail.chronicle.challenge import StarRailChallenge from simnet.models.starrail.chronicle.challenge import StarRailChallenge
from simnet.models.starrail.chronicle.characters import StarRailDetailCharacters from simnet.models.starrail.chronicle.characters import StarRailDetailCharacters
from simnet.models.starrail.chronicle.museum import StarRailMuseumBasic, StarRailMuseumDetail from simnet.models.starrail.chronicle.museum import StarRailMuseumBasic, StarRailMuseumDetail
from simnet.models.starrail.chronicle.notes import StarRailNote from simnet.models.starrail.chronicle.notes import StarRailNote, StarRailNoteWidget
from simnet.models.starrail.chronicle.rogue import StarRailRogue from simnet.models.starrail.chronicle.rogue import StarRailRogue
from simnet.models.starrail.chronicle.stats import StarRailUserStats, StarRailUserInfo from simnet.models.starrail.chronicle.stats import StarRailUserStats, StarRailUserInfo
from simnet.utils.enum_ import Game from simnet.utils.enum_ import Game, Region
from simnet.utils.player import recognize_starrail_server, recognize_region from simnet.utils.player import recognize_starrail_server, recognize_region
__all__ = ("StarRailBattleChronicleClient",) __all__ = ("StarRailBattleChronicleClient",)
@ -28,6 +28,7 @@ class StarRailBattleChronicleClient(BaseChronicleClient):
self, self,
endpoint: str, endpoint: str,
player_id: Optional[int] = None, player_id: Optional[int] = None,
endpoint_type: str = "api",
method: str = "GET", method: str = "GET",
lang: Optional[str] = None, lang: Optional[str] = None,
payload: Optional[Dict[str, Any]] = None, payload: Optional[Dict[str, Any]] = None,
@ -61,6 +62,7 @@ class StarRailBattleChronicleClient(BaseChronicleClient):
return await self.request_game_record( return await self.request_game_record(
endpoint, endpoint,
endpoint_type=endpoint_type,
lang=lang, lang=lang,
game=Game.STARRAIL, game=Game.STARRAIL,
region=recognize_region(player_id, game=Game.STARRAIL), region=recognize_region(player_id, game=Game.STARRAIL),
@ -287,3 +289,32 @@ class StarRailBattleChronicleClient(BaseChronicleClient):
""" """
data = await self._request_starrail_record("activity", uid, lang=lang) data = await self._request_starrail_record("activity", uid, lang=lang)
return StarRailActivity(**data) return StarRailActivity(**data)
async def get_starrail_notes_by_stoken(
self,
lang: Optional[str] = None,
) -> StarRailNoteWidget:
"""Get StarRail's real-time notes.
Args:
lang (Optional[str], optional): The language of the data. Defaults to None.
Returns:
StarRailNoteWidget: The requested real-time notes.
Raises:
RegionNotSupported: If the region is not supported.
BadRequest: If the request is invalid.
"""
if self.region == Region.OVERSEAS:
raise RegionNotSupported("Notes widget is not supported in overseas region.")
stoken = self.cookies.get("stoken")
if stoken is None:
raise ValueError("stoken not found in cookies.")
stuid = self.cookies.get("stuid")
if stuid is None and self.account_id is None:
raise ValueError("account_id or stuid not found")
if self.account_id is not None and stuid is None:
self.cookies.set("stuid", str(self.account_id))
data = await self._request_starrail_record("widget", endpoint_type="aapi", lang=lang)
return StarRailNoteWidget(**data)

View File

@ -11,7 +11,6 @@ from simnet.client.components.wish.genshin import GenshinWishClient
from simnet.utils.enum_ import Region from simnet.utils.enum_ import Region
from simnet.utils.types import CookieTypes, HeaderTypes, TimeoutTypes from simnet.utils.types import CookieTypes, HeaderTypes, TimeoutTypes
class GenshinClient( class GenshinClient(
CalculatorClient, CalculatorClient,
GenshinBattleChronicleClient, GenshinBattleChronicleClient,

View File

@ -9,7 +9,6 @@ from simnet.client.components.wish.starrail import StarRailWishClient
from simnet.utils.enum_ import Region from simnet.utils.enum_ import Region
from simnet.utils.types import CookieTypes, HeaderTypes, TimeoutTypes from simnet.utils.types import CookieTypes, HeaderTypes, TimeoutTypes
class StarRailClient( class StarRailClient(
StarRailBattleChronicleClient, StarRailWishClient, StarrailDiaryClient, DailyRewardClient, AuthClient, LabClient StarRailBattleChronicleClient, StarRailWishClient, StarrailDiaryClient, DailyRewardClient, AuthClient, LabClient
): ):

View File

@ -5,7 +5,7 @@ from pydantic import Field, root_validator
from simnet.models.base import APIModel from simnet.models.base import APIModel
__all__ = ("Expedition", "Notes") __all__ = ("Expedition", "Notes", "ExpeditionWidget", "NotesWidget")
def _process_timedelta(time: Union[int, timedelta, datetime]) -> datetime: def _process_timedelta(time: Union[int, timedelta, datetime]) -> datetime:
@ -184,3 +184,55 @@ class Notes(APIModel):
raise ValueError("Transformer recovery time cannot exceed 7 days.") raise ValueError("Transformer recovery time cannot exceed 7 days.")
return values return values
class ExpeditionWidget(APIModel):
"""The model for a real-time expedition.
Attributes:
character (str): The expedition character icon url.
status (Literal["Ongoing", "Finished"]): The status of the expedition.
"""
character: str = Field(alias="avatar_side_icon")
status: Literal["Ongoing", "Finished"]
class NotesWidget(APIModel):
"""The model for real-time notes.
Attributes:
current_resin (int): The current amount of resin.
max_resin (int): The maximum amount of resin.
remaining_resin_recovery_time (timedelta): The remaining time until resin recovery.
current_realm_currency (int): The current amount of realm currency.
max_realm_currency (int): The maximum amount of realm currency.
completed_commissions (int): The number of completed commissions.
max_commissions (int): The maximum number of commissions.
claimed_commission_reward (bool): Whether the commission reward has been claimed.
expeditions (List[Expedition]): The list of expeditions.
max_expeditions (int): The maximum number of expeditions.
Raises:
ValueError: If the remaining resin recovery time is less than 0 or greater than 8 hours,
or if the remaining realm currency recovery time is less than 0 or greater than 24 hours.
"""
current_resin: int
max_resin: int
remaining_resin_recovery_time: timedelta = Field(alias="resin_recovery_time")
current_realm_currency: int = Field(alias="current_home_coin")
max_realm_currency: int = Field(alias="max_home_coin")
completed_commissions: int = Field(alias="finished_task_num")
max_commissions: int = Field(alias="total_task_num")
claimed_commission_reward: bool = Field(alias="is_extra_task_reward_received")
expeditions: List[ExpeditionWidget]
max_expeditions: int = Field(alias="max_expedition_num")
@property
def resin_recovery_time(self) -> datetime:
"""A property that returns the time when resin will be fully recovered."""
return datetime.now().astimezone() + self.remaining_resin_recovery_time

View File

@ -72,3 +72,41 @@ class StarRailNote(APIModel):
"""Remaining echo of war rewards""" """Remaining echo of war rewards"""
max_weekly_discounts: int = Field(alias="weekly_cocoon_limit") max_weekly_discounts: int = Field(alias="weekly_cocoon_limit")
"""Echo of war attempt limit""" """Echo of war attempt limit"""
class StarRailNoteWidget(APIModel):
"""Represents a StarRail Note.
Attributes:
current_stamina (int): The current stamina of the user.
max_stamina (int): The maximum stamina of the user.
stamina_recover_time (timedelta): The time it takes for one stamina to recover.
accepted_expedition_num (int): The number of expeditions the user has accepted.
total_expedition_num (int): The total number of expeditions the user has participated in.
expeditions (Sequence[StarRailExpedition]): A list of expeditions the user has participated in.
current_train_score (int): The current daily training activity.
max_train_score (int): The max daily training activity.
current_rogue_score (int): The current simulated universe weekly points.
max_rogue_score (int): The max simulated universe weekly points.
has_signed (bool): Whether the user has signed in today.
"""
current_stamina: int
max_stamina: int
stamina_recover_time: timedelta
accepted_expedition_num: int
total_expedition_num: int
expeditions: Sequence[StarRailExpedition]
current_train_score: int
"""Current daily training activity"""
max_train_score: int
"""Max daily training activity"""
current_rogue_score: int
"""Current simulated universe weekly points"""
max_rogue_score: int
"""Max simulated universe weekly points"""
has_signed: bool
"""Whether the user has signed in today"""