diff --git a/nonebot_plugin_tetris_stats/games/tetrio/query.py b/nonebot_plugin_tetris_stats/games/tetrio/query.py index a6e9a40..659b281 100644 --- a/nonebot_plugin_tetris_stats/games/tetrio/query.py +++ b/nonebot_plugin_tetris_stats/games/tetrio/query.py @@ -30,13 +30,13 @@ from ...utils.host import HostPage, get_self_netloc from ...utils.metrics import TetrisMetricsProWithPPSVS, get_metrics from ...utils.render import render from ...utils.render.schemas.base import Avatar, Ranking -from ...utils.render.schemas.tetrio_info import Data, Radar, TetraLeague, TetraLeagueHistory -from ...utils.render.schemas.tetrio_info import Info as V1TemplateInfo -from ...utils.render.schemas.tetrio_info import User as V1TemplateUser -from ...utils.render.schemas.tetrio_info_v2 import Badge, Blitz, Sprint, Statistic, TetraLeagueStatistic -from ...utils.render.schemas.tetrio_info_v2 import Info as V2TemplateInfo -from ...utils.render.schemas.tetrio_info_v2 import TetraLeague as V2TemplateTetraLeague -from ...utils.render.schemas.tetrio_info_v2 import User as V2TemplateUser +from ...utils.render.schemas.tetrio.tetrio_info import Info as V1TemplateInfo +from ...utils.render.schemas.tetrio.tetrio_info import Radar, TetraLeague, TetraLeagueHistory, TetraLeagueHistoryData +from ...utils.render.schemas.tetrio.tetrio_info import User as V1TemplateUser +from ...utils.render.schemas.tetrio.tetrio_user_info_v2 import Badge, Blitz, Sprint, Statistic, TetraLeagueStatistic +from ...utils.render.schemas.tetrio.tetrio_user_info_v2 import Info as V2TemplateInfo +from ...utils.render.schemas.tetrio.tetrio_user_info_v2 import TetraLeague as V2TemplateTetraLeague +from ...utils.render.schemas.tetrio.tetrio_user_info_v2 import User as V2TemplateUser from ...utils.screenshot import screenshot from ...utils.typing import Me, Number from ..constant import CANT_VERIFY_MESSAGE @@ -129,10 +129,10 @@ def get_split(value_max: int, value_min: int) -> tuple[int, int]: def get_specified_point( - previous_point: Data, - behind_point: Data, + previous_point: TetraLeagueHistoryData, + behind_point: TetraLeagueHistoryData, point_time: datetime, -) -> Data: +) -> TetraLeagueHistoryData: """根据给出的 previous_point 和 behind_point, 推算 point_time 点处的数据 Args: @@ -147,13 +147,13 @@ def get_specified_point( slope = (behind_point.tr - previous_point.tr) / ( datetime.timestamp(behind_point.record_at) - datetime.timestamp(previous_point.record_at) ) - return Data( + return TetraLeagueHistoryData( record_at=point_time, tr=previous_point.tr + slope * (datetime.timestamp(point_time) - datetime.timestamp(previous_point.record_at)), ) -async def query_historical_data(user: User, user_info: UserInfoSuccess) -> list[Data]: +async def query_historical_data(user: User, user_info: UserInfoSuccess) -> list[TetraLeagueHistoryData]: today = datetime.now(ZoneInfo('Asia/Shanghai')).replace(hour=0, minute=0, second=0, microsecond=0) forward = timedelta(days=9) start_time = (today - forward).astimezone(UTC) @@ -183,11 +183,11 @@ async def query_historical_data(user: User, user_info: UserInfoSuccess) -> list[ full_export_data = FullExport.get_data(user.unique_identifier) if not historical_data and not full_export_data: return [ - Data(record_at=today - forward, tr=user_info.data.user.league.rating), - Data(record_at=today.replace(microsecond=1000), tr=user_info.data.user.league.rating), + TetraLeagueHistoryData(record_at=today - forward, tr=user_info.data.user.league.rating), + TetraLeagueHistoryData(record_at=today.replace(microsecond=1000), tr=user_info.data.user.league.rating), ] histories = [ - Data( + TetraLeagueHistoryData( record_at=i.update_time.astimezone(ZoneInfo('Asia/Shanghai')), tr=i.data.data.user.league.rating, ) @@ -208,7 +208,7 @@ async def query_historical_data(user: User, user_info: UserInfoSuccess) -> list[ histories.append( get_specified_point( histories[-1], - Data(record_at=user_info.cache.cached_at, tr=user_info.data.user.league.rating), + TetraLeagueHistoryData(record_at=user_info.cache.cached_at, tr=user_info.data.user.league.rating), today.replace(microsecond=1000), ) ) @@ -219,7 +219,7 @@ async def query_historical_data(user: User, user_info: UserInfoSuccess) -> list[ today - forward, ) else: - histories.insert(0, Data(record_at=today - forward, tr=histories[0].tr)) + histories.insert(0, TetraLeagueHistoryData(record_at=today - forward, tr=histories[0].tr)) return histories @@ -322,6 +322,7 @@ async def make_query_image_v2(player: Player) -> bytes: player.user, player.get_info(), player.sprint, player.blitz, player.zen ) league = get_league(user_info) + histories = await query_historical_data(user, user_info) if sprint.record is not None: duration = timedelta(milliseconds=sprint.record.endcontext.final_time).total_seconds() @@ -342,7 +343,7 @@ async def make_query_image_v2(player: Player) -> bytes: netloc = get_self_netloc() async with HostPage( await render( - 'v2/tetrio/info', + 'v2/tetrio/user/info', V2TemplateInfo( user=V2TemplateUser( id=user.ID, @@ -397,6 +398,7 @@ async def make_query_image_v2(player: Player) -> bytes: wins=league.gameswon, ), decaying=league.decaying, + history=histories, ) if isinstance(league, RatedLeague) else None, @@ -510,8 +512,8 @@ class FullExport: cls.latest_update = datetime.now(tz=ZoneInfo('Asia/Shanghai')).date() @classmethod - def get_data(cls, unique_identifier: str) -> list[Data]: - return [Data(record_at=i[0], tr=i[1]) for i in cls.cache[unique_identifier]] + def get_data(cls, unique_identifier: str) -> list[TetraLeagueHistoryData]: + return [TetraLeagueHistoryData(record_at=i[0], tr=i[1]) for i in cls.cache[unique_identifier]] @classmethod def start_time(cls) -> datetime: diff --git a/nonebot_plugin_tetris_stats/games/tetrio/record/blitz.py b/nonebot_plugin_tetris_stats/games/tetrio/record/blitz.py index 599a8a7..331e3c7 100644 --- a/nonebot_plugin_tetris_stats/games/tetrio/record/blitz.py +++ b/nonebot_plugin_tetris_stats/games/tetrio/record/blitz.py @@ -17,8 +17,8 @@ from ....utils.host import HostPage, get_self_netloc from ....utils.metrics import get_metrics from ....utils.render import render from ....utils.render.schemas.base import Avatar -from ....utils.render.schemas.tetrio_record_base import Finesse, Max, Mini, Tspins, User -from ....utils.render.schemas.tetrio_record_blitz import Record, Statistic +from ....utils.render.schemas.tetrio.tetrio_record_base import Finesse, Max, Mini, Tspins, User +from ....utils.render.schemas.tetrio.tetrio_record_blitz import Record, Statistic from ....utils.screenshot import screenshot from ....utils.typing import Me from ...constant import CANT_VERIFY_MESSAGE diff --git a/nonebot_plugin_tetris_stats/games/tetrio/record/sprint.py b/nonebot_plugin_tetris_stats/games/tetrio/record/sprint.py index 4cf6631..5b021d6 100644 --- a/nonebot_plugin_tetris_stats/games/tetrio/record/sprint.py +++ b/nonebot_plugin_tetris_stats/games/tetrio/record/sprint.py @@ -17,8 +17,8 @@ from ....utils.host import HostPage, get_self_netloc from ....utils.metrics import get_metrics from ....utils.render import render from ....utils.render.schemas.base import Avatar -from ....utils.render.schemas.tetrio_record_base import Finesse, Max, Mini, Tspins, User -from ....utils.render.schemas.tetrio_record_sprint import Record, Statistic +from ....utils.render.schemas.tetrio.tetrio_record_base import Finesse, Max, Mini, Tspins, User +from ....utils.render.schemas.tetrio.tetrio_record_sprint import Record, Statistic from ....utils.screenshot import screenshot from ....utils.typing import Me from ...constant import CANT_VERIFY_MESSAGE diff --git a/nonebot_plugin_tetris_stats/utils/render/__init__.py b/nonebot_plugin_tetris_stats/utils/render/__init__.py index bbe5e9b..4362234 100644 --- a/nonebot_plugin_tetris_stats/utils/render/__init__.py +++ b/nonebot_plugin_tetris_stats/utils/render/__init__.py @@ -5,10 +5,10 @@ from nonebot.compat import PYDANTIC_V2 from ..templates import templates_dir from .schemas.bind import Bind -from .schemas.tetrio_info import Info as TETRIOInfo -from .schemas.tetrio_info_v2 import Info as TETRIOInfoV2 -from .schemas.tetrio_record_blitz import Record as TETRIORecordBlitz -from .schemas.tetrio_record_sprint import Record as TETRIORecordSprint +from .schemas.tetrio.tetrio_info import Info as TETRIOInfo +from .schemas.tetrio.tetrio_record_blitz import Record as TETRIORecordBlitz +from .schemas.tetrio.tetrio_record_sprint import Record as TETRIORecordSprint +from .schemas.tetrio.tetrio_user_info_v2 import Info as TETRIOUserInfoV2 from .schemas.top_info import Info as TOPInfo from .schemas.tos_info import Info as TOSInfo @@ -34,7 +34,7 @@ async def render(render_type: Literal['v1/tos/info'], data: TOSInfo) -> str: ... @overload -async def render(render_type: Literal['v2/tetrio/info'], data: TETRIOInfoV2) -> str: ... +async def render(render_type: Literal['v2/tetrio/user/info'], data: TETRIOUserInfoV2) -> str: ... @overload @@ -51,11 +51,11 @@ async def render( 'v1/tetrio/info', 'v1/top/info', 'v1/tos/info', - 'v2/tetrio/info', + 'v2/tetrio/user/info', 'v2/tetrio/record/40l', 'v2/tetrio/record/blitz', ], - data: Bind | TETRIOInfo | TOPInfo | TOSInfo | TETRIOInfoV2 | TETRIORecordSprint | TETRIORecordBlitz, + data: Bind | TETRIOInfo | TOPInfo | TOSInfo | TETRIOUserInfoV2 | TETRIORecordSprint | TETRIORecordBlitz, ) -> str: if PYDANTIC_V2: return await env.get_template('index.html').render_async( diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio/base.py b/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio/base.py new file mode 100644 index 0000000..d55d928 --- /dev/null +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio/base.py @@ -0,0 +1,10 @@ +from datetime import datetime + +from pydantic import BaseModel + +from ....typing import Number + + +class TetraLeagueHistoryData(BaseModel): + record_at: datetime + tr: Number diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio/tetrio_info.py b/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio/tetrio_info.py new file mode 100644 index 0000000..3e345d5 --- /dev/null +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio/tetrio_info.py @@ -0,0 +1,49 @@ +from pydantic import BaseModel + +from .....games.tetrio.api.typing import Rank +from ....typing import Number +from ..base import People, Ranking +from .base import TetraLeagueHistoryData + + +class User(People): + bio: str | None + + +class TetraLeague(BaseModel): + rank: Rank + tr: Number + global_rank: Number + pps: Number + lpm: Number + apm: Number + apl: Number + vs: Number + adpm: Number + adpl: Number + + +class TetraLeagueHistory(BaseModel): + data: list[TetraLeagueHistoryData] + split_interval: Number + min_tr: Number + max_tr: Number + offset: Number + + +class Radar(BaseModel): + app: Number + dsps: Number + dspp: Number + ci: Number + ge: Number + + +class Info(BaseModel): + user: User + ranking: Ranking + tetra_league: TetraLeague + tetra_league_history: TetraLeagueHistory + radar: Radar + sprint: str + blitz: str diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio_record_base.py b/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio/tetrio_record_base.py similarity index 96% rename from nonebot_plugin_tetris_stats/utils/render/schemas/tetrio_record_base.py rename to nonebot_plugin_tetris_stats/utils/render/schemas/tetrio/tetrio_record_base.py index 8308d9b..9b1f988 100644 --- a/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio_record_base.py +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio/tetrio_record_base.py @@ -1,6 +1,6 @@ from pydantic import BaseModel -from .base import People +from ..base import People class User(People): diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio_record_blitz.py b/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio/tetrio_record_blitz.py similarity index 100% rename from nonebot_plugin_tetris_stats/utils/render/schemas/tetrio_record_blitz.py rename to nonebot_plugin_tetris_stats/utils/render/schemas/tetrio/tetrio_record_blitz.py diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio_record_sprint.py b/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio/tetrio_record_sprint.py similarity index 100% rename from nonebot_plugin_tetris_stats/utils/render/schemas/tetrio_record_sprint.py rename to nonebot_plugin_tetris_stats/utils/render/schemas/tetrio/tetrio_record_sprint.py diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio_info_v2.py b/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio/tetrio_user_info_v2.py similarity index 84% rename from nonebot_plugin_tetris_stats/utils/render/schemas/tetrio_info_v2.py rename to nonebot_plugin_tetris_stats/utils/render/schemas/tetrio/tetrio_user_info_v2.py index 9319557..dd954c5 100644 --- a/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio_info_v2.py +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio/tetrio_user_info_v2.py @@ -2,10 +2,11 @@ from datetime import datetime from pydantic import BaseModel -from ....games.tetrio.api.schemas.user_records import Zen -from ....games.tetrio.api.typing import Rank -from ...typing import Number -from .base import Avatar +from .....games.tetrio.api.schemas.user_records import Zen +from .....games.tetrio.api.typing import Rank +from ....typing import Number +from ..base import Avatar +from .base import TetraLeagueHistoryData class Badge(BaseModel): @@ -72,6 +73,8 @@ class TetraLeague(BaseModel): decaying: bool + history: list[TetraLeagueHistoryData] + class Sprint(BaseModel): time: str diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio_info.py b/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio_info.py deleted file mode 100644 index 5df176d..0000000 --- a/nonebot_plugin_tetris_stats/utils/render/schemas/tetrio_info.py +++ /dev/null @@ -1,72 +0,0 @@ -from datetime import datetime -from typing import Annotated, ClassVar - -from nonebot.compat import PYDANTIC_V2 -from pydantic import BaseModel - -from ....games.tetrio.api.typing import Rank -from ...typing import Number -from .base import People, Ranking - -if PYDANTIC_V2: - from pydantic import PlainSerializer - - -def format_datetime_to_timestamp(dt: datetime) -> int: - return int(dt.timestamp() * 1000) - - -class User(People): - bio: str | None - - -class TetraLeague(BaseModel): - rank: Rank - tr: Number - global_rank: Number - pps: Number - lpm: Number - apm: Number - apl: Number - vs: Number - adpm: Number - adpl: Number - - -class Data(BaseModel): - if PYDANTIC_V2: - record_at: Annotated[datetime, PlainSerializer(format_datetime_to_timestamp, return_type=int)] - else: - record_at: datetime # type: ignore[no-redef] - tr: Number - - -class TetraLeagueHistory(BaseModel): - data: list[Data] - split_interval: Number - min_tr: Number - max_tr: Number - offset: Number - - -class Radar(BaseModel): - app: Number - dsps: Number - dspp: Number - ci: Number - ge: Number - - -class Info(BaseModel): - user: User - ranking: Ranking - tetra_league: TetraLeague - tetra_league_history: TetraLeagueHistory - radar: Radar - sprint: str - blitz: str - - if not PYDANTIC_V2: - - class Config: - json_encoders: ClassVar[dict] = {datetime: format_datetime_to_timestamp}