Add more starrail func

This commit is contained in:
omg-xtao 2023-06-09 22:55:51 +08:00 committed by GitHub
parent a92a7f84f8
commit 9aaaec2d88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 294 additions and 116 deletions

View File

@ -69,7 +69,8 @@ class BaseClient(AsyncContextManager["BaseClient"]):
write=5.0, write=5.0,
pool=1.0, pool=1.0,
) )
cookies = Cookies(parse_cookie(cookies)) if isinstance(cookies, str) else cookies cookies = parse_cookie(cookies) if isinstance(cookies, str) else cookies
cookies = Cookies(cookies)
self.headers = Headers(headers) self.headers = Headers(headers)
self.player_id = player_id self.player_id = player_id
self.account_id = account_id or cookies.account_id self.account_id = account_id or cookies.account_id

View File

@ -87,7 +87,7 @@ class BaseChronicleClient(BaseClient):
if game is None and switch_id == 3: if game is None and switch_id == 3:
game = Game.GENSHIN game = Game.GENSHIN
game_id = {Game.HONKAI: 1, Game.GENSHIN: 2, Game.STARRAIL: 3}[game] game_id = {Game.HONKAI: 1, Game.GENSHIN: 2, Game.STARRAIL: 6}[game]
await self.request_game_record( await self.request_game_record(
"card/wapi/changeDataSwitch", "card/wapi/changeDataSwitch",

View File

@ -4,9 +4,11 @@ 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
from simnet.models.lab.record import RecordCard from simnet.models.lab.record import RecordCard
from simnet.models.starrail.chronicle.characters import StarShipDetailCharacters from simnet.models.starrail.chronicle.challenge import StarRailChallenge
from simnet.models.starrail.chronicle.characters import StarRailDetailCharacters
from simnet.models.starrail.chronicle.notes import StarRailNote from simnet.models.starrail.chronicle.notes import StarRailNote
from simnet.models.starrail.chronicle.stats import StarRailUserStats from simnet.models.starrail.chronicle.rogue import StarRailRogue
from simnet.models.starrail.chronicle.stats import StarRailUserStats, StarRailUserInfo
from simnet.utils.enum_ import Game from simnet.utils.enum_ import Game
from simnet.utils.player import recognize_starrail_server, recognize_region from simnet.utils.player import recognize_starrail_server, recognize_region
@ -92,6 +94,7 @@ class StarRailBattleChronicleClient(BaseChronicleClient):
raise BadRequest(e.response, "Cannot view real-time notes of other users.") from e raise BadRequest(e.response, "Cannot view real-time notes of other users.") from e
if not autoauth: if not autoauth:
raise BadRequest(e.response, "Real-time notes are not enabled.") from e raise BadRequest(e.response, "Real-time notes are not enabled.") from e
await self.update_settings(3, True, game=Game.STARRAIL)
data = await self._request_starrail_record("note", player_id, lang=lang) data = await self._request_starrail_record("note", player_id, lang=lang)
return StarRailNote(**data) return StarRailNote(**data)
@ -119,14 +122,14 @@ class StarRailBattleChronicleClient(BaseChronicleClient):
self._request_starrail_record("index", player_id, lang=lang), self._request_starrail_record("index", player_id, lang=lang),
self._request_starrail_record("role/basicInfo", player_id, lang=lang), self._request_starrail_record("role/basicInfo", player_id, lang=lang),
) )
index_data["info"] = basic_info basic_data = StarRailUserInfo(**basic_info)
return StarRailUserStats(**index_data) return StarRailUserStats(**index_data, info=basic_data)
async def get_starrail_characters( async def get_starrail_characters(
self, self,
player_id: Optional[int] = None, player_id: Optional[int] = None,
lang: Optional[str] = None, lang: Optional[str] = None,
) -> StarShipDetailCharacters: ) -> StarRailDetailCharacters:
"""Get StarRail character information. """Get StarRail character information.
Args: Args:
@ -134,7 +137,7 @@ class StarRailBattleChronicleClient(BaseChronicleClient):
lang (Optional[str], optional): The language of the data. Defaults to None. lang (Optional[str], optional): The language of the data. Defaults to None.
Returns: Returns:
StarShipDetailCharacters: The requested character information. StarRailDetailCharacters: The requested character information.
Raises: Raises:
BadRequest: If the request is invalid. BadRequest: If the request is invalid.
@ -142,7 +145,7 @@ class StarRailBattleChronicleClient(BaseChronicleClient):
""" """
payload = {"need_wiki": "true"} payload = {"need_wiki": "true"}
data = await self._request_starrail_record("avatar/info", player_id, lang=lang, payload=payload) data = await self._request_starrail_record("avatar/info", player_id, lang=lang, payload=payload)
return StarShipDetailCharacters(**data) return StarRailDetailCharacters(**data)
async def get_record_card( async def get_record_card(
self, self,
@ -171,3 +174,51 @@ class StarRailBattleChronicleClient(BaseChronicleClient):
return record_card return record_card
return None return None
async def get_starrail_challenge(
self,
player_id: Optional[int] = None,
previous: bool = False,
lang: Optional[str] = None,
) -> StarRailChallenge:
"""Get starrail challenge runs.
Args:
player_id (Optional[int], optional): The player ID. Defaults to None.
previous (bool, optional): Whether to get previous runs. Defaults to False.
lang (Optional[str], optional): The language of the data. Defaults to None.
Returns:
StarRailChallenge: The requested challenge runs.
Raises:
BadRequest: If the request is invalid.
DataNotPublic: If the requested data is not public.
"""
payload = dict(schedule_type=2 if previous else 1, need_all="true")
data = await self._request_starrail_record("challenge", player_id, lang=lang, payload=payload)
return StarRailChallenge(**data)
async def get_starrail_rogue(
self,
player_id: Optional[int] = None,
schedule_type: int = 3,
lang: Optional[str] = None,
) -> StarRailRogue:
"""Get starrail rogue runs.
Args:
player_id (Optional[int], optional): The player ID. Defaults to None.
schedule_type (int, optional): The schedule type. Defaults to 3.
lang (Optional[str], optional): The language of the data. Defaults to None.
Returns:
StarRailRogue: The requested rogue runs.
Raises:
BadRequest: If the request is invalid.
DataNotPublic: If the requested data is not public.
"""
payload = dict(schedule_type=schedule_type, need_detail="true")
data = await self._request_starrail_record("rogue", player_id, lang=lang, payload=payload)
return StarRailRogue(**data)

View File

@ -1,19 +1,31 @@
"""Starrail base character model."""
from simnet.models.base import APIModel from simnet.models.base import APIModel
class BaseCharacter(APIModel): class StarRailBaseCharacter(APIModel):
""" """Base character model."""
A class representing a character in a game.
Attributes:
id (:obj:`int`): The unique identifier of the character.
name (:obj:`str`): The name of the character.
element (:obj:`str`): The element that the character represents (e.g. fire, water, etc.).
rarity (:obj:`int`): The rarity of the character (e.g. 1-5 stars).
"""
id: int id: int
name: str
element: str element: str
rarity: int rarity: int
icon: str icon: str
class StarRailPartialCharacter(StarRailBaseCharacter):
"""Character without any equipment."""
name: str
level: int
rank: int
class FloorCharacter(StarRailBaseCharacter):
"""Character in a floor."""
level: int
class RogueCharacter(StarRailBaseCharacter):
"""Rogue character model."""
level: int

View File

@ -0,0 +1,18 @@
"""Starrail Chronicle Base Model."""
import datetime
from simnet.models.base import APIModel
class PartialTime(APIModel):
"""Partial time model."""
year: int
month: int
day: int
hour: int
minute: int
@property
def datetime(self) -> datetime.datetime:
return datetime.datetime(self.year, self.month, self.day, self.hour, self.minute)

View File

@ -0,0 +1,44 @@
"""Starrail chronicle challenge."""
from typing import List
from pydantic import Field
from simnet.models.base import APIModel
from simnet.models.starrail.character import FloorCharacter
from .base import PartialTime
__all__ = ["StarRailFloor", "FloorNode", "StarRailChallenge"]
class FloorNode(APIModel):
"""Node for a floor."""
challenge_time: PartialTime
avatars: List[FloorCharacter]
class StarRailFloor(APIModel):
"""Floor in a challenge."""
name: str
round_num: int
star_num: int
node_1: FloorNode
node_2: FloorNode
is_chaos: bool
class StarRailChallenge(APIModel):
"""Challenge in a season."""
season: int = Field(alias="schedule_id")
begin_time: PartialTime
end_time: PartialTime
total_stars: int = Field(alias="star_num")
max_floor: str
total_battles: int = Field(alias="battle_num")
has_data: bool
floors: List[StarRailFloor] = Field(alias="all_floor_detail")

View File

@ -1,32 +1,21 @@
from typing import Optional, List """Starrail chronicle character."""
from typing import List, Optional
from simnet.models.base import APIModel from simnet.models.base import APIModel
from simnet.models.starrail.character import BaseCharacter
from .. import character
__all__ = [
"StarRailEquipment",
"Rank",
"Relic",
"StarRailDetailCharacter",
"StarRailDetailCharacters",
]
class PartialCharacter(BaseCharacter): class StarRailEquipment(APIModel):
"""A character without any equipment. """Character equipment."""
Attributes:
level (int): The level of the character.
rank (int): The rank of the character.
"""
level: int
rank: int
class Equipment(APIModel):
"""An equipment model used in StarRailDetailCharacter.
Attributes:
id (int): The ID of the equipment.
level (int): The level of the equipment.
rank (int): The rank of the equipment.
name (str): The name of the equipment.
desc (str): The description of the equipment.
icon (str): The icon of the equipment.
"""
id: int id: int
level: int level: int
@ -37,17 +26,7 @@ class Equipment(APIModel):
class Relic(APIModel): class Relic(APIModel):
"""A relic model used in StarRailDetailCharacter. """Character relic."""
Attributes:
id (int): The ID of the relic.
level (int): The level of the relic.
pos (int): The position of the relic.
name (str): The name of the relic.
desc (str): The description of the relic.
icon (str): The icon of the relic.
rarity (int): The rarity of the relic.
"""
id: int id: int
level: int level: int
@ -59,16 +38,7 @@ class Relic(APIModel):
class Rank(APIModel): class Rank(APIModel):
"""A rank model used in StarRailDetailCharacter. """Character rank."""
Attributes:
id (int): The ID of the rank.
pos (int): The position of the rank.
name (str): The name of the rank.
icon (str): The icon of the rank.
desc (str): The description of the rank.
is_unlocked (bool): Whether the rank is unlocked.
"""
id: int id: int
pos: int pos: int
@ -78,29 +48,17 @@ class Rank(APIModel):
is_unlocked: bool is_unlocked: bool
class StarRailDetailCharacter(PartialCharacter): class StarRailDetailCharacter(character.StarRailPartialCharacter):
"""A detailed character model used in StarShipDetailCharacters. """StarRail character with equipment and relics."""
Attributes:
image (str): The image of the character.
equip (Optional[Equipment]): The equipment of the character, if any.
relics (List[Relic]): The relics of the character.
ornaments (List[Relic]): The ornaments of the character.
ranks (List[Rank]): The ranks of the character.
"""
image: str image: str
equip: Optional[Equipment] equip: Optional[StarRailEquipment]
relics: List[Relic] relics: List[Relic]
ornaments: List[Relic] ornaments: List[Relic]
ranks: List[Rank] ranks: List[Rank]
class StarShipDetailCharacters(APIModel): class StarRailDetailCharacters(APIModel):
"""A model containing a list of detailed characters used in the StarShipDetail API. """StarRail characters."""
Attributes:
avatar_list (List[StarRailDetailCharacter]): The list of detailed characters.
"""
avatar_list: List[StarRailDetailCharacter] avatar_list: List[StarRailDetailCharacter]

View File

@ -0,0 +1,96 @@
"""Starrail Rogue models."""
from typing import List
from simnet.models.base import APIModel
from ..character import RogueCharacter
from .base import PartialTime
class RogueUserRole(APIModel):
"""Rogue User info."""
nickname: str
server: str
level: int
class RogueBasicInfo(APIModel):
"""generalized rogue basic info."""
unlocked_buff_num: int
unlocked_miracle_num: int
unlocked_skill_points: int
class RogueRecordBasic(APIModel):
"""Basic record info."""
id: int
finish_cnt: int
schedule_begin: PartialTime
schedule_end: PartialTime
class RogueBuffType(APIModel):
"""Rogue buff type."""
id: int
name: str
cnt: int
class RogueBuffItem(APIModel):
"""Rogue buff item."""
id: int
name: str
is_evoluted: bool
rank: int
class RogueBuff(APIModel):
"""Rogue buff info."""
base_type: RogueBuffType
items: List[RogueBuffItem]
class RogueMiracle(APIModel):
"""Rogue miracle info."""
id: int
name: str
icon: str
class RogueRecordDetail(APIModel):
"""Detailed record info."""
name: str
finish_time: PartialTime
score: int
final_lineup: List[RogueCharacter]
base_type_list: List[RogueBuffType]
cached_avatars: List[RogueCharacter]
buffs: List[RogueBuff]
miracles: List[RogueMiracle]
difficulty: int
progress: int
class RogueRecord(APIModel):
"""generic record data."""
basic: RogueRecordBasic
records: List[RogueRecordDetail]
has_data: bool
class StarRailRogue(APIModel):
"""generic rogue data."""
role: RogueUserRole
basic_info: RogueBasicInfo
current_record: RogueRecord
last_record: RogueRecord

View File

@ -1,20 +1,22 @@
from typing import List """Starrail chronicle stats."""
import typing
from pydantic import Field from pydantic import Field
from simnet.models.base import APIModel from simnet.models.base import APIModel
from simnet.models.starrail.chronicle.characters import PartialCharacter
from .. import character
__all__ = [
"PartialStarRailUserStats",
"StarRailUserInfo",
"StarRailUserStats",
"StarRailStats",
]
class Stats(APIModel): class StarRailStats(APIModel):
""" """Overall user stats."""
Statistics of user data.
Attributes:
active_days (int): Number of days the user has been active.
avatar_num (int): Number of avatars the user has.
achievement_num (int): Number of achievements the user has earned.
chest_num (int): Number of chests the user has opened.
abyss_process (str): Progress of the user in the abyss mode.
"""
active_days: int active_days: int
avatar_num: int avatar_num: int
@ -24,28 +26,14 @@ class Stats(APIModel):
class PartialStarRailUserStats(APIModel): class PartialStarRailUserStats(APIModel):
""" """User stats with characters without equipment."""
Partial data of StarRail user, containing statistics and character information.
Attributes: stats: StarRailStats
stats (Stats): Statistics of user data. characters: typing.Sequence[character.StarRailPartialCharacter] = Field(alias="avatar_list")
characters (List[PartialCharacter]): List of user's avatars/characters.
"""
stats: Stats
characters: List[PartialCharacter] = Field(alias="avatar_list")
class StarRailUserInfo(APIModel): class StarRailUserInfo(APIModel):
""" """User info."""
Information of StarRail user.
Attributes:
nickname (str): User's nickname.
server (str): User's server.
level (int): User's level.
avatar (str): User's avatar url.
"""
nickname: str nickname: str
server: str = Field(alias="region") server: str = Field(alias="region")
@ -54,6 +42,6 @@ class StarRailUserInfo(APIModel):
class StarRailUserStats(PartialStarRailUserStats): class StarRailUserStats(PartialStarRailUserStats):
"""Complete data of StarRail user, containing statistics and character information.""" """User stats."""
info: StarRailUserInfo info: StarRailUserInfo

View File

@ -11,7 +11,7 @@ UID_RANGE: Mapping[Game, Mapping[Region, Sequence[int]]] = {
}, },
Game.STARRAIL: { Game.STARRAIL: {
Region.OVERSEAS: (6, 7, 8, 9), Region.OVERSEAS: (6, 7, 8, 9),
Region.CHINESE: (1, 2), Region.CHINESE: (1, 2, 5),
}, },
Game.HONKAI: { Game.HONKAI: {
Region.OVERSEAS: (1, 2), Region.OVERSEAS: (1, 2),

View File

@ -45,3 +45,13 @@ class TestStarrailBattleChronicleClient:
assert len(characters.avatar_list) > 0 assert len(characters.avatar_list) > 0
character = characters.avatar_list[-1] character = characters.avatar_list[-1]
assert character.id > 0 assert character.id > 0
@staticmethod
async def test_get_starrail_challenge(starrail_client: "StarRailBattleChronicleClient"):
challenge = await starrail_client.get_starrail_challenge()
assert challenge.season > 0
@staticmethod
async def test_get_starrail_rogue(starrail_client: "StarRailBattleChronicleClient"):
rogue = await starrail_client.get_starrail_rogue()
assert rogue.role is not None