🐛 修复 leagueflow 没有有效数据爆炸 (#508)

This commit is contained in:
呵呵です
2024-10-28 21:58:38 +08:00
committed by GitHub
parent b3a77f5296
commit 381f2505d6
3 changed files with 93 additions and 85 deletions

View File

@@ -1,6 +1,6 @@
from datetime import datetime from datetime import datetime
from enum import IntEnum from enum import IntEnum
from typing import NamedTuple from typing import Literal, NamedTuple
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
@@ -28,11 +28,16 @@ class Point(NamedTuple):
class Data(BaseModel): class Data(BaseModel):
start_time: datetime = Field(..., alias='startTime') start_time: datetime = Field(..., alias='startTime')
points: list[Point] points: list[Point] = Field(..., min_length=1)
class Empty(BaseModel):
start_time: Literal[9007199254740991] = Field(..., alias='startTime')
points: list = Field(..., max_length=0)
class LeagueFlowSuccess(BaseSuccessModel): class LeagueFlowSuccess(BaseSuccessModel):
data: Data data: Data | Empty
LeagueFlow = LeagueFlowSuccess | FailedModel LeagueFlow = LeagueFlowSuccess | FailedModel

View File

@@ -5,7 +5,7 @@ from zoneinfo import ZoneInfo
from ....utils.exception import FallbackError from ....utils.exception import FallbackError
from ....utils.render.schemas.tetrio.user.base import TetraLeagueHistoryData from ....utils.render.schemas.tetrio.user.base import TetraLeagueHistoryData
from ..api.schemas.labs.leagueflow import LeagueFlowSuccess from ..api.schemas.labs.leagueflow import Empty, LeagueFlowSuccess
from ..api.schemas.summaries.league import LeagueSuccessModel, NeverPlayedData, NeverRatedData, RatedData from ..api.schemas.summaries.league import LeagueSuccessModel, NeverPlayedData, NeverRatedData, RatedData
@@ -13,6 +13,8 @@ def flow_to_history(
leagueflow: LeagueFlowSuccess, leagueflow: LeagueFlowSuccess,
handle: Callable[[list[TetraLeagueHistoryData]], list[TetraLeagueHistoryData]] | None = None, handle: Callable[[list[TetraLeagueHistoryData]], list[TetraLeagueHistoryData]] | None = None,
) -> list[TetraLeagueHistoryData]: ) -> list[TetraLeagueHistoryData]:
if isinstance(leagueflow.data, Empty):
raise FallbackError
start_time = leagueflow.data.start_time.astimezone(ZoneInfo('Asia/Shanghai')) start_time = leagueflow.data.start_time.astimezone(ZoneInfo('Asia/Shanghai'))
ret = [ ret = [
TetraLeagueHistoryData( TetraLeagueHistoryData(

View File

@@ -4,6 +4,7 @@ from hashlib import md5
from yarl import URL from yarl import URL
from ....utils.exception import FallbackError
from ....utils.host import HostPage, get_self_netloc from ....utils.host import HostPage, get_self_netloc
from ....utils.metrics import get_metrics from ....utils.metrics import get_metrics
from ....utils.render import render from ....utils.render import render
@@ -49,89 +50,89 @@ async def make_query_image_v2(player: Player) -> bytes:
play_time = f'{game_time:.0f}s' play_time = f'{game_time:.0f}s'
else: else:
play_time = game_time play_time = game_time
try:
history = flow_to_history(leagueflow, lambda x: x[-100:])
except FallbackError:
history = None
netloc = get_self_netloc() netloc = get_self_netloc()
async with ( async with HostPage(
HostPage( await render(
await render( 'v2/tetrio/user/info',
'v2/tetrio/user/info', Info(
Info( user=User(
user=User( id=user.ID,
id=user.ID, name=user.name.upper(),
name=user.name.upper(), bio=user_info.data.bio,
bio=user_info.data.bio, banner=str(
banner=str( URL(f'http://{netloc}/host/resource/tetrio/banners/{user.ID}') % {'revision': banner_revision}
URL(f'http://{netloc}/host/resource/tetrio/banners/{user.ID}') )
% {'revision': banner_revision} if banner_revision is not None and banner_revision != 0
) else None,
if banner_revision is not None and banner_revision != 0 avatar=str(
else None, URL(f'http://{netloc}/host/resource/tetrio/avatars/{user.ID}') % {'revision': avatar_revision}
avatar=str( )
URL(f'http://{netloc}/host/resource/tetrio/avatars/{user.ID}') if avatar_revision is not None and avatar_revision != 0
% {'revision': avatar_revision} else Avatar(
) type='identicon',
if avatar_revision is not None and avatar_revision != 0 hash=md5(user.ID.encode()).hexdigest(), # noqa: S324
else Avatar(
type='identicon',
hash=md5(user.ID.encode()).hexdigest(), # noqa: S324
),
badges=[
Badge(
id=i.id,
description=i.label,
group=i.group,
receive_at=i.ts if isinstance(i.ts, datetime) else None,
)
for i in user_info.data.badges
],
country=user_info.data.country,
role=user_info.data.role,
xp=user_info.data.xp,
friend_count=user_info.data.friend_count,
supporter_tier=user_info.data.supporter_tier,
bad_standing=user_info.data.badstanding or False,
playtime=play_time,
join_at=user_info.data.ts,
), ),
tetra_league=TetraLeague( badges=[
rank=league.data.rank, Badge(
highest_rank='z' if isinstance(league.data, NeverRatedData) else league.data.bestrank, id=i.id,
tr=round(league.data.tr, 2), description=i.label,
glicko=round(league.data.glicko, 2), group=i.group,
rd=round(league.data.rd, 2), receive_at=i.ts if isinstance(i.ts, datetime) else None,
global_rank=league.data.standing, )
country_rank=league.data.standing_local, for i in user_info.data.badges
pps=(metrics := get_metrics(pps=league.data.pps, apm=league.data.apm, vs=league.data.vs)).pps, ],
apm=metrics.apm, country=user_info.data.country,
apl=metrics.apl, role=user_info.data.role,
vs=metrics.vs, xp=user_info.data.xp,
adpl=metrics.adpl, friend_count=user_info.data.friend_count,
statistic=TetraLeagueStatistic(total=league.data.gamesplayed, wins=league.data.gameswon), supporter_tier=user_info.data.supporter_tier,
decaying=league.data.decaying, bad_standing=user_info.data.badstanding or False,
history=flow_to_history(leagueflow, lambda x: x[-100:]), playtime=play_time,
) join_at=user_info.data.ts,
if not isinstance(league.data, NeverPlayedData)
else None,
statistic=Statistic(
total=handling_special_value(user_info.data.gamesplayed),
wins=handling_special_value(user_info.data.gameswon),
),
sprint=Sprint(
time=sprint_value,
global_rank=sprint.data.rank,
play_at=sprint.data.record.ts,
)
if sprint.data.record is not None
else None,
blitz=Blitz(
score=blitz.data.record.results.stats.score,
global_rank=blitz.data.rank,
play_at=blitz.data.record.ts,
)
if blitz.data.record is not None
else None,
zen=Zen(level=zen.data.level, score=zen.data.score),
), ),
tetra_league=TetraLeague(
rank=league.data.rank,
highest_rank='z' if isinstance(league.data, NeverRatedData) else league.data.bestrank,
tr=round(league.data.tr, 2),
glicko=round(league.data.glicko, 2),
rd=round(league.data.rd, 2),
global_rank=league.data.standing,
country_rank=league.data.standing_local,
pps=(metrics := get_metrics(pps=league.data.pps, apm=league.data.apm, vs=league.data.vs)).pps,
apm=metrics.apm,
apl=metrics.apl,
vs=metrics.vs,
adpl=metrics.adpl,
statistic=TetraLeagueStatistic(total=league.data.gamesplayed, wins=league.data.gameswon),
decaying=league.data.decaying,
history=history,
)
if not isinstance(league.data, NeverPlayedData)
else None,
statistic=Statistic(
total=handling_special_value(user_info.data.gamesplayed),
wins=handling_special_value(user_info.data.gameswon),
),
sprint=Sprint(
time=sprint_value,
global_rank=sprint.data.rank,
play_at=sprint.data.record.ts,
)
if sprint.data.record is not None
else None,
blitz=Blitz(
score=blitz.data.record.results.stats.score,
global_rank=blitz.data.rank,
play_at=blitz.data.record.ts,
)
if blitz.data.record is not None
else None,
zen=Zen(level=zen.data.level, score=zen.data.score),
), ),
) as page_hash ),
): ) as page_hash:
return await screenshot(f'http://{netloc}/host/{page_hash}.html') return await screenshot(f'http://{netloc}/host/{page_hash}.html')