2023-05-05 04:06:43 +00:00
|
|
|
import enum
|
|
|
|
import re
|
2023-09-12 02:58:46 +00:00
|
|
|
from typing import Optional, Any, Dict, List, Union, Type
|
2023-05-05 04:06:43 +00:00
|
|
|
|
|
|
|
from pydantic import Field, validator
|
|
|
|
|
|
|
|
from simnet.models.base import APIModel
|
2023-12-27 07:09:24 +00:00
|
|
|
from simnet.utils.enums import Game
|
2023-05-05 04:06:43 +00:00
|
|
|
|
|
|
|
__all__ = (
|
|
|
|
"FullUser",
|
|
|
|
"Gender",
|
|
|
|
"Account",
|
|
|
|
"UserCertification",
|
|
|
|
"UserLevel",
|
|
|
|
"PartialUser",
|
|
|
|
"RecordCard",
|
|
|
|
"RecordCardData",
|
|
|
|
"RecordCardSetting",
|
|
|
|
"RecordCardSettingType",
|
|
|
|
"UserInfo",
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2023-09-12 02:58:46 +00:00
|
|
|
RECORD_CARD_MAP: Dict[int, Type["RecordCard"]] = {}
|
|
|
|
|
|
|
|
|
2023-05-05 04:06:43 +00:00
|
|
|
class Account(APIModel):
|
|
|
|
"""A representation of an account.
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
game_biz (str): The game business code for the account.
|
|
|
|
uid (int): The game user ID associated with the account.
|
|
|
|
level (int): The game level associated with the account.
|
|
|
|
nickname (str): The game nickname associated with the account.
|
|
|
|
server (str): The game server code associated with the account.
|
|
|
|
server_name (str): The game server name associated with the account.
|
|
|
|
"""
|
|
|
|
|
|
|
|
game_biz: str
|
|
|
|
uid: int = Field(alias="game_uid")
|
|
|
|
level: int
|
|
|
|
nickname: str
|
|
|
|
server: str = Field(alias="region")
|
|
|
|
server_name: str = Field(alias="region_name")
|
|
|
|
|
|
|
|
@property
|
|
|
|
def game(self) -> Union[Game, str]:
|
|
|
|
"""Returns the game associated with the account.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
Union[Game, str]: The game associated with the account. If the game cannot be determined,
|
|
|
|
the game business code is returned.
|
|
|
|
"""
|
|
|
|
if "hk4e" in self.game_biz:
|
|
|
|
return Game.GENSHIN
|
|
|
|
if "bh3" in self.game_biz:
|
|
|
|
return Game.HONKAI
|
|
|
|
if "hkrpg" in self.game_biz:
|
|
|
|
return Game.STARRAIL
|
2024-07-05 13:58:00 +00:00
|
|
|
if "nap" in self.game_biz:
|
|
|
|
return Game.ZZZ
|
2023-05-05 04:06:43 +00:00
|
|
|
try:
|
|
|
|
return Game(self.game_biz)
|
|
|
|
except ValueError:
|
|
|
|
return self.game_biz
|
|
|
|
|
|
|
|
|
|
|
|
class UserInfo(APIModel):
|
|
|
|
"""A representation of a user's information in a game.
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
nickname (str): The user's nickname in the game.
|
|
|
|
server (str): The server code associated with the user.
|
|
|
|
level (int): The user's level in the game.
|
|
|
|
icon (str): The user's avatar URL.
|
|
|
|
"""
|
|
|
|
|
|
|
|
nickname: str
|
|
|
|
server: str = Field(alias="region")
|
|
|
|
level: int
|
|
|
|
icon: str = Field(alias="AvatarUrl")
|
|
|
|
|
|
|
|
|
|
|
|
class RecordCardData(APIModel):
|
|
|
|
"""A data entry of a record card.
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
name (str): The name of the data entry.
|
|
|
|
value (str): The value of the data entry.
|
|
|
|
"""
|
|
|
|
|
|
|
|
name: str
|
|
|
|
value: str
|
|
|
|
|
|
|
|
|
|
|
|
class RecordCardSetting(APIModel):
|
|
|
|
"""A privacy setting of a record card.
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
id (int): The ID of the setting.
|
|
|
|
description (str): The name of the setting.
|
|
|
|
public (bool): Whether the setting is public or not.
|
|
|
|
"""
|
|
|
|
|
|
|
|
id: int = Field(alias="switch_id")
|
|
|
|
description: str = Field(alias="switch_name")
|
|
|
|
public: bool = Field(alias="is_public")
|
|
|
|
|
|
|
|
|
|
|
|
class RecordCardSettingType(enum.IntEnum):
|
|
|
|
"""An enumeration of privacy setting types for a record card."""
|
|
|
|
|
|
|
|
SHOW_CHRONICLE = 1
|
|
|
|
SHOW_CHARACTER_DETAILS = 2
|
|
|
|
ENABLE_REAL_TIME_NOTES = 3
|
|
|
|
|
|
|
|
|
|
|
|
class Gender(enum.IntEnum):
|
|
|
|
"""An enumeration of genders."""
|
|
|
|
|
|
|
|
unknown = 0
|
|
|
|
male = 1
|
|
|
|
female = 2
|
|
|
|
other = 3
|
|
|
|
|
|
|
|
|
|
|
|
class PartialUser(APIModel):
|
|
|
|
"""A representation of a partial user from a search result.
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
accident_id (int): The user's ID.
|
|
|
|
nickname (str): The user's nickname.
|
|
|
|
introduction (str): The user's introduction.
|
|
|
|
avatar_id (int): The user's avatar ID.
|
2023-11-03 15:18:11 +00:00
|
|
|
avatar_url (str): The user's avatar URL.
|
2023-05-05 04:06:43 +00:00
|
|
|
gender (Gender): The user's gender.
|
|
|
|
icon (str): The user's avatar URL.
|
|
|
|
"""
|
|
|
|
|
|
|
|
accident_id: int = Field(alias="uid")
|
|
|
|
nickname: str
|
|
|
|
introduction: str = Field(alias="introduce")
|
2023-11-03 15:18:11 +00:00
|
|
|
avatar_id: Optional[str] = Field(alias="avatar")
|
|
|
|
avatar_url: Optional[str] = ""
|
2023-05-05 04:06:43 +00:00
|
|
|
gender: Gender
|
|
|
|
icon: str = Field(alias="avatar_url")
|
|
|
|
|
|
|
|
@validator("nickname")
|
|
|
|
def remove_highlight(cls, v: str) -> str:
|
|
|
|
"""Removes the highlight tags from the user's nickname.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
v (str): The user's nickname.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
str: The user's nickname without any highlight tags.
|
|
|
|
"""
|
|
|
|
return re.sub(r"<.+?>", "", v)
|
|
|
|
|
|
|
|
|
|
|
|
class UserCertification(APIModel):
|
|
|
|
"""A representation of a user's certification.
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
icon_url (Optional[str]): The certification's icon URL.
|
|
|
|
description (Optional[str]): The certification's description.
|
|
|
|
type (int): The certification's type, e.g. 2 for artist.
|
|
|
|
"""
|
|
|
|
|
|
|
|
icon_url: Optional[str] = None
|
|
|
|
description: Optional[str] = Field(alias="desc", default=None)
|
|
|
|
type: int
|
|
|
|
|
|
|
|
|
|
|
|
class UserLevel(APIModel):
|
|
|
|
"""A representation of a user's level.
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
level (int): The user's level.
|
|
|
|
exp (int): The user's experience points.
|
|
|
|
level_desc (str): The user's level description.
|
|
|
|
bg_color (str): The user's background color.
|
|
|
|
bg_image (str): The user's background image.
|
|
|
|
"""
|
|
|
|
|
|
|
|
level: int
|
|
|
|
exp: int
|
|
|
|
level_desc: str
|
|
|
|
bg_color: str
|
|
|
|
bg_image: str
|
|
|
|
|
|
|
|
|
|
|
|
class FullUser(PartialUser):
|
|
|
|
"""A representation of a full user.
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
certification (Optional[UserCertification]): The user's certification.
|
|
|
|
level (Optional[UserLevel]): The user's level.
|
|
|
|
pendant_url (str): The user's pendant URL.
|
|
|
|
bg_url (Optional[str]): The user's background URL.
|
|
|
|
pc_bg_url (Optional[str]): The user's PC background URL.
|
|
|
|
"""
|
|
|
|
|
|
|
|
certification: Optional[UserCertification] = None
|
|
|
|
level: Optional[UserLevel] = None
|
|
|
|
pendant_url: str = Field(alias="pendant")
|
|
|
|
bg_url: Optional[str] = None
|
|
|
|
pc_bg_url: Optional[str] = None
|
|
|
|
|
|
|
|
|
|
|
|
class BaseRecordCard(Account):
|
|
|
|
"""A representation of a record card.
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
game_id (int): The ID of the game associated with the record card.
|
|
|
|
game_biz (str): The game business code for the record card.
|
|
|
|
uid (int): The game user ID associated with the record card.
|
|
|
|
data (List[RecordCardData]): A list of data entries for the record card.
|
|
|
|
settings (List[RecordCardSetting]): A list of privacy settings for the record card.
|
|
|
|
public (bool): Whether the record card is public or not.
|
|
|
|
background_image (str): The URL of the background image for the record card.
|
|
|
|
has_uid (bool): Whether the record card has a user ID associated with it or not.
|
|
|
|
url (str): The URL of the record card.
|
|
|
|
"""
|
|
|
|
|
|
|
|
game_id: int
|
|
|
|
game_biz: str = ""
|
|
|
|
uid: int = Field(alias="game_role_id")
|
|
|
|
|
|
|
|
data: List[RecordCardData]
|
|
|
|
settings: List[RecordCardSetting] = Field(alias="data_switches")
|
|
|
|
|
|
|
|
public: bool = Field(alias="is_public")
|
|
|
|
background_image: str
|
|
|
|
has_uid: bool = Field(alias="has_role")
|
|
|
|
url: str
|
|
|
|
|
|
|
|
def as_dict(self) -> Dict[str, Any]:
|
|
|
|
"""Returns the data as a dictionary.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
Dict[str, Any]: The data as a dictionary.
|
|
|
|
"""
|
2023-05-12 03:24:06 +00:00
|
|
|
return {d.name: (int(d.value) if d.value.isdigit() else d.value) for d in self.data}
|
2023-05-05 04:06:43 +00:00
|
|
|
|
|
|
|
|
2023-06-23 14:56:51 +00:00
|
|
|
class RecordCard(BaseRecordCard):
|
|
|
|
"""A representation of a record card.
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
game_id (int): The ID of the game associated with the record card.
|
|
|
|
game_biz (str): The game business code for the record card.
|
|
|
|
uid (int): The game user ID associated with the record card.
|
|
|
|
data (List[RecordCardData]): A list of data entries for the record card.
|
|
|
|
settings (List[RecordCardSetting]): A list of privacy settings for the record card.
|
|
|
|
public (bool): Whether the record card is public or not.
|
|
|
|
background_image (str): The URL of the background image for the record card.
|
|
|
|
has_uid (bool): Whether the record card has a user ID associated with it or not.
|
|
|
|
url (str): The URL of the record card.
|
|
|
|
"""
|
|
|
|
|
2023-09-12 02:58:46 +00:00
|
|
|
@classmethod
|
|
|
|
def creat(cls, **kwargs: Any):
|
|
|
|
"""Creates a record card.
|
2023-06-23 14:56:51 +00:00
|
|
|
|
|
|
|
Args:
|
2023-09-12 02:58:46 +00:00
|
|
|
**kwargs: Keyword arguments.
|
2023-06-23 14:56:51 +00:00
|
|
|
|
|
|
|
Returns:
|
2023-09-12 02:58:46 +00:00
|
|
|
RecordCard: The record card.
|
2023-06-23 14:56:51 +00:00
|
|
|
"""
|
|
|
|
game_id = kwargs.get("game_id", 0)
|
2023-09-12 02:58:46 +00:00
|
|
|
new_cls = RECORD_CARD_MAP.get(game_id, cls)
|
|
|
|
return new_cls(**kwargs)
|
2023-06-23 14:56:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
class GenshinRecordCard(RecordCard):
|
2023-05-05 04:06:43 +00:00
|
|
|
"""Genshin record card."""
|
|
|
|
|
|
|
|
@property
|
|
|
|
def game(self) -> Game:
|
|
|
|
"""Returns the game associated with the record card.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
Game: The game associated with the record card.
|
|
|
|
"""
|
|
|
|
return Game.GENSHIN
|
|
|
|
|
|
|
|
@property
|
|
|
|
def days_active(self) -> int:
|
|
|
|
"""Returns the number of days the user has been active.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
int: The number of days the user has been active.
|
|
|
|
"""
|
|
|
|
return int(self.data[0].value)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def characters(self) -> int:
|
|
|
|
"""Returns the number of characters the user has.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
int: The number of characters the user has.
|
|
|
|
"""
|
|
|
|
return int(self.data[1].value)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def achievements(self) -> int:
|
|
|
|
"""Returns the number of achievements the user has.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
int: The number of achievements the user has.
|
|
|
|
"""
|
|
|
|
return int(self.data[2].value)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def spiral_abyss(self) -> str:
|
|
|
|
"""Returns the user's progress in the Spiral Abyss.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
str: The user's progress in the Spiral Abyss.
|
|
|
|
"""
|
|
|
|
return self.data[3].value
|
|
|
|
|
|
|
|
|
2023-06-23 14:56:51 +00:00
|
|
|
class HonkaiRecordCard(RecordCard):
|
2023-05-05 04:06:43 +00:00
|
|
|
"""Honkai record card."""
|
|
|
|
|
|
|
|
@property
|
|
|
|
def game(self) -> Game:
|
|
|
|
"""Returns the game associated with the record card.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
Game: The game associated with the record card.
|
|
|
|
"""
|
|
|
|
return Game.HONKAI
|
|
|
|
|
|
|
|
@property
|
|
|
|
def days_active(self) -> int:
|
|
|
|
"""Returns the number of days the user has been active.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
int: The number of days the user has been active.
|
|
|
|
"""
|
|
|
|
return int(self.data[0].value)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def stigmata(self) -> int:
|
|
|
|
"""Returns the number of stigmata the user has.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
int: The number of stigmata the user has.
|
|
|
|
"""
|
|
|
|
return int(self.data[1].value)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def battlesuits(self) -> int:
|
|
|
|
"""Returns the number of battlesuits the user has.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
int: The number of battlesuits the user has.
|
|
|
|
"""
|
|
|
|
return int(self.data[2].value)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def outfits(self) -> int:
|
|
|
|
"""Returns the number of outfits the user has.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
int: The number of outfits the user has.
|
|
|
|
"""
|
|
|
|
return int(self.data[3].value)
|
|
|
|
|
|
|
|
|
2023-06-23 14:56:51 +00:00
|
|
|
class StarRailRecodeCard(RecordCard):
|
2023-05-05 04:06:43 +00:00
|
|
|
"""Star rail record card."""
|
|
|
|
|
|
|
|
@property
|
|
|
|
def game(self) -> Game:
|
|
|
|
"""Returns the game associated with the record card.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
Game: The game associated with the record card.
|
|
|
|
"""
|
|
|
|
return Game.STARRAIL
|
|
|
|
|
|
|
|
@property
|
|
|
|
def days_active(self) -> int:
|
|
|
|
"""Returns the number of days the user has been active.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
int: The number of days the user has been active.
|
|
|
|
"""
|
|
|
|
return int(self.data[0].value)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def characters(self) -> int:
|
|
|
|
"""Returns the number of characters the user has.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
int: The number of characters the user has.
|
|
|
|
"""
|
|
|
|
return int(self.data[1].value)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def achievements(self) -> int:
|
|
|
|
"""Returns the number of achievements the user has.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
int: The number of achievements the user has.
|
|
|
|
"""
|
|
|
|
return int(self.data[2].value)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def chests(self) -> int:
|
|
|
|
"""Returns the number of chests the user has found.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
int: The number of chests the user has found.
|
|
|
|
"""
|
|
|
|
return int(self.data[3].value)
|
2023-09-12 02:58:46 +00:00
|
|
|
|
|
|
|
|
2024-07-05 13:58:00 +00:00
|
|
|
class ZZZRecodeCard(RecordCard):
|
|
|
|
"""ZZZ record card."""
|
|
|
|
|
|
|
|
@property
|
|
|
|
def game(self) -> Game:
|
|
|
|
"""Returns the game associated with the record card.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
Game: The game associated with the record card.
|
|
|
|
"""
|
|
|
|
return Game.ZZZ
|
|
|
|
|
|
|
|
@property
|
|
|
|
def days_active(self) -> int:
|
|
|
|
"""Returns the number of days the user has been active.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
int: The number of days the user has been active.
|
|
|
|
"""
|
|
|
|
return int(self.data[0].value)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def world_level_name(self) -> str:
|
|
|
|
"""
|
|
|
|
Returns the user's world level name.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
str: The user's world level name.
|
|
|
|
"""
|
|
|
|
return self.data[1].value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def characters(self) -> int:
|
|
|
|
"""Returns the number of characters the user has.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
int: The number of characters the user has.
|
|
|
|
"""
|
|
|
|
return int(self.data[2].value)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def buddies(self) -> int:
|
|
|
|
"""Returns the number of buddies the user has found.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
int: The number of buddies the user has found.
|
|
|
|
"""
|
|
|
|
return int(self.data[3].value)
|
|
|
|
|
|
|
|
|
2023-09-12 02:58:46 +00:00
|
|
|
RECORD_CARD_MAP.setdefault(1, HonkaiRecordCard)
|
|
|
|
RECORD_CARD_MAP.setdefault(2, GenshinRecordCard)
|
|
|
|
RECORD_CARD_MAP.setdefault(6, StarRailRecodeCard)
|
2024-07-05 13:58:00 +00:00
|
|
|
RECORD_CARD_MAP.setdefault(8, ZZZRecodeCard)
|