mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2024-12-22 23:57:26 +08:00
feat: Update to version 1.1
- Add UserNotFound and InvalidParams exception. - The API has changed its data format. - Updated the model to accommodate the new format. - Old format models have been moved to "models.v1". - Use the "fetch_user_v1" function to retrieve data in the old format.
This commit is contained in:
parent
8dcd3b62be
commit
4a892d213b
@ -3,8 +3,9 @@ from enum import Enum
|
||||
|
||||
import aiohttp
|
||||
|
||||
from .errors import HttpRequestError
|
||||
from .errors import HttpRequestError, InvalidParams, UserNotFound
|
||||
from .models import StarrailInfoParsed
|
||||
from .models.v1 import StarrailInfoParsedV1
|
||||
from .tools import remove_empty_dict, replace_trailblazer_name
|
||||
|
||||
|
||||
@ -48,6 +49,8 @@ class MihomoAPI:
|
||||
self,
|
||||
uid: int | str,
|
||||
language: Language,
|
||||
*,
|
||||
params: dict[str, str] = {},
|
||||
) -> typing.Any:
|
||||
"""
|
||||
Makes an HTTP request to the API.
|
||||
@ -61,17 +64,31 @@ class MihomoAPI:
|
||||
|
||||
Raises:
|
||||
HttpRequestError: If the HTTP request fails.
|
||||
InvalidParams: If the API request contains invalid parameters.
|
||||
UserNotFound: If the requested user is not found.
|
||||
|
||||
"""
|
||||
url = self.BASE_URL + "/" + str(uid)
|
||||
params = {}
|
||||
if language != Language.CHS:
|
||||
params.update({"lang": language.value})
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, params=params) as response:
|
||||
if response.status == 200:
|
||||
match response.status:
|
||||
case 200:
|
||||
return await response.json(encoding="utf-8")
|
||||
case 400:
|
||||
try:
|
||||
data = await response.json(encoding="utf-8")
|
||||
except:
|
||||
raise InvalidParams()
|
||||
else:
|
||||
if isinstance(data, dict) and (detail := data.get("detail")):
|
||||
raise InvalidParams(detail)
|
||||
raise InvalidParams()
|
||||
case 404:
|
||||
raise UserNotFound()
|
||||
case _:
|
||||
raise HttpRequestError(response.status, str(response.reason))
|
||||
|
||||
async def fetch_user(self, uid: int) -> StarrailInfoParsed:
|
||||
@ -86,8 +103,23 @@ class MihomoAPI:
|
||||
|
||||
"""
|
||||
data = await self.request(uid, self.lang)
|
||||
data = remove_empty_dict(data)
|
||||
data = StarrailInfoParsed.parse_obj(data)
|
||||
return data
|
||||
|
||||
async def fetch_user_v1(self, uid: int) -> StarrailInfoParsedV1:
|
||||
"""
|
||||
Fetches user data from the API using version 1.
|
||||
|
||||
Args:
|
||||
uid (int): The user ID.
|
||||
|
||||
Returns:
|
||||
StarrailInfoParsedV1: The parsed user data from the Mihomo API (version 1).
|
||||
|
||||
"""
|
||||
data = await self.request(uid, self.lang, params={"version": "v1"})
|
||||
data = remove_empty_dict(data)
|
||||
data = StarrailInfoParsedV1.parse_obj(data)
|
||||
data = replace_trailblazer_name(data)
|
||||
return data
|
||||
|
||||
|
@ -1,9 +1,19 @@
|
||||
class HttpRequestError(Exception):
|
||||
"""Http request failed"""
|
||||
class BaseException(Exception):
|
||||
"""Base exception class."""
|
||||
|
||||
message: str = ""
|
||||
|
||||
def __init__(self, message: str | None = None, *args: object) -> None:
|
||||
if message is not None:
|
||||
self.message = message
|
||||
super().__init__(self.message, *args)
|
||||
|
||||
|
||||
class HttpRequestError(BaseException):
|
||||
"""Exception raised when an HTTP request fails."""
|
||||
|
||||
status: int = 0
|
||||
reason: str = ""
|
||||
message: str = ""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -18,3 +28,15 @@ class HttpRequestError(Exception):
|
||||
self.reason = reason
|
||||
self.message = message
|
||||
super().__init__(message, *args)
|
||||
|
||||
|
||||
class UserNotFound(BaseException):
|
||||
"""Exception raised when a user is not found."""
|
||||
|
||||
message = "User not found."
|
||||
|
||||
|
||||
class InvalidParams(BaseException):
|
||||
"""Exception raised when invalid parameters are provided."""
|
||||
|
||||
message: str = "Invalid parameters"
|
||||
|
@ -1,4 +1,5 @@
|
||||
from .base import *
|
||||
from .character import *
|
||||
from .combat import *
|
||||
from .equipment import *
|
||||
from .player import *
|
||||
|
@ -1,7 +1,7 @@
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from .character import Character
|
||||
from .player import Player, PlayerSpaceInfo
|
||||
from .player import Player
|
||||
|
||||
|
||||
class StarrailInfoParsed(BaseModel):
|
||||
@ -9,14 +9,11 @@ class StarrailInfoParsed(BaseModel):
|
||||
Mihomo parsed data
|
||||
|
||||
Attributes:
|
||||
- player (`Player`): The player's basic info.
|
||||
- player_details (`PlayerSpaceInfo`): The player's details.
|
||||
- player (`Player`): The player's info.
|
||||
- characters (list[`Character`]): The list of characters.
|
||||
"""
|
||||
|
||||
player: Player
|
||||
"""Player's basic info"""
|
||||
player_details: PlayerSpaceInfo = Field(..., alias="PlayerSpaceInfo")
|
||||
"""Player's details"""
|
||||
characters: list[Character]
|
||||
"""The list of characters"""
|
||||
|
@ -2,66 +2,55 @@ from typing import Any
|
||||
|
||||
from pydantic import BaseModel, Field, root_validator
|
||||
|
||||
from .combat import Attribute, Element, Path, Property
|
||||
from .equipment import LightCone, Relic, RelicSet
|
||||
|
||||
|
||||
class EidolonIcon(BaseModel):
|
||||
"""
|
||||
Represents an Eidolon icon.
|
||||
|
||||
Attributes:
|
||||
- icon (`str`): The eidolon icon.
|
||||
- unlock (`bool`): Indicates if the eidolon is unlocked.
|
||||
"""
|
||||
|
||||
icon: str
|
||||
"""The eidolon icon"""
|
||||
unlock: bool
|
||||
"""Indicates if the eidolon is unlocked"""
|
||||
|
||||
|
||||
class Trace(BaseModel):
|
||||
"""
|
||||
Represents a character's skill trace.
|
||||
|
||||
Attributes:
|
||||
- id (`int`): The ID of the trace.
|
||||
- name (`str`): The name of the trace.
|
||||
- level (`int`): The level of the trace.
|
||||
- level (`int`): The current level of the trace.
|
||||
- max_level (`int`): The maximum level of the trace.
|
||||
- element (`Element` | None): The element of the trace, or None if not applicable.
|
||||
- type (`str`): The type of the trace.
|
||||
- type_text (`str`): The type text of the trace.
|
||||
- effect (`str`): The effect of the trace.
|
||||
- effect_text (`str`): The effect text of the trace.
|
||||
- simple_desc (`str`): The simple description of the trace.
|
||||
- desc (`str`): The detailed description of the trace.
|
||||
- icon (`str`): The trace icon.
|
||||
"""
|
||||
|
||||
id: int
|
||||
"""The ID of the trace"""
|
||||
name: str
|
||||
"""The name of the trace"""
|
||||
level: int
|
||||
"""The level of the trace"""
|
||||
"""The current level of the trace"""
|
||||
max_level: int
|
||||
"""The maximum level of the trace"""
|
||||
element: Element | None = None
|
||||
"""The element of the trace"""
|
||||
type: str
|
||||
"""The type of the trace"""
|
||||
type_text: str
|
||||
"""The type text of the trace"""
|
||||
effect: str
|
||||
"""The effect of the trace"""
|
||||
effect_text: str
|
||||
"""The effect text of the trace"""
|
||||
simple_desc: str
|
||||
"""The simple description of the trace"""
|
||||
desc: str
|
||||
"""The detailed description of the trace"""
|
||||
icon: str
|
||||
"""The trace icon"""
|
||||
|
||||
|
||||
class Stat(BaseModel):
|
||||
"""
|
||||
Represents a character's stat.
|
||||
|
||||
Attributes:
|
||||
- name (`str`): The name of the stat.
|
||||
- base (`str`): The base value of the stat.
|
||||
- addition (`str` | `None`): The additional value of the stat, or None if not applicable.
|
||||
- icon (`str`): The stat icon.
|
||||
"""
|
||||
|
||||
name: str
|
||||
"""The name of the stat"""
|
||||
base: str
|
||||
"""The base value of the stat"""
|
||||
addition: str | None = None
|
||||
"""The additional value of the stat"""
|
||||
icon: str
|
||||
"""The stat icon"""
|
||||
|
||||
|
||||
class Character(BaseModel):
|
||||
"""
|
||||
Represents a character.
|
||||
@ -72,26 +61,25 @@ class Character(BaseModel):
|
||||
- name (`str`): The character's name.
|
||||
- rarity (`int`): The character's rarity.
|
||||
- level (`int`): The character's level.
|
||||
- Eidolon
|
||||
- ascension (`int`): Ascension level.
|
||||
- eidolon (`int`): The character's eidolon rank.
|
||||
- eidolon_text (`str`): The text representation of the eidolon.
|
||||
- eidolon_icons (list[`EidolonIcon`]): The list of eidolon icons.
|
||||
- Image
|
||||
- icon (`str`): The character avatar image
|
||||
- preview (`str`): The character's preview image.
|
||||
- portrait (`str`): The character's portrait image.
|
||||
- Combat type
|
||||
- path (`str`): The character's path.
|
||||
- path_icon (`str`): The character's path icon.
|
||||
- element (`str`): The character's element.
|
||||
- element_icon (`str`): The character's element icon.
|
||||
- color (`str`): The character's element color.
|
||||
- Combat
|
||||
- path (`Path`): The character's path.
|
||||
- element (`Element`): The character's element.
|
||||
- Equipment
|
||||
- traces (list[`Trace`]): The list of character's skill traces.
|
||||
- light_cone (`LightCone` | `None`): The character's light cone (weapon), or None if not applicable.
|
||||
- relics (list[`Relic`] | `None`): The list of character's relics, or None if not applicable.
|
||||
- relic_set (list[`RelicSet`] | `None`): The list of character's relic sets, or None if not applicable.
|
||||
- stats (list[`Stat`]): The list of character's stats.
|
||||
- Stats
|
||||
- attributes (list[`Attribute`]): The list of character's attributes.
|
||||
- additions (list[`Attribute`]): The list of character's additional attributes.
|
||||
- properties (list[`Property`]): The list of character's properties.
|
||||
"""
|
||||
|
||||
id: str
|
||||
@ -102,52 +90,35 @@ class Character(BaseModel):
|
||||
"""Character's rarity"""
|
||||
level: int
|
||||
"""Character's level"""
|
||||
|
||||
ascension: int = Field(..., alias="promotion")
|
||||
"""Ascension Level"""
|
||||
eidolon: int = Field(..., alias="rank")
|
||||
"""Character's eidolon rank"""
|
||||
eidolon_text: str = Field(..., alias="rank_text")
|
||||
"""The text representation of the eidolon"""
|
||||
eidolon_icons: list[EidolonIcon] = Field(..., alias="rank_icons")
|
||||
"""The list of eidolon icons"""
|
||||
|
||||
icon: str
|
||||
"""Character avatar image"""
|
||||
preview: str
|
||||
"""Character preview image"""
|
||||
portrait: str
|
||||
"""Character portrait image"""
|
||||
|
||||
path: str
|
||||
path: Path
|
||||
"""Character's path"""
|
||||
path_icon: str
|
||||
"""Character's path icon"""
|
||||
|
||||
element: str
|
||||
element: Element
|
||||
"""Character's element"""
|
||||
element_icon: str
|
||||
"""Character's element icon"""
|
||||
|
||||
color: str
|
||||
"""Character's element color"""
|
||||
|
||||
traces: list[Trace] = Field(..., alias="skill")
|
||||
traces: list[Trace] = Field(..., alias="skills")
|
||||
"""The list of character's skill traces"""
|
||||
light_cone: LightCone | None = None
|
||||
"""Character's light cone (weapon)"""
|
||||
relics: list[Relic] | None = Field(None, alias="relic")
|
||||
relics: list[Relic] = []
|
||||
"""The list of character's relics"""
|
||||
relic_set: list[RelicSet] | None = None
|
||||
relic_sets: list[RelicSet] = []
|
||||
"""The list of character's relic sets"""
|
||||
stats: list[Stat] = Field(..., alias="property")
|
||||
"""The list of character's stats"""
|
||||
|
||||
@root_validator(pre=True)
|
||||
def dict_to_list(cls, data: dict[str, Any]):
|
||||
# The keys of the original dict is not necessary, so remove them here.
|
||||
if isinstance(data, dict) and data.get("relic") is not None:
|
||||
if isinstance(data["relic"], dict):
|
||||
data["relic"] = list(data["relic"].values())
|
||||
return data
|
||||
|
||||
@property
|
||||
def icon(self) -> str:
|
||||
"""Character avatar image"""
|
||||
return f"icon/character/{self.id}.png"
|
||||
attributes: list[Attribute]
|
||||
"""The list of character's attributes"""
|
||||
additions: list[Attribute]
|
||||
"""The list of character's additional attributes"""
|
||||
properties: list[Property]
|
||||
"""The list of character's properties"""
|
||||
|
97
mihomo/models/combat.py
Normal file
97
mihomo/models/combat.py
Normal file
@ -0,0 +1,97 @@
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class Element(BaseModel):
|
||||
"""
|
||||
Represents an element.
|
||||
|
||||
Attributes:
|
||||
- id (`str`): The ID of the element.
|
||||
- name (`str`): The name of the element.
|
||||
- color (`str`): The color of the element.
|
||||
- icon (`str`): The element icon.
|
||||
"""
|
||||
|
||||
id: str
|
||||
"""The ID of the element"""
|
||||
name: str
|
||||
"""The name of the element"""
|
||||
color: str
|
||||
"""The color of the element"""
|
||||
icon: str
|
||||
"""The element icon"""
|
||||
|
||||
|
||||
class Path(BaseModel):
|
||||
"""
|
||||
Paths are congregations of Imaginary energy, with which the ideals harmonize.
|
||||
|
||||
Attributes:
|
||||
- id (`str`): The ID of the path.
|
||||
- name (`str`): The name of the path.
|
||||
- icon (`str`): The path icon.
|
||||
"""
|
||||
|
||||
id: str
|
||||
"""The ID of the path"""
|
||||
name: str
|
||||
"""The name of the path"""
|
||||
icon: str
|
||||
"""The path icon"""
|
||||
|
||||
|
||||
class Attribute(BaseModel):
|
||||
"""
|
||||
Represents an attribute.
|
||||
|
||||
Attributes:
|
||||
- field (`str`): The field of the attribute.
|
||||
- name (`str`): The name of the attribute.
|
||||
- icon (`str`): The attribute icon image.
|
||||
- value (`float`): The value of the attribute.
|
||||
- displayed_value (`str`): The displayed value of the attribute.
|
||||
- is_percent (`bool`): Indicates if the value is in percentage.
|
||||
"""
|
||||
|
||||
field: str
|
||||
"""The field of the attribute"""
|
||||
name: str
|
||||
"""The name of the attribute"""
|
||||
icon: str
|
||||
"""The attribute icon image"""
|
||||
value: float
|
||||
"""The value of the attribute"""
|
||||
displayed_value: str = Field(..., alias="display")
|
||||
"""The displayed value of the attribute"""
|
||||
is_percent: bool = Field(..., alias="percent")
|
||||
"""Indicates if the value is in percentage"""
|
||||
|
||||
|
||||
class Property(BaseModel):
|
||||
"""
|
||||
Represents a property.
|
||||
|
||||
Attributes:
|
||||
- type (`str`): The type of the property.
|
||||
- field (`str`): The field of the property.
|
||||
- name (`str`): The name of the property.
|
||||
- icon (`str`): The property icon image.
|
||||
- value (`float`): The value of the property.
|
||||
- displayed_value (`str`): The displayed value of the property.
|
||||
- is_percent (`bool`): Indicates if the value is in percentage.
|
||||
"""
|
||||
|
||||
type: str
|
||||
"""The type of the property"""
|
||||
field: str
|
||||
"""The field of the property"""
|
||||
name: str
|
||||
"""The name of the property"""
|
||||
icon: str
|
||||
"""The property icon image"""
|
||||
value: float
|
||||
"""The value of the property"""
|
||||
displayed_value: str = Field(..., alias="display")
|
||||
"""The displayed value of the property"""
|
||||
is_percent: bool = Field(..., alias="percent")
|
||||
"""Indicates if the value is in percentage"""
|
@ -1,38 +1,51 @@
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from .combat import Attribute, Path, Property
|
||||
|
||||
|
||||
class LightCone(BaseModel):
|
||||
"""
|
||||
Represents a light cone (weapon).
|
||||
|
||||
Attributes:
|
||||
- id (`int`): The ID of the light cone.
|
||||
- name (`str`): The name of the light cone.
|
||||
- rarity (`int`): The rarity of the light cone.
|
||||
- superimpose (`int`): The superimpose rank of the light cone.
|
||||
- level (`int`): The level of the light cone.
|
||||
- icon (`str`): The light cone icon.
|
||||
- ascension (`int`): The ascension level of the light cone.
|
||||
- icon (`str`): The light cone icon image.
|
||||
- preview (`str`): The light cone preview image.
|
||||
- portrait (`str`): The light cone portrait image.
|
||||
- path (`Path`): The path of the light cone.
|
||||
- attributes (list[`Attribute`]): The list of attributes of the light cone.
|
||||
- properties (list[`Property`]): The list of properties of the light cone.
|
||||
"""
|
||||
|
||||
id: int
|
||||
"""The ID of the light cone"""
|
||||
name: str
|
||||
"""The name of the light cone"""
|
||||
rarity: int
|
||||
"""The rarity of the light cone"""
|
||||
superimpose: int = Field(..., alias="rank")
|
||||
"""The superimpose rank of the light cone"""
|
||||
level: int
|
||||
"""The level of the light cone"""
|
||||
ascension: int = Field(..., alias="promotion")
|
||||
"""The ascension level of the light cone"""
|
||||
icon: str
|
||||
|
||||
|
||||
class RelicProperty(BaseModel):
|
||||
"""
|
||||
Represents a property of a relic.
|
||||
|
||||
Attributes:
|
||||
- name (`str`): The name of the relic property.
|
||||
- value (`str`): The value of the relic property.
|
||||
- icon (`str`): The property icon.
|
||||
"""
|
||||
|
||||
name: str
|
||||
value: str
|
||||
icon: str
|
||||
"""The light cone icon image"""
|
||||
preview: str
|
||||
"""The light cone preview image"""
|
||||
portrait: str
|
||||
"""The light cone portrait image"""
|
||||
path: Path
|
||||
"""The path of the light cone"""
|
||||
attributes: list[Attribute]
|
||||
"""The list of attributes of the light cone"""
|
||||
properties: list[Property]
|
||||
"""The list of properties of the light cone"""
|
||||
|
||||
|
||||
class Relic(BaseModel):
|
||||
@ -40,7 +53,10 @@ class Relic(BaseModel):
|
||||
Represents a relic.
|
||||
|
||||
Attributes:
|
||||
- id (`int`): The ID of the relic.
|
||||
- name (`str`): The name of the relic.
|
||||
- set_id (`int`): The ID of the relic set.
|
||||
- set_name (`str`): The name of the relic set.
|
||||
- rarity (`int`): The rarity of the relic.
|
||||
- level (`int`): The level of the relic.
|
||||
- main_property (`RelicProperty`): The main property of the relic.
|
||||
@ -48,12 +64,24 @@ class Relic(BaseModel):
|
||||
- icon (`str`): The relic icon.
|
||||
"""
|
||||
|
||||
id: int
|
||||
"""The ID of the relic"""
|
||||
name: str
|
||||
"""The name of the relic"""
|
||||
set_id: int
|
||||
"""The ID of the relic set"""
|
||||
set_name: str
|
||||
"""The name of the relic set"""
|
||||
rarity: int
|
||||
"""The rarity of the relic"""
|
||||
level: int
|
||||
main_property: RelicProperty
|
||||
sub_property: list[RelicProperty]
|
||||
"""The level of the relic"""
|
||||
main_property: Property = Field(..., alias="main_affix")
|
||||
"""The main property of the relic"""
|
||||
sub_properties: list[Property] = Field(..., alias="sub_affix")
|
||||
"""The list of sub properties of the relic"""
|
||||
icon: str
|
||||
"""The relic icon"""
|
||||
|
||||
|
||||
class RelicSet(BaseModel):
|
||||
@ -61,11 +89,17 @@ class RelicSet(BaseModel):
|
||||
Represents a set of relics.
|
||||
|
||||
Attributes:
|
||||
- id (`int`): The ID of the relic set.
|
||||
- name (`str`): The name of the relic set.
|
||||
- icon (`str`): The relic set icon.
|
||||
- desc (`int`): The description of the relic set.
|
||||
- desc (`str`): The description of the relic set.
|
||||
- properties (list[`Property`]): The list of properties of the relic set.
|
||||
"""
|
||||
|
||||
id: int
|
||||
"""The ID of the relic set"""
|
||||
name: str
|
||||
icon: str
|
||||
desc: int
|
||||
"""The name of the relic set"""
|
||||
desc: str
|
||||
"""The description of the relic set"""
|
||||
properties: list[Property]
|
||||
"""The list of properties of the relic set"""
|
||||
|
@ -1,28 +1,12 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, Field, root_validator
|
||||
|
||||
|
||||
class Player(BaseModel):
|
||||
"""
|
||||
Player basic info
|
||||
|
||||
Attributes:
|
||||
- uid (`str`): The player's uid.
|
||||
- name (`str`): The player's nickname.
|
||||
- level (`int`): The player's Trailblaze level.
|
||||
- icon (`str`): The player's profile picture.
|
||||
- signature (`str`): The player's bio.
|
||||
"""
|
||||
|
||||
uid: str
|
||||
"""Player's uid"""
|
||||
name: str
|
||||
"""Player's nickname"""
|
||||
level: int
|
||||
"""Trailblaze level"""
|
||||
icon: str
|
||||
class Avatar(BaseModel):
|
||||
"""Profile picture"""
|
||||
signature: str
|
||||
"""Bio"""
|
||||
|
||||
id: int
|
||||
name: str
|
||||
icon: str
|
||||
|
||||
|
||||
class ForgottenHall(BaseModel):
|
||||
@ -30,21 +14,31 @@ class ForgottenHall(BaseModel):
|
||||
|
||||
Attributes:
|
||||
- memory (`int`): The progress of the memory.
|
||||
- memory_of_chaos_id (`int` | `None`): The ID of the memory of chaos, or None if not applicable.
|
||||
- memory_of_chaos (`int` | `None`): The progress of the memory of chaos, or None if not applicable.
|
||||
- memory_of_chaos_id (`int`): The ID of the memory of chaos, or None if not applicable.
|
||||
- memory_of_chaos (`int`): The progress of the memory of chaos, or None if not applicable.
|
||||
"""
|
||||
|
||||
memory: int = Field(..., alias="PreMazeGroupIndex")
|
||||
memory: int = Field(..., alias="pre_maze_group_index")
|
||||
"""The progress of the memory"""
|
||||
memory_of_chaos_id: int | None = Field(None, alias="MazeGroupID")
|
||||
memory_of_chaos: int | None = Field(None, alias="MazeGroupIndex")
|
||||
memory_of_chaos_id: int = Field(..., alias="maze_group_id")
|
||||
"""The ID of the memory of chaos"""
|
||||
memory_of_chaos: int = Field(..., alias="maze_group_index")
|
||||
"""The progress of the memory of chaos"""
|
||||
|
||||
|
||||
class PlayerSpaceInfo(BaseModel):
|
||||
"""Player details
|
||||
class Player(BaseModel):
|
||||
"""
|
||||
Player basic info
|
||||
|
||||
Attributes:
|
||||
- uid (`int`): The player's uid.
|
||||
- name (`str`): The player's nickname.
|
||||
- level (`int`): The player's Trailblaze level.
|
||||
- world_level (`int`): The player's Equilibrium level.
|
||||
- avatar (`Avatar`): The player's profile picture.
|
||||
- signature (`str`): The player's bio.
|
||||
- is_display (`bool`): Is the player's profile display enabled.
|
||||
|
||||
- forgotten_hall (`ForgottenHall` | None): The progress of the Forgotten Hall, or None if not applicable.
|
||||
- simulated_universes (`int`): The number of simulated universes passed.
|
||||
- light_cones (`int`): The number of light cones owned.
|
||||
@ -52,13 +46,28 @@ class PlayerSpaceInfo(BaseModel):
|
||||
- achievements (`int`): The number of achievements unlocked.
|
||||
"""
|
||||
|
||||
forgotten_hall: ForgottenHall | None = Field(None, alias="ChallengeData")
|
||||
uid: int
|
||||
"""Player's uid"""
|
||||
name: str = Field(..., alias="nickname")
|
||||
"""Player's nickname"""
|
||||
level: int
|
||||
"""Trailblaze level"""
|
||||
world_level: int
|
||||
"""Equilibrium level"""
|
||||
avatar: Avatar
|
||||
"""Profile picture"""
|
||||
signature: str
|
||||
"""Bio"""
|
||||
is_display: bool
|
||||
"""Is the player's profile display enabled."""
|
||||
|
||||
forgotten_hall: ForgottenHall | None = Field(None, alias="challenge_data")
|
||||
"""The progress of the Forgotten Hall"""
|
||||
simulated_universes: int = Field(0, alias="PassAreaProgress")
|
||||
simulated_universes: int = Field(0, alias="pass_area_progress")
|
||||
"""Number of simulated universes passed"""
|
||||
light_cones: int = Field(0, alias="LightConeCount")
|
||||
light_cones: int = Field(0, alias="light_cone_count")
|
||||
"""Number of light cones owned"""
|
||||
characters: int = Field(0, alias="AvatarCount")
|
||||
characters: int = Field(0, alias="avatar_count")
|
||||
"""Number of characters owned"""
|
||||
achievements: int = Field(0, alias="AchievementCount")
|
||||
achievements: int = Field(0, alias="achievement_count")
|
||||
"""Number of achievements unlocked"""
|
||||
|
4
mihomo/models/v1/__init__.py
Normal file
4
mihomo/models/v1/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
from .base import *
|
||||
from .character import *
|
||||
from .equipment import *
|
||||
from .player import *
|
22
mihomo/models/v1/base.py
Normal file
22
mihomo/models/v1/base.py
Normal file
@ -0,0 +1,22 @@
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from .character import Character
|
||||
from .player import Player, PlayerSpaceInfo
|
||||
|
||||
|
||||
class StarrailInfoParsedV1(BaseModel):
|
||||
"""
|
||||
Mihomo parsed data V1
|
||||
|
||||
Attributes:
|
||||
- player (`Player`): The player's basic info.
|
||||
- player_details (`PlayerSpaceInfo`): The player's details.
|
||||
- characters (list[`Character`]): The list of characters.
|
||||
"""
|
||||
|
||||
player: Player
|
||||
"""Player's basic info"""
|
||||
player_details: PlayerSpaceInfo = Field(..., alias="PlayerSpaceInfo")
|
||||
"""Player's details"""
|
||||
characters: list[Character]
|
||||
"""The list of characters"""
|
150
mihomo/models/v1/character.py
Normal file
150
mihomo/models/v1/character.py
Normal file
@ -0,0 +1,150 @@
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, Field, root_validator
|
||||
|
||||
from .equipment import LightCone, Relic, RelicSet
|
||||
|
||||
|
||||
class EidolonIcon(BaseModel):
|
||||
"""
|
||||
Represents an Eidolon icon.
|
||||
|
||||
Attributes:
|
||||
- icon (`str`): The eidolon icon.
|
||||
- unlock (`bool`): Indicates if the eidolon is unlocked.
|
||||
"""
|
||||
|
||||
icon: str
|
||||
"""The eidolon icon"""
|
||||
unlock: bool
|
||||
"""Indicates if the eidolon is unlocked"""
|
||||
|
||||
|
||||
class Trace(BaseModel):
|
||||
"""
|
||||
Represents a character's skill trace.
|
||||
|
||||
Attributes:
|
||||
- name (`str`): The name of the trace.
|
||||
- level (`int`): The level of the trace.
|
||||
- type (`str`): The type of the trace.
|
||||
- icon (`str`): The trace icon.
|
||||
"""
|
||||
|
||||
name: str
|
||||
"""The name of the trace"""
|
||||
level: int
|
||||
"""The level of the trace"""
|
||||
type: str
|
||||
"""The type of the trace"""
|
||||
icon: str
|
||||
"""The trace icon"""
|
||||
|
||||
|
||||
class Stat(BaseModel):
|
||||
"""
|
||||
Represents a character's stat.
|
||||
|
||||
Attributes:
|
||||
- name (`str`): The name of the stat.
|
||||
- base (`str`): The base value of the stat.
|
||||
- addition (`str` | `None`): The additional value of the stat, or None if not applicable.
|
||||
- icon (`str`): The stat icon.
|
||||
"""
|
||||
|
||||
name: str
|
||||
"""The name of the stat"""
|
||||
base: str
|
||||
"""The base value of the stat"""
|
||||
addition: str | None = None
|
||||
"""The additional value of the stat"""
|
||||
icon: str
|
||||
"""The stat icon"""
|
||||
|
||||
|
||||
class Character(BaseModel):
|
||||
"""
|
||||
Represents a character.
|
||||
|
||||
Attributes:
|
||||
- Basic info:
|
||||
- id (`str`): The character's ID.
|
||||
- name (`str`): The character's name.
|
||||
- rarity (`int`): The character's rarity.
|
||||
- level (`int`): The character's level.
|
||||
- Eidolon
|
||||
- eidolon (`int`): The character's eidolon rank.
|
||||
- eidolon_icons (list[`EidolonIcon`]): The list of eidolon icons.
|
||||
- Image
|
||||
- icon (`str`): The character avatar image
|
||||
- preview (`str`): The character's preview image.
|
||||
- portrait (`str`): The character's portrait image.
|
||||
- Combat type
|
||||
- path (`str`): The character's path.
|
||||
- path_icon (`str`): The character's path icon.
|
||||
- element (`str`): The character's element.
|
||||
- element_icon (`str`): The character's element icon.
|
||||
- color (`str`): The character's element color.
|
||||
- Equipment
|
||||
- traces (list[`Trace`]): The list of character's skill traces.
|
||||
- light_cone (`LightCone` | `None`): The character's light cone (weapon), or None if not applicable.
|
||||
- relics (list[`Relic`] | `None`): The list of character's relics, or None if not applicable.
|
||||
- relic_set (list[`RelicSet`] | `None`): The list of character's relic sets, or None if not applicable.
|
||||
- stats (list[`Stat`]): The list of character's stats.
|
||||
"""
|
||||
|
||||
id: str
|
||||
"""Character's ID"""
|
||||
name: str
|
||||
"""Character's name"""
|
||||
rarity: int
|
||||
"""Character's rarity"""
|
||||
level: int
|
||||
"""Character's level"""
|
||||
|
||||
eidolon: int = Field(..., alias="rank")
|
||||
"""Character's eidolon rank"""
|
||||
eidolon_icons: list[EidolonIcon] = Field(..., alias="rank_icons")
|
||||
"""The list of eidolon icons"""
|
||||
|
||||
preview: str
|
||||
"""Character preview image"""
|
||||
portrait: str
|
||||
"""Character portrait image"""
|
||||
|
||||
path: str
|
||||
"""Character's path"""
|
||||
path_icon: str
|
||||
"""Character's path icon"""
|
||||
|
||||
element: str
|
||||
"""Character's element"""
|
||||
element_icon: str
|
||||
"""Character's element icon"""
|
||||
|
||||
color: str
|
||||
"""Character's element color"""
|
||||
|
||||
traces: list[Trace] = Field(..., alias="skill")
|
||||
"""The list of character's skill traces"""
|
||||
light_cone: LightCone | None = None
|
||||
"""Character's light cone (weapon)"""
|
||||
relics: list[Relic] | None = Field(None, alias="relic")
|
||||
"""The list of character's relics"""
|
||||
relic_set: list[RelicSet] | None = None
|
||||
"""The list of character's relic sets"""
|
||||
stats: list[Stat] = Field(..., alias="property")
|
||||
"""The list of character's stats"""
|
||||
|
||||
@root_validator(pre=True)
|
||||
def dict_to_list(cls, data: dict[str, Any]):
|
||||
# The keys of the original dict is not necessary, so remove them here.
|
||||
if isinstance(data, dict) and data.get("relic") is not None:
|
||||
if isinstance(data["relic"], dict):
|
||||
data["relic"] = list(data["relic"].values())
|
||||
return data
|
||||
|
||||
@property
|
||||
def icon(self) -> str:
|
||||
"""Character avatar image"""
|
||||
return f"icon/character/{self.id}.png"
|
71
mihomo/models/v1/equipment.py
Normal file
71
mihomo/models/v1/equipment.py
Normal file
@ -0,0 +1,71 @@
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class LightCone(BaseModel):
|
||||
"""
|
||||
Represents a light cone (weapon).
|
||||
|
||||
Attributes:
|
||||
- name (`str`): The name of the light cone.
|
||||
- rarity (`int`): The rarity of the light cone.
|
||||
- superimpose (`int`): The superimpose rank of the light cone.
|
||||
- level (`int`): The level of the light cone.
|
||||
- icon (`str`): The light cone icon.
|
||||
"""
|
||||
|
||||
name: str
|
||||
rarity: int
|
||||
superimpose: int = Field(..., alias="rank")
|
||||
level: int
|
||||
icon: str
|
||||
|
||||
|
||||
class RelicProperty(BaseModel):
|
||||
"""
|
||||
Represents a property of a relic.
|
||||
|
||||
Attributes:
|
||||
- name (`str`): The name of the relic property.
|
||||
- value (`str`): The value of the relic property.
|
||||
- icon (`str`): The property icon.
|
||||
"""
|
||||
|
||||
name: str
|
||||
value: str
|
||||
icon: str
|
||||
|
||||
|
||||
class Relic(BaseModel):
|
||||
"""
|
||||
Represents a relic.
|
||||
|
||||
Attributes:
|
||||
- name (`str`): The name of the relic.
|
||||
- rarity (`int`): The rarity of the relic.
|
||||
- level (`int`): The level of the relic.
|
||||
- main_property (`RelicProperty`): The main property of the relic.
|
||||
- sub_property (list[`RelicProperty`]): The list of sub properties of the relic.
|
||||
- icon (`str`): The relic icon.
|
||||
"""
|
||||
|
||||
name: str
|
||||
rarity: int
|
||||
level: int
|
||||
main_property: RelicProperty
|
||||
sub_property: list[RelicProperty]
|
||||
icon: str
|
||||
|
||||
|
||||
class RelicSet(BaseModel):
|
||||
"""
|
||||
Represents a set of relics.
|
||||
|
||||
Attributes:
|
||||
- name (`str`): The name of the relic set.
|
||||
- icon (`str`): The relic set icon.
|
||||
- desc (`int`): The description of the relic set.
|
||||
"""
|
||||
|
||||
name: str
|
||||
icon: str
|
||||
desc: int
|
64
mihomo/models/v1/player.py
Normal file
64
mihomo/models/v1/player.py
Normal file
@ -0,0 +1,64 @@
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class Player(BaseModel):
|
||||
"""
|
||||
Player basic info
|
||||
|
||||
Attributes:
|
||||
- uid (`str`): The player's uid.
|
||||
- name (`str`): The player's nickname.
|
||||
- level (`int`): The player's Trailblaze level.
|
||||
- icon (`str`): The player's profile picture.
|
||||
- signature (`str`): The player's bio.
|
||||
"""
|
||||
|
||||
uid: str
|
||||
"""Player's uid"""
|
||||
name: str
|
||||
"""Player's nickname"""
|
||||
level: int
|
||||
"""Trailblaze level"""
|
||||
icon: str
|
||||
"""Profile picture"""
|
||||
signature: str
|
||||
"""Bio"""
|
||||
|
||||
|
||||
class ForgottenHall(BaseModel):
|
||||
"""The progress of the Forgotten Hall
|
||||
|
||||
Attributes:
|
||||
- memory (`int`): The progress of the memory.
|
||||
- memory_of_chaos_id (`int` | `None`): The ID of the memory of chaos, or None if not applicable.
|
||||
- memory_of_chaos (`int` | `None`): The progress of the memory of chaos, or None if not applicable.
|
||||
"""
|
||||
|
||||
memory: int | None = Field(None, alias="PreMazeGroupIndex")
|
||||
"""The progress of the memory"""
|
||||
memory_of_chaos_id: int | None = Field(None, alias="MazeGroupID")
|
||||
memory_of_chaos: int | None = Field(None, alias="MazeGroupIndex")
|
||||
"""The progress of the memory of chaos"""
|
||||
|
||||
|
||||
class PlayerSpaceInfo(BaseModel):
|
||||
"""Player details
|
||||
|
||||
Attributes:
|
||||
- forgotten_hall (`ForgottenHall` | None): The progress of the Forgotten Hall, or None if not applicable.
|
||||
- simulated_universes (`int`): The number of simulated universes passed.
|
||||
- light_cones (`int`): The number of light cones owned.
|
||||
- characters (`int`): The number of characters owned.
|
||||
- achievements (`int`): The number of achievements unlocked.
|
||||
"""
|
||||
|
||||
forgotten_hall: ForgottenHall | None = Field(None, alias="ChallengeData")
|
||||
"""The progress of the Forgotten Hall"""
|
||||
simulated_universes: int = Field(0, alias="PassAreaProgress")
|
||||
"""Number of simulated universes passed"""
|
||||
light_cones: int = Field(0, alias="LightConeCount")
|
||||
"""Number of light cones owned"""
|
||||
characters: int = Field(0, alias="AvatarCount")
|
||||
"""Number of characters owned"""
|
||||
achievements: int = Field(0, alias="AchievementCount")
|
||||
"""Number of achievements unlocked"""
|
@ -1,8 +1,10 @@
|
||||
from typing import TypeVar
|
||||
|
||||
from .models import Character, StarrailInfoParsed
|
||||
from .models.v1 import Character, StarrailInfoParsedV1
|
||||
|
||||
T = TypeVar("T")
|
||||
ParsedData = TypeVar("ParsedData", StarrailInfoParsed, StarrailInfoParsedV1)
|
||||
|
||||
|
||||
def remove_empty_dict(data: T) -> T:
|
||||
@ -24,7 +26,7 @@ def remove_empty_dict(data: T) -> T:
|
||||
return data
|
||||
|
||||
|
||||
def replace_trailblazer_name(data: StarrailInfoParsed) -> StarrailInfoParsed:
|
||||
def replace_trailblazer_name(data: StarrailInfoParsedV1) -> StarrailInfoParsedV1:
|
||||
"""
|
||||
Replaces the trailblazer name with the player's name.
|
||||
|
||||
@ -40,17 +42,17 @@ def replace_trailblazer_name(data: StarrailInfoParsed) -> StarrailInfoParsed:
|
||||
return data
|
||||
|
||||
|
||||
def remove_duplicate_character(data: StarrailInfoParsed) -> StarrailInfoParsed:
|
||||
def remove_duplicate_character(data: ParsedData) -> ParsedData:
|
||||
"""
|
||||
Removes duplicate characters from the given StarrailInfoParsed data.
|
||||
|
||||
Args:
|
||||
- data (`StarrailInfoParsed`): The input StarrailInfoParsed data.
|
||||
- data (`ParsedData`): The input StarrailInfoParsed data.
|
||||
|
||||
Returns:
|
||||
- `StarrailInfoParsed`: The updated StarrailInfoParsed data without duplicate characters.
|
||||
- `ParsedData`: The updated StarrailInfoParsed data without duplicate characters.
|
||||
"""
|
||||
new_characters: list[Character] = []
|
||||
new_characters = []
|
||||
characters_ids: set[str] = set()
|
||||
for character in data.characters:
|
||||
if character.id not in characters_ids:
|
||||
@ -60,19 +62,17 @@ def remove_duplicate_character(data: StarrailInfoParsed) -> StarrailInfoParsed:
|
||||
return data
|
||||
|
||||
|
||||
def merge_character_data(
|
||||
new_data: StarrailInfoParsed, old_data: StarrailInfoParsed
|
||||
) -> StarrailInfoParsed:
|
||||
def merge_character_data(new_data: ParsedData, old_data: ParsedData) -> ParsedData:
|
||||
"""
|
||||
Append the old data characters to the list of new data characters.
|
||||
The player's info from the old data will be omitted/discarded.
|
||||
|
||||
Args:
|
||||
- new_data (`StarrailInfoParsed`): The new data to be merged.
|
||||
- old_data (`StarrailInfoParsed`): The old data to merge into.
|
||||
- new_data (`ParsedData`): The new data to be merged.
|
||||
- old_data (`ParsedData`): The old data to merge into.
|
||||
|
||||
Returns:
|
||||
- `StarrailInfoParsed`: The merged new data.
|
||||
- `ParsedData`: The merged new data.
|
||||
"""
|
||||
for character in old_data.characters:
|
||||
new_data.characters.append(character)
|
||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "mihomo"
|
||||
version = "0.0.1"
|
||||
version = "1.1.0"
|
||||
authors = [
|
||||
{ name="KT", email="xns77477@gmail.com" },
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user