Support detailed Genshin character endpoint

This commit is contained in:
omg-xtao 2024-08-22 22:48:46 +08:00 committed by GitHub
parent b38d5f72b0
commit 0a707db982
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 193 additions and 0 deletions

View File

@ -5,6 +5,7 @@ from simnet.client.components.chronicle.base import BaseChronicleClient
from simnet.client.routes import RECORD_URL from simnet.client.routes import RECORD_URL
from simnet.errors import DataNotPublic, BadRequest from simnet.errors import DataNotPublic, BadRequest
from simnet.models.genshin.chronicle.abyss import SpiralAbyss, SpiralAbyssPair from simnet.models.genshin.chronicle.abyss import SpiralAbyss, SpiralAbyssPair
from simnet.models.genshin.chronicle.character_detail import GenshinCharacterListInfo, GenshinDetailCharacters
from simnet.models.genshin.chronicle.characters import Character from simnet.models.genshin.chronicle.characters import Character
from simnet.models.genshin.chronicle.img_theater import ImgTheater from simnet.models.genshin.chronicle.img_theater import ImgTheater
from simnet.models.genshin.chronicle.notes import Notes, NotesWidget, NotesOverseaWidget from simnet.models.genshin.chronicle.notes import Notes, NotesWidget, NotesOverseaWidget
@ -323,3 +324,47 @@ class GenshinBattleChronicleClient(BaseChronicleClient):
data = await self._request_genshin_record("widget/v2", endpoint_type="aapi", lang=lang) data = await self._request_genshin_record("widget/v2", endpoint_type="aapi", lang=lang)
model = NotesWidget model = NotesWidget
return model(**data) return model(**data)
async def get_genshin_character_list(
self,
player_id: Optional[int] = None,
*,
lang: Optional[str] = None,
) -> List[GenshinCharacterListInfo]:
"""Retrieve a list of Genshin Impact character information for a player.
Args:
player_id (Optional[int]): The ID of the player. Defaults to None.
lang (Optional[str]): The language for the character information. Defaults to None.
Returns:
List[GenshinCharacterListInfo]: A list of GenshinCharacterListInfo objects containing character details.
"""
data = await self._request_genshin_record("character/list", player_id, method="POST", lang=lang)
return [GenshinCharacterListInfo(**i) for i in data["list"]]
async def get_genshin_character_detail(
self,
characters: List[int],
player_id: Optional[int] = None,
*,
lang: Optional[str] = None,
) -> GenshinDetailCharacters:
"""Retrieve detailed information about Genshin Impact characters.
Args:
characters (List[int]): The IDs of the characters to retrieve details for.
player_id (Optional[int]): The ID of the player. Defaults to None.
lang (Optional[str]): The language for the character information. Defaults to None.
Returns:
GenshinDetailCharacters: An object containing detailed information.
"""
ids = [characters] if isinstance(characters, int) else characters
payload = {"character_ids": ids}
data = await self._request_genshin_record(
"character/detail", player_id, method="POST", lang=lang, payload=payload
)
return GenshinDetailCharacters(**data)

View File

@ -0,0 +1,143 @@
import enum
import typing
import pydantic
from pydantic import Field
from simnet.models.base import APIModel
from simnet.models.genshin.chronicle.characters import (
PartialCharacter,
CharacterWeapon,
Outfit,
Constellation,
Artifact,
)
class GenshinWeaponType(enum.IntEnum):
"""Character weapon types."""
SWORD = 1
CATALYST = 10
CLAYMORE = 11
BOW = 12
POLEARM = 13
class GenshinCharacterListInfoWeapon(APIModel):
"""A class representing information about a Genshin Impact character's weapon."""
id: int
icon: str
type: GenshinWeaponType
rarity: int
level: int
affix_level: int
class GenshinCharacterListInfo(PartialCharacter):
"""A class representing detailed information about a Genshin Impact character."""
icon: str
image: str
side_icon: str
weapon_type: GenshinWeaponType
weapon: GenshinCharacterListInfoWeapon
class PropInfo(APIModel):
"""A property such as Crit Rate, HP, HP%."""
type: int = Field(alias="property_type")
name: str
icon: typing.Optional[str]
filter_name: str
@pydantic.validator("name", "filter_name")
@classmethod
def __fix_names(cls, value: str) -> str: # skipcq: PTC-W0038
r"""Fix "\xa0" in Crit Damage + Crit Rate names."""
return value.replace("\xa0", " ")
class PropertyValue(APIModel):
"""A property with a value."""
property_type: int
base: str
add: str
final: str
class DetailCharacterWeapon(CharacterWeapon):
"""Detailed Genshin Weapon with main/sub stats."""
type: GenshinWeaponType
type_name: str
main_property: PropertyValue
sub_property: typing.Optional[PropertyValue] = None
class ArtifactProperty(APIModel):
"""Artifact's Property value & roll count."""
property_type: int
value: str
times: int
class DetailArtifact(Artifact):
"""Detailed artifact with main/sub stats."""
main_property: ArtifactProperty
sub_property_list: typing.Sequence[ArtifactProperty]
class SkillAffix(APIModel):
"""Skill affix texts."""
name: str
value: str
class CharacterSkill(APIModel):
"""Character's skill."""
id: int = Field(alias="skill_id")
skill_type: int
name: str
level: int
description: str = Field(alias="desc")
affixes: typing.Sequence[SkillAffix] = Field(alias="skill_affix_list")
icon: str
is_unlocked: bool = Field(alias="is_unlock")
class GenshinDetailCharacter(APIModel):
"""Full Detailed Genshin Character"""
base: GenshinCharacterListInfo
weapon: DetailCharacterWeapon
artifacts: typing.Sequence[DetailArtifact] = Field(alias="relics")
constellations: typing.Sequence[Constellation]
costumes: typing.Sequence[Outfit]
skills: typing.Sequence[CharacterSkill]
selected_properties: typing.Sequence[PropertyValue]
base_properties: typing.Sequence[PropertyValue]
extra_properties: typing.Sequence[PropertyValue]
element_properties: typing.Sequence[PropertyValue]
class GenshinDetailCharacters(APIModel):
"""Genshin character list."""
characters: typing.Sequence[GenshinDetailCharacter] = Field(alias="list")
property_map: typing.Mapping[str, PropInfo]
relic_property_options: typing.Mapping[str, typing.Sequence[int]]

View File

@ -54,3 +54,8 @@ class TestGenshinBattleChronicleClient:
async def test_get_genshin_imaginarium_theater(genshin_client: GenshinBattleChronicleClient): async def test_get_genshin_imaginarium_theater(genshin_client: GenshinBattleChronicleClient):
data = await genshin_client.get_genshin_imaginarium_theater() data = await genshin_client.get_genshin_imaginarium_theater()
assert len(data.data) > 0 assert len(data.data) > 0
@staticmethod
async def test_get_genshin_character_list(genshin_client: GenshinBattleChronicleClient):
data = await genshin_client.get_genshin_character_list()
assert len(data) > 0