diff --git a/nonebot_plugin_tetris_stats/games/tetrio/bind.py b/nonebot_plugin_tetris_stats/games/tetrio/bind.py index c5e6c48..7eb104d 100644 --- a/nonebot_plugin_tetris_stats/games/tetrio/bind.py +++ b/nonebot_plugin_tetris_stats/games/tetrio/bind.py @@ -14,12 +14,12 @@ from yarl import URL from ...config.config import global_config from ...db import BindStatus, create_or_update_bind, trigger -from ...utils.host import HostPage, get_self_netloc +from ...utils.host import get_self_netloc from ...utils.image import get_avatar from ...utils.lang import get_lang -from ...utils.render import Bind, render +from ...utils.render import render_image from ...utils.render.schemas.base import Avatar, People -from ...utils.screenshot import screenshot +from ...utils.render.schemas.bind import Bind from . import alc, command, get_player from .api import Player from .constant import GAME_TYPE @@ -113,35 +113,31 @@ async def make_bind_image( player: Player, event_session: Uninfo, interface: QryItrface, *, verify: bool | None = None ) -> bytes: (user, avatar_revision) = await gather(player.user, player.avatar_revision) - netloc = get_self_netloc() - async with HostPage( - await render( - 'v1/binding', - Bind( - platform='TETR.IO', - type='unknown' if verify is None else 'success' if verify else 'unverified', - user=People( - avatar=str( - URL(f'http://{netloc}/host/resource/tetrio/avatars/{user.ID}') % {'revision': avatar_revision} - ) - if avatar_revision is not None and avatar_revision != 0 - else Avatar(type='identicon', hash=md5(user.ID.encode()).hexdigest()), # noqa: S324 - name=user.name.upper(), - ), - bot=People( - avatar=await get_avatar( - ( - bot_user := await interface.get_user(event_session.self_id) - or UninfoUser(id=event_session.self_id) - ), - 'Data URI', - '../../static/logo/logo.svg', - ), - name=bot_user.nick or bot_user.name or choice(list(global_config.nickname) or ['bot']), - ), - prompt='io查我', - lang=get_lang(), + return await render_image( + Bind( + platform='TETR.IO', + type='unknown' if verify is None else 'success' if verify else 'unverified', + user=People( + avatar=str( + URL(f'http://{get_self_netloc()}/host/resource/tetrio/avatars/{user.ID}') + % {'revision': avatar_revision} + ) + if avatar_revision is not None and avatar_revision != 0 + else Avatar(type='identicon', hash=md5(user.ID.encode()).hexdigest()), # noqa: S324 + name=user.name.upper(), ), - ) - ) as page_hash: - return await screenshot(f'http://{netloc}/host/{page_hash}.html') + bot=People( + avatar=await get_avatar( + ( + bot_user := await interface.get_user(event_session.self_id) + or UninfoUser(id=event_session.self_id) + ), + 'Data URI', + '../../static/logo/logo.svg', + ), + name=bot_user.nick or bot_user.name or choice(list(global_config.nickname) or ['bot']), + ), + prompt='io查我', + lang=get_lang(), + ), + ) diff --git a/nonebot_plugin_tetris_stats/games/tetrio/list.py b/nonebot_plugin_tetris_stats/games/tetrio/list.py index a3cb1d5..f565529 100644 --- a/nonebot_plugin_tetris_stats/games/tetrio/list.py +++ b/nonebot_plugin_tetris_stats/games/tetrio/list.py @@ -4,12 +4,10 @@ from nonebot_plugin_uninfo import Uninfo from nonebot_plugin_uninfo.orm import get_session_persist_id from ...db import trigger -from ...utils.host import HostPage, get_self_netloc from ...utils.lang import get_lang from ...utils.metrics import get_metrics -from ...utils.render import render +from ...utils.render import render_image from ...utils.render.schemas.v2.tetrio.user.list import Data, List, TetraLeague, User -from ...utils.screenshot import screenshot from .. import alc from . import command from .api.leaderboards import by @@ -59,9 +57,8 @@ async def _( country=country, ) league = await by('league', parameter) - async with HostPage( - await render( - 'v2/tetrio/user/list', + await UniMessage.image( + raw=await render_image( List( show_index=True, data=[ @@ -92,5 +89,4 @@ async def _( lang=get_lang(), ), ) - ) as page_hash: - await UniMessage.image(raw=await screenshot(f'http://{get_self_netloc()}/host/{page_hash}.html')).finish() + ).finish() diff --git a/nonebot_plugin_tetris_stats/games/tetrio/query/v1.py b/nonebot_plugin_tetris_stats/games/tetrio/query/v1.py index b8100f4..2d97042 100644 --- a/nonebot_plugin_tetris_stats/games/tetrio/query/v1.py +++ b/nonebot_plugin_tetris_stats/games/tetrio/query/v1.py @@ -6,14 +6,13 @@ from yarl import URL from ....utils.chart import get_split, get_value_bounds, handle_history_data from ....utils.exception import FallbackError -from ....utils.host import HostPage, get_self_netloc +from ....utils.host import get_self_netloc from ....utils.lang import get_lang from ....utils.metrics import get_metrics -from ....utils.render import render +from ....utils.render import render_image from ....utils.render.schemas.base import Avatar, Trending from ....utils.render.schemas.v1.base import History -from ....utils.render.schemas.v1.tetrio.user.info import Info, Multiplayer, Singleplayer, User -from ....utils.screenshot import screenshot +from ....utils.render.schemas.v1.tetrio.info import Info, Multiplayer, Singleplayer, User from ..api import Player from ..api.schemas.summaries.league import RatedData from ..constant import TR_MAX, TR_MIN @@ -40,61 +39,57 @@ async def make_query_image_v1(player: Player) -> bytes: else: sprint_value = 'N/A' blitz_value = f'{blitz.data.record.results.stats.score:,}' if blitz.data.record is not None else 'N/A' - netloc = get_self_netloc() dsps: float dspp: float # make mypy happy - async with HostPage( - page=await render( - 'v1/tetrio/info', - Info( - user=User( - avatar=str( - URL(f'http://{netloc}/host/resource/tetrio/avatars/{user.ID}') % {'revision': avatar_revision} - ) - if avatar_revision is not None and avatar_revision != 0 - else Avatar( - type='identicon', - hash=md5(user.ID.encode()).hexdigest(), # noqa: S324 - ), - name=user.name.upper(), - bio=user_info.data.bio, + return await render_image( + Info( + user=User( + avatar=str( + URL(f'http://{get_self_netloc()}/host/resource/tetrio/avatars/{user.ID}') + % {'revision': avatar_revision} + ) + if avatar_revision is not None and avatar_revision != 0 + else Avatar( + type='identicon', + hash=md5(user.ID.encode()).hexdigest(), # noqa: S324 ), - multiplayer=Multiplayer( - glicko=f'{round(league_data.glicko, 2):,}', - rd=round(league_data.rd, 2), - rank=league_data.rank, - tr=f'{round(league_data.tr, 2):,}', - global_rank=league_data.standing, - history=History( - data=histories, - split_interval=split_value, - min_value=values.value_min, - max_value=values.value_max, - offset=offset, - ), - lpm=(metrics := get_metrics(pps=league_data.pps, apm=league_data.apm, vs=league_data.vs)).lpm, - pps=metrics.pps, - lpm_trending=Trending.KEEP, - apm=metrics.apm, - apl=metrics.apl, - apm_trending=Trending.KEEP, - adpm=metrics.adpm, - vs=metrics.vs, - adpl=metrics.adpl, - adpm_trending=Trending.KEEP, - app=(app := (league_data.apm / (60 * league_data.pps))), - dsps=(dsps := ((league_data.vs / 100) - (league_data.apm / 60))), - dspp=(dspp := (dsps / league_data.pps)), - ci=150 * dspp - 125 * app + 50 * (league_data.vs / league_data.apm) - 25, - ge=2 * ((app * dsps) / league_data.pps), - ), - singleplayer=Singleplayer( - sprint=sprint_value, - blitz=blitz_value, - ), - lang=get_lang(), + name=user.name.upper(), + bio=user_info.data.bio, ), - ) - ) as page_hash: - return await screenshot(f'http://{netloc}/host/{page_hash}.html') + multiplayer=Multiplayer( + glicko=f'{round(league_data.glicko, 2):,}', + rd=round(league_data.rd, 2), + rank=league_data.rank, + tr=f'{round(league_data.tr, 2):,}', + global_rank=league_data.standing, + history=History( + data=histories, + split_interval=split_value, + min_value=values.value_min, + max_value=values.value_max, + offset=offset, + ), + lpm=(metrics := get_metrics(pps=league_data.pps, apm=league_data.apm, vs=league_data.vs)).lpm, + pps=metrics.pps, + lpm_trending=Trending.KEEP, + apm=metrics.apm, + apl=metrics.apl, + apm_trending=Trending.KEEP, + adpm=metrics.adpm, + vs=metrics.vs, + adpl=metrics.adpl, + adpm_trending=Trending.KEEP, + app=(app := (league_data.apm / (60 * league_data.pps))), + dsps=(dsps := ((league_data.vs / 100) - (league_data.apm / 60))), + dspp=(dspp := (dsps / league_data.pps)), + ci=150 * dspp - 125 * app + 50 * (league_data.vs / league_data.apm) - 25, + ge=2 * ((app * dsps) / league_data.pps), + ), + singleplayer=Singleplayer( + sprint=sprint_value, + blitz=blitz_value, + ), + lang=get_lang(), + ), + ) diff --git a/nonebot_plugin_tetris_stats/games/tetrio/query/v2.py b/nonebot_plugin_tetris_stats/games/tetrio/query/v2.py index a2a199f..e230693 100644 --- a/nonebot_plugin_tetris_stats/games/tetrio/query/v2.py +++ b/nonebot_plugin_tetris_stats/games/tetrio/query/v2.py @@ -5,10 +5,10 @@ from hashlib import md5 from yarl import URL from ....utils.exception import FallbackError -from ....utils.host import HostPage, get_self_netloc +from ....utils.host import get_self_netloc from ....utils.lang import get_lang from ....utils.metrics import get_metrics -from ....utils.render import render +from ....utils.render import render_image from ....utils.render.schemas.base import Avatar from ....utils.render.schemas.v2.tetrio.user.info import ( Achievement, @@ -25,7 +25,6 @@ from ....utils.render.schemas.v2.tetrio.user.info import ( Zen, Zenith, ) -from ....utils.screenshot import screenshot from ..api import Player from ..api.schemas.summaries.league import InvalidData, NeverPlayedData, NeverRatedData from .tools import flow_to_history, handling_special_value @@ -74,137 +73,133 @@ async def make_query_image_v2(player: Player) -> bytes: except FallbackError: history = None netloc = get_self_netloc() - async with HostPage( - await render( - 'v2/tetrio/user/info', - Info( - user=User( - id=user.ID, - name=user.name.upper(), - country=user_info.data.country, - role=user_info.data.role, - botmaster=user_info.data.botmaster, - avatar=str( - URL(f'http://{netloc}/host/resource/tetrio/avatars/{user.ID}') % {'revision': avatar_revision} - ) - if avatar_revision is not None and avatar_revision != 0 - else Avatar( - type='identicon', - hash=md5(user.ID.encode()).hexdigest(), # noqa: S324 - ), - banner=str( - 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, - bio=user_info.data.bio, - friend_count=user_info.data.friend_count, - supporter_tier=user_info.data.supporter_tier, - bad_standing=user_info.data.badstanding or False, - 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 - ], - xp=user_info.data.xp, - ar=user_info.data.ar, - achievements=[ - Achievement( - key=i.achievement_id, - rank_type=i.rank_type, - ar_type=i.ar_type, - stub=i.stub, - rank=i.rank, - achieved_score=i.achieved_score, - pos=i.pos, - progress=i.progress, - total=i.total, - ) - for i in achievements.data - ], - playtime=play_time, - join_at=user_info.data.ts, - ), - 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, + return await render_image( + Info( + user=User( + id=user.ID, + name=user.name.upper(), + country=user_info.data.country, + role=user_info.data.role, + botmaster=user_info.data.botmaster, + avatar=str( + URL(f'http://{netloc}/host/resource/tetrio/avatars/{user.ID}') % {'revision': avatar_revision} ) - if not isinstance(league.data, NeverPlayedData | InvalidData) - else None, - zenith=Zenith( - week=Week( - altitude=zenith.data.record.results.stats.zenith.altitude, - global_rank=zenith.data.rank, - country_rank=zenith.data.rank_local, - play_at=zenith.data.record.ts, - ) - if zenith.data.record is not None - else None, - best=Best( - altitude=zenith.data.best.record.results.stats.zenith.altitude, - global_rank=zenith.data.best.rank, - play_at=zenith.data.best.record.ts, - ) - if zenith.data.best.record is not None - else None, + if avatar_revision is not None and avatar_revision != 0 + else Avatar( + type='identicon', + hash=md5(user.ID.encode()).hexdigest(), # noqa: S324 ), - zenithex=Zenith( - week=Week( - altitude=zenithex.data.record.results.stats.zenith.altitude, - global_rank=zenithex.data.rank, - country_rank=zenithex.data.rank_local, - play_at=zenithex.data.record.ts, - ) - if zenithex.data.record is not None - else None, - best=Best( - altitude=zenithex.data.best.record.results.stats.zenith.altitude, - global_rank=zenithex.data.best.rank, - play_at=zenithex.data.best.record.ts, - ) - if zenithex.data.best.record is not None - 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, - country_rank=sprint.data.rank_local, - play_at=sprint.data.record.ts, + banner=str( + URL(f'http://{netloc}/host/resource/tetrio/banners/{user.ID}') % {'revision': banner_revision} ) - if sprint.data.record is not None + if banner_revision is not None and banner_revision != 0 else None, - blitz=Blitz( - score=blitz.data.record.results.stats.score, - global_rank=blitz.data.rank, - country_rank=blitz.data.rank_local, - 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), - lang=get_lang(), + bio=user_info.data.bio, + friend_count=user_info.data.friend_count, + supporter_tier=user_info.data.supporter_tier, + bad_standing=user_info.data.badstanding or False, + 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 + ], + xp=user_info.data.xp, + ar=user_info.data.ar, + achievements=[ + Achievement( + key=i.achievement_id, + rank_type=i.rank_type, + ar_type=i.ar_type, + stub=i.stub, + rank=i.rank, + achieved_score=i.achieved_score, + pos=i.pos, + progress=i.progress, + total=i.total, + ) + for i in achievements.data + ], + playtime=play_time, + join_at=user_info.data.ts, ), + 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 | InvalidData) + else None, + zenith=Zenith( + week=Week( + altitude=zenith.data.record.results.stats.zenith.altitude, + global_rank=zenith.data.rank, + country_rank=zenith.data.rank_local, + play_at=zenith.data.record.ts, + ) + if zenith.data.record is not None + else None, + best=Best( + altitude=zenith.data.best.record.results.stats.zenith.altitude, + global_rank=zenith.data.best.rank, + play_at=zenith.data.best.record.ts, + ) + if zenith.data.best.record is not None + else None, + ), + zenithex=Zenith( + week=Week( + altitude=zenithex.data.record.results.stats.zenith.altitude, + global_rank=zenithex.data.rank, + country_rank=zenithex.data.rank_local, + play_at=zenithex.data.record.ts, + ) + if zenithex.data.record is not None + else None, + best=Best( + altitude=zenithex.data.best.record.results.stats.zenith.altitude, + global_rank=zenithex.data.best.rank, + play_at=zenithex.data.best.record.ts, + ) + if zenithex.data.best.record is not None + 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, + country_rank=sprint.data.rank_local, + 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, + country_rank=blitz.data.rank_local, + 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), + lang=get_lang(), ), - ) as page_hash: - return await screenshot(f'http://{netloc}/host/{page_hash}.html') + ) diff --git a/nonebot_plugin_tetris_stats/games/tetrio/rank/all.py b/nonebot_plugin_tetris_stats/games/tetrio/rank/all.py index 47d35c0..bbcd77f 100644 --- a/nonebot_plugin_tetris_stats/games/tetrio/rank/all.py +++ b/nonebot_plugin_tetris_stats/games/tetrio/rank/all.py @@ -9,16 +9,14 @@ from sqlalchemy import select from sqlalchemy.orm import selectinload from ....db import trigger -from ....utils.host import HostPage, get_self_netloc from ....utils.lang import get_lang from ....utils.metrics import get_metrics -from ....utils.render import render +from ....utils.render import render_image from ....utils.render.schemas.v1.tetrio.rank import Data as DataV1 from ....utils.render.schemas.v1.tetrio.rank import ItemData as ItemDataV1 from ....utils.render.schemas.v2.tetrio.rank import AverageData as AverageDataV2 from ....utils.render.schemas.v2.tetrio.rank import Data as DataV2 from ....utils.render.schemas.v2.tetrio.rank import ItemData as ItemDataV2 -from ....utils.screenshot import screenshot from .. import alc from ..constant import GAME_TYPE from ..models import TETRIOLeagueStats @@ -94,49 +92,41 @@ async def _(event_session: Uninfo, template: Template | None = None): async def make_image_v1(latest_data: TETRIOLeagueStats, compare_data: TETRIOLeagueStats) -> bytes: - async with HostPage( - await render( - 'v1/tetrio/rank', - DataV1( - items={ - i[0].rank: ItemDataV1( - trending=round(i[0].tr_line - i[1].tr_line, 2), - require_tr=round(i[0].tr_line, 2), - players=i[0].player_count, - ) - for i in zip(latest_data.fields, compare_data.fields, strict=True) - }, - updated_at=latest_data.update_time, - lang=get_lang(), - ), - ) - ) as page_hash: - return await screenshot(f'http://{get_self_netloc()}/host/{page_hash}.html') + return await render_image( + DataV1( + items={ + i[0].rank: ItemDataV1( + trending=round(i[0].tr_line - i[1].tr_line, 2), + require_tr=round(i[0].tr_line, 2), + players=i[0].player_count, + ) + for i in zip(latest_data.fields, compare_data.fields, strict=True) + }, + updated_at=latest_data.update_time, + lang=get_lang(), + ), + ) async def make_image_v2(latest_data: TETRIOLeagueStats, compare_data: TETRIOLeagueStats) -> bytes: - async with HostPage( - await render( - 'v2/tetrio/rank', - DataV2( - items={ - i[0].rank: ItemDataV2( - require_tr=round(i[0].tr_line, 2), - trending=round(i[0].tr_line - i[1].tr_line, 2), - average_data=AverageDataV2( - pps=(metrics := get_metrics(pps=i[0].avg_pps, apm=i[0].avg_apm, vs=i[0].avg_vs)).pps, - apm=metrics.apm, - apl=metrics.apl, - vs=metrics.vs, - adpl=metrics.adpl, - ), - players=i[0].player_count, - ) - for i in zip(latest_data.fields, compare_data.fields, strict=True) - }, - updated_at=latest_data.update_time, - lang=get_lang(), - ), - ) - ) as page_hash: - return await screenshot(f'http://{get_self_netloc()}/host/{page_hash}.html') + return await render_image( + DataV2( + items={ + i[0].rank: ItemDataV2( + require_tr=round(i[0].tr_line, 2), + trending=round(i[0].tr_line - i[1].tr_line, 2), + average_data=AverageDataV2( + pps=(metrics := get_metrics(pps=i[0].avg_pps, apm=i[0].avg_apm, vs=i[0].avg_vs)).pps, + apm=metrics.apm, + apl=metrics.apl, + vs=metrics.vs, + adpl=metrics.adpl, + ), + players=i[0].player_count, + ) + for i in zip(latest_data.fields, compare_data.fields, strict=True) + }, + updated_at=latest_data.update_time, + lang=get_lang(), + ), + ) diff --git a/nonebot_plugin_tetris_stats/games/tetrio/rank/detail.py b/nonebot_plugin_tetris_stats/games/tetrio/rank/detail.py index eefd0aa..ff4c699 100644 --- a/nonebot_plugin_tetris_stats/games/tetrio/rank/detail.py +++ b/nonebot_plugin_tetris_stats/games/tetrio/rank/detail.py @@ -11,12 +11,10 @@ from sqlalchemy import select from sqlalchemy.orm import selectinload from ....db import trigger -from ....utils.host import HostPage, get_self_netloc from ....utils.lang import get_lang from ....utils.metrics import get_metrics -from ....utils.render import render +from ....utils.render import render_image from ....utils.render.schemas.v2.tetrio.rank.detail import Data, SpecialData -from ....utils.screenshot import screenshot from .. import alc from ..api.typedefs import ValidRank from ..constant import GAME_TYPE @@ -114,40 +112,36 @@ async def make_image(rank: ValidRank, latest: TETRIOLeagueStats, compare: TETRIO max_vs = get_metrics( pps=latest_data.high_vs.league.pps, apm=latest_data.high_vs.league.apm, vs=latest_data.high_vs.league.vs ) - async with HostPage( - await render( - 'v2/tetrio/rank/detail', - Data( - name=latest_data.rank, - trending=round(latest_data.tr_line - compare_data.tr_line, 2), - require_tr=round(latest_data.tr_line, 2), - players=latest_data.player_count, - minimum_data=SpecialData( - apm=low_apm.apm, - pps=low_pps.pps, - lpm=low_pps.lpm, - vs=low_vs.vs, - adpm=low_vs.adpm, - apm_holder=latest_data.low_apm.username.upper(), - pps_holder=latest_data.low_pps.username.upper(), - vs_holder=latest_data.low_vs.username.upper(), - ), - average_data=SpecialData( - apm=avg.apm, pps=avg.pps, lpm=avg.lpm, vs=avg.vs, adpm=avg.adpm, apl=avg.apl, adpl=avg.adpl - ), - maximum_data=SpecialData( - apm=max_apm.apm, - pps=max_pps.pps, - lpm=max_pps.lpm, - vs=max_vs.vs, - adpm=max_vs.adpm, - apm_holder=latest_data.high_apm.username.upper(), - pps_holder=latest_data.high_pps.username.upper(), - vs_holder=latest_data.high_vs.username.upper(), - ), - updated_at=latest.update_time.replace(tzinfo=UTC).astimezone(ZoneInfo('Asia/Shanghai')), - lang=get_lang(), + return await render_image( + Data( + name=latest_data.rank, + trending=round(latest_data.tr_line - compare_data.tr_line, 2), + require_tr=round(latest_data.tr_line, 2), + players=latest_data.player_count, + minimum_data=SpecialData( + apm=low_apm.apm, + pps=low_pps.pps, + lpm=low_pps.lpm, + vs=low_vs.vs, + adpm=low_vs.adpm, + apm_holder=latest_data.low_apm.username.upper(), + pps_holder=latest_data.low_pps.username.upper(), + vs_holder=latest_data.low_vs.username.upper(), ), - ) - ) as page_hash: - return await screenshot(f'http://{get_self_netloc()}/host/{page_hash}.html') + average_data=SpecialData( + apm=avg.apm, pps=avg.pps, lpm=avg.lpm, vs=avg.vs, adpm=avg.adpm, apl=avg.apl, adpl=avg.adpl + ), + maximum_data=SpecialData( + apm=max_apm.apm, + pps=max_pps.pps, + lpm=max_pps.lpm, + vs=max_vs.vs, + adpm=max_vs.adpm, + apm_holder=latest_data.high_apm.username.upper(), + pps_holder=latest_data.high_pps.username.upper(), + vs_holder=latest_data.high_vs.username.upper(), + ), + updated_at=latest.update_time.replace(tzinfo=UTC).astimezone(ZoneInfo('Asia/Shanghai')), + lang=get_lang(), + ), + ) diff --git a/nonebot_plugin_tetris_stats/games/tetrio/record/blitz.py b/nonebot_plugin_tetris_stats/games/tetrio/record/blitz.py index cb30339..30f74a5 100644 --- a/nonebot_plugin_tetris_stats/games/tetrio/record/blitz.py +++ b/nonebot_plugin_tetris_stats/games/tetrio/record/blitz.py @@ -15,14 +15,13 @@ from yarl import URL from ....db import query_bind_info, trigger from ....i18n import Lang from ....utils.exception import RecordNotFoundError -from ....utils.host import HostPage, get_self_netloc +from ....utils.host import get_self_netloc from ....utils.lang import get_lang from ....utils.metrics import get_metrics -from ....utils.render import render +from ....utils.render import render_image from ....utils.render.schemas.base import Avatar from ....utils.render.schemas.v2.tetrio.record.base import Finesse, Max, Mini, Tspins, User from ....utils.render.schemas.v2.tetrio.record.blitz import Record, Statistic -from ....utils.screenshot import screenshot from ....utils.typedefs import Me from .. import alc from ..api.player import Player @@ -88,66 +87,62 @@ async def make_blitz_image(player: Player) -> bytes: duration = timedelta(milliseconds=stats.finaltime).total_seconds() metrics = get_metrics(pps=stats.piecesplaced / duration) netloc = get_self_netloc() - async with HostPage( - page=await render( - 'v2/tetrio/record/blitz', - Record( - type='best', - user=User( - id=user.ID, - name=user.name.upper(), - avatar=str( - URL(f'http://{netloc}/host/resource/tetrio/avatars/{user.ID}') % {'revision': avatar_revision} - ) - if (avatar_revision := (await player.avatar_revision)) is not None and avatar_revision != 0 - else Avatar( - type='identicon', - hash=md5(user.ID.encode()).hexdigest(), # noqa: S324 - ), + return await render_image( + Record( + type='best', + user=User( + id=user.ID, + name=user.name.upper(), + avatar=str( + URL(f'http://{netloc}/host/resource/tetrio/avatars/{user.ID}') % {'revision': avatar_revision} + ) + if (avatar_revision := (await player.avatar_revision)) is not None and avatar_revision != 0 + else Avatar( + type='identicon', + hash=md5(user.ID.encode()).hexdigest(), # noqa: S324 ), - replay_id=blitz.data.record.replayid, - rank=blitz.data.rank, - personal_rank=1, - statistic=Statistic( - keys=stats.inputs, - kpp=round(stats.inputs / stats.piecesplaced, 2), - kps=round(stats.inputs / duration, 2), - max=Max( - combo=max((0, stats.topcombo - 1)), - btb=max((0, stats.topbtb - 1)), - ), - pieces=stats.piecesplaced, - pps=metrics.pps, - lines=stats.lines, - lpm=metrics.lpm, - holds=stats.holds, - score=stats.score, - spp=round(stats.score / stats.piecesplaced, 2), - single=clears.singles, - double=clears.doubles, - triple=clears.triples, - quad=clears.quads, - tspins=Tspins( - total=clears.realtspins, - single=clears.tspinsingles, - double=clears.tspindoubles, - triple=clears.tspintriples, - mini=Mini( - total=clears.minitspins, - single=clears.minitspinsingles, - double=clears.minitspindoubles, - ), - ), - all_clear=clears.allclear, - finesse=Finesse( - faults=stats.finesse.faults, - accuracy=round(stats.finesse.perfectpieces / stats.piecesplaced * 100, 2), - ), - level=stats.level, - ), - play_at=blitz.data.record.ts, - lang=get_lang(), ), - ) - ) as page_hash: - return await screenshot(f'http://{netloc}/host/{page_hash}.html') + replay_id=blitz.data.record.replayid, + rank=blitz.data.rank, + personal_rank=1, + statistic=Statistic( + keys=stats.inputs, + kpp=round(stats.inputs / stats.piecesplaced, 2), + kps=round(stats.inputs / duration, 2), + max=Max( + combo=max((0, stats.topcombo - 1)), + btb=max((0, stats.topbtb - 1)), + ), + pieces=stats.piecesplaced, + pps=metrics.pps, + lines=stats.lines, + lpm=metrics.lpm, + holds=stats.holds, + score=stats.score, + spp=round(stats.score / stats.piecesplaced, 2), + single=clears.singles, + double=clears.doubles, + triple=clears.triples, + quad=clears.quads, + tspins=Tspins( + total=clears.realtspins, + single=clears.tspinsingles, + double=clears.tspindoubles, + triple=clears.tspintriples, + mini=Mini( + total=clears.minitspins, + single=clears.minitspinsingles, + double=clears.minitspindoubles, + ), + ), + all_clear=clears.allclear, + finesse=Finesse( + faults=stats.finesse.faults, + accuracy=round(stats.finesse.perfectpieces / stats.piecesplaced * 100, 2), + ), + level=stats.level, + ), + play_at=blitz.data.record.ts, + lang=get_lang(), + ), + ) diff --git a/nonebot_plugin_tetris_stats/games/tetrio/record/sprint.py b/nonebot_plugin_tetris_stats/games/tetrio/record/sprint.py index 5d0c024..a3a20d2 100644 --- a/nonebot_plugin_tetris_stats/games/tetrio/record/sprint.py +++ b/nonebot_plugin_tetris_stats/games/tetrio/record/sprint.py @@ -15,14 +15,13 @@ from yarl import URL from ....db import query_bind_info, trigger from ....i18n import Lang from ....utils.exception import RecordNotFoundError -from ....utils.host import HostPage, get_self_netloc +from ....utils.host import get_self_netloc from ....utils.lang import get_lang from ....utils.metrics import get_metrics -from ....utils.render import render +from ....utils.render import render_image from ....utils.render.schemas.base import Avatar from ....utils.render.schemas.v2.tetrio.record.base import Finesse, Max, Mini, Statistic, Tspins, User from ....utils.render.schemas.v2.tetrio.record.sprint import Record -from ....utils.screenshot import screenshot from ....utils.typedefs import Me from .. import alc from ..api.player import Player @@ -89,65 +88,61 @@ async def make_sprint_image(player: Player) -> bytes: sprint_value = f'{duration:.3f}s' if duration < 60 else f'{duration // 60:.0f}m {duration % 60:.3f}s' # noqa: PLR2004 metrics = get_metrics(pps=stats.piecesplaced / duration) netloc = get_self_netloc() - async with HostPage( - page=await render( - 'v2/tetrio/record/sprint', - Record( - type='best', - user=User( - id=user.ID, - name=user.name.upper(), - avatar=str( - URL(f'http://{netloc}/host/resource/tetrio/avatars/{user.ID}') % {'revision': avatar_revision} - ) - if (avatar_revision := (await player.avatar_revision)) is not None and avatar_revision != 0 - else Avatar( - type='identicon', - hash=md5(user.ID.encode()).hexdigest(), # noqa: S324 - ), + return await render_image( + Record( + type='best', + user=User( + id=user.ID, + name=user.name.upper(), + avatar=str( + URL(f'http://{netloc}/host/resource/tetrio/avatars/{user.ID}') % {'revision': avatar_revision} + ) + if (avatar_revision := (await player.avatar_revision)) is not None and avatar_revision != 0 + else Avatar( + type='identicon', + hash=md5(user.ID.encode()).hexdigest(), # noqa: S324 ), - time=sprint_value, - replay_id=sprint.data.record.replayid, - rank=sprint.data.rank, - personal_rank=1, - statistic=Statistic( - keys=stats.inputs, - kpp=round(stats.inputs / stats.piecesplaced, 2), - kps=round(stats.inputs / duration, 2), - max=Max( - combo=max((0, stats.topcombo - 1)), - btb=max((0, stats.topbtb - 1)), - ), - pieces=stats.piecesplaced, - pps=metrics.pps, - lines=stats.lines, - lpm=metrics.lpm, - holds=stats.holds, - score=stats.score, - single=clears.singles, - double=clears.doubles, - triple=clears.triples, - quad=clears.quads, - tspins=Tspins( - total=clears.realtspins, - single=clears.tspinsingles, - double=clears.tspindoubles, - triple=clears.tspintriples, - mini=Mini( - total=clears.minitspins, - single=clears.minitspinsingles, - double=clears.minitspindoubles, - ), - ), - all_clear=clears.allclear, - finesse=Finesse( - faults=stats.finesse.faults, - accuracy=round(stats.finesse.perfectpieces / stats.piecesplaced * 100, 2), - ), - ), - play_at=sprint.data.record.ts, - lang=get_lang(), ), - ) - ) as page_hash: - return await screenshot(f'http://{netloc}/host/{page_hash}.html') + time=sprint_value, + replay_id=sprint.data.record.replayid, + rank=sprint.data.rank, + personal_rank=1, + statistic=Statistic( + keys=stats.inputs, + kpp=round(stats.inputs / stats.piecesplaced, 2), + kps=round(stats.inputs / duration, 2), + max=Max( + combo=max((0, stats.topcombo - 1)), + btb=max((0, stats.topbtb - 1)), + ), + pieces=stats.piecesplaced, + pps=metrics.pps, + lines=stats.lines, + lpm=metrics.lpm, + holds=stats.holds, + score=stats.score, + single=clears.singles, + double=clears.doubles, + triple=clears.triples, + quad=clears.quads, + tspins=Tspins( + total=clears.realtspins, + single=clears.tspinsingles, + double=clears.tspindoubles, + triple=clears.tspintriples, + mini=Mini( + total=clears.minitspins, + single=clears.minitspinsingles, + double=clears.minitspindoubles, + ), + ), + all_clear=clears.allclear, + finesse=Finesse( + faults=stats.finesse.faults, + accuracy=round(stats.finesse.perfectpieces / stats.piecesplaced * 100, 2), + ), + ), + play_at=sprint.data.record.ts, + lang=get_lang(), + ), + ) diff --git a/nonebot_plugin_tetris_stats/games/tetrio/unbind.py b/nonebot_plugin_tetris_stats/games/tetrio/unbind.py index 5ad7f09..96493b4 100644 --- a/nonebot_plugin_tetris_stats/games/tetrio/unbind.py +++ b/nonebot_plugin_tetris_stats/games/tetrio/unbind.py @@ -13,12 +13,12 @@ from yarl import URL from ...config.config import global_config from ...db import query_bind_info, remove_bind, trigger -from ...utils.host import HostPage, get_self_netloc +from ...utils.host import get_self_netloc from ...utils.image import get_avatar from ...utils.lang import get_lang -from ...utils.render import Bind, render +from ...utils.render import render_image from ...utils.render.schemas.base import Avatar, People -from ...utils.screenshot import screenshot +from ...utils.render.schemas.bind import Bind from . import alc, command from .api import Player from .constant import GAME_TYPE @@ -51,9 +51,8 @@ async def _(nb_user: User, event_session: Uninfo, interface: QryItrface): player = Player(user_id=bind.game_account, trust=True) user = await player.user netloc = get_self_netloc() - async with HostPage( - await render( - 'v1/binding', + await UniMessage.image( + raw=await render_image( Bind( platform='TETR.IO', type='unlink', @@ -81,6 +80,5 @@ async def _(nb_user: User, event_session: Uninfo, interface: QryItrface): lang=get_lang(), ), ) - ) as page_hash: - await UniMessage.image(raw=await screenshot(f'http://{netloc}/host/{page_hash}.html')).send() + ).send() await remove_bind(session=session, user=nb_user, game_platform=GAME_TYPE) diff --git a/nonebot_plugin_tetris_stats/games/top/bind.py b/nonebot_plugin_tetris_stats/games/top/bind.py index 0ccdfb5..da5bdae 100644 --- a/nonebot_plugin_tetris_stats/games/top/bind.py +++ b/nonebot_plugin_tetris_stats/games/top/bind.py @@ -9,12 +9,11 @@ from nonebot_plugin_user import User from ...config.config import global_config from ...db import BindStatus, create_or_update_bind, trigger -from ...utils.host import HostPage, get_self_netloc from ...utils.image import get_avatar from ...utils.lang import get_lang -from ...utils.render import Bind, render +from ...utils.render import render_image from ...utils.render.schemas.base import People -from ...utils.screenshot import screenshot +from ...utils.render.schemas.bind import Bind from . import alc from .api import Player from .constant import GAME_TYPE @@ -37,9 +36,8 @@ async def _(nb_user: User, account: Player, event_session: Uninfo, interface: Qr game_account=user.unique_identifier, ) if bind_status in (BindStatus.SUCCESS, BindStatus.UPDATE): - async with HostPage( - await render( - 'v1/binding', + await UniMessage.image( + raw=await render_image( Bind( platform=GAME_TYPE, type='unknown', @@ -66,7 +64,4 @@ async def _(nb_user: User, account: Player, event_session: Uninfo, interface: Qr lang=get_lang(), ), ) - ) as page_hash: - await UniMessage.image( - raw=await screenshot(f'http://{get_self_netloc()}/host/{page_hash}.html') - ).finish() + ).finish() diff --git a/nonebot_plugin_tetris_stats/games/top/query.py b/nonebot_plugin_tetris_stats/games/top/query.py index 19272c1..06de649 100644 --- a/nonebot_plugin_tetris_stats/games/top/query.py +++ b/nonebot_plugin_tetris_stats/games/top/query.py @@ -10,15 +10,13 @@ from nonebot_plugin_user import get_user from ...db import query_bind_info, trigger from ...i18n import Lang from ...utils.exception import FallbackError -from ...utils.host import HostPage, get_self_netloc from ...utils.lang import get_lang from ...utils.metrics import TetrisMetricsBasicWithLPM, get_metrics -from ...utils.render import render +from ...utils.render import render_image from ...utils.render.avatar import get_avatar from ...utils.render.schemas.base import People, Trending from ...utils.render.schemas.v1.top.info import Data as InfoData from ...utils.render.schemas.v1.top.info import Info -from ...utils.screenshot import screenshot from ...utils.typedefs import Me from . import alc from .api import Player @@ -75,32 +73,28 @@ async def make_query_image(profile: UserProfile) -> bytes: raise FallbackError today = get_metrics(lpm=profile.today.lpm, apm=profile.today.apm) history = get_avg_metrics(profile.total) - async with HostPage( - await render( - 'v1/top/info', - Info( - user=People(avatar=get_avatar(profile.user_name), name=profile.user_name), - today=InfoData( - pps=today.pps, - lpm=today.lpm, - lpm_trending=Trending.KEEP, - apm=today.apm, - apl=today.apl, - apm_trending=Trending.KEEP, - ), - historical=InfoData( - pps=history.pps, - lpm=history.lpm, - lpm_trending=Trending.KEEP, - apm=history.apm, - apl=history.apl, - apm_trending=Trending.KEEP, - ), - lang=get_lang(), + return await render_image( + Info( + user=People(avatar=get_avatar(profile.user_name), name=profile.user_name), + today=InfoData( + pps=today.pps, + lpm=today.lpm, + lpm_trending=Trending.KEEP, + apm=today.apm, + apl=today.apl, + apm_trending=Trending.KEEP, ), - ) - ) as page_hash: - return await screenshot(f'http://{get_self_netloc()}/host/{page_hash}.html') + historical=InfoData( + pps=history.pps, + lpm=history.lpm, + lpm_trending=Trending.KEEP, + apm=history.apm, + apl=history.apl, + apm_trending=Trending.KEEP, + ), + lang=get_lang(), + ), + ) def make_query_text(profile: UserProfile) -> UniMessage: diff --git a/nonebot_plugin_tetris_stats/games/top/unbind.py b/nonebot_plugin_tetris_stats/games/top/unbind.py index f34029e..377a6eb 100644 --- a/nonebot_plugin_tetris_stats/games/top/unbind.py +++ b/nonebot_plugin_tetris_stats/games/top/unbind.py @@ -10,12 +10,11 @@ from nonebot_plugin_waiter import suggest # type: ignore[import-untyped] from ...config.config import global_config from ...db import query_bind_info, remove_bind, trigger -from ...utils.host import HostPage, get_self_netloc from ...utils.image import get_avatar from ...utils.lang import get_lang -from ...utils.render import Bind, render +from ...utils.render import render_image from ...utils.render.schemas.base import People -from ...utils.screenshot import screenshot +from ...utils.render.schemas.bind import Bind from . import alc from .api import Player from .constant import GAME_TYPE @@ -43,10 +42,8 @@ async def _( return player = Player(user_name=bind.game_account, trust=True) user = await player.user - netloc = get_self_netloc() - async with HostPage( - await render( - 'v1/binding', + await UniMessage.image( + raw=await render_image( Bind( platform='TOP', type='unlink', @@ -73,6 +70,5 @@ async def _( lang=get_lang(), ), ) - ) as page_hash: - await UniMessage.image(raw=await screenshot(f'http://{netloc}/host/{page_hash}.html')).send() + ).send() await remove_bind(session=session, user=nb_user, game_platform=GAME_TYPE) diff --git a/nonebot_plugin_tetris_stats/games/tos/bind.py b/nonebot_plugin_tetris_stats/games/tos/bind.py index a72f7c2..23dbeab 100644 --- a/nonebot_plugin_tetris_stats/games/tos/bind.py +++ b/nonebot_plugin_tetris_stats/games/tos/bind.py @@ -9,12 +9,11 @@ from nonebot_plugin_user import User from ...config.config import global_config from ...db import BindStatus, create_or_update_bind, trigger -from ...utils.host import HostPage, get_self_netloc from ...utils.image import get_avatar from ...utils.lang import get_lang -from ...utils.render import Bind, render +from ...utils.render import render_image from ...utils.render.schemas.base import People -from ...utils.screenshot import screenshot +from ...utils.render.schemas.bind import Bind from . import alc from .api import Player from .constant import GAME_TYPE @@ -43,9 +42,8 @@ async def _( ) user_info = await account.get_info() if bind_status in (BindStatus.SUCCESS, BindStatus.UPDATE): - async with HostPage( - await render( - 'v1/binding', + await UniMessage.image( + raw=await render_image( Bind( platform=GAME_TYPE, type='unknown', @@ -72,7 +70,4 @@ async def _( lang=get_lang(), ), ) - ) as page_hash: - await UniMessage.image( - raw=await screenshot(f'http://{get_self_netloc()}/host/{page_hash}.html') - ).finish() + ).finish() diff --git a/nonebot_plugin_tetris_stats/games/tos/query.py b/nonebot_plugin_tetris_stats/games/tos/query.py index 0a924b5..05d8ff8 100644 --- a/nonebot_plugin_tetris_stats/games/tos/query.py +++ b/nonebot_plugin_tetris_stats/games/tos/query.py @@ -18,16 +18,14 @@ from ...db import query_bind_info, trigger from ...i18n import Lang from ...utils.chart import get_split, get_value_bounds, handle_history_data from ...utils.exception import RequestError -from ...utils.host import HostPage, get_self_netloc from ...utils.image import get_avatar from ...utils.lang import get_lang from ...utils.metrics import TetrisMetricsProWithLPMADPM, get_metrics -from ...utils.render import render +from ...utils.render import render_image from ...utils.render.avatar import get_avatar as get_random_avatar from ...utils.render.schemas.base import HistoryData, People, Trending from ...utils.render.schemas.v1.base import History from ...utils.render.schemas.v1.tos.info import Info, Multiplayer, Singleplayer -from ...utils.screenshot import screenshot from ...utils.time_it import time_it from ...utils.typedefs import Me, Number from . import alc @@ -264,52 +262,48 @@ async def make_query_image(user_info: UserInfoSuccess, game_data: GameData, even ) data = handle_history_data(await get_historical_data(user_info.data.teaid)) values = get_value_bounds([i.score for i in data]) - async with HostPage( - await render( - 'v1/tos/info', - Info( - user=People( - avatar=await get_avatar(event_user_info, 'Data URI', None) - if event_user_info is not None - else get_random_avatar(user_info.data.teaid), - name=user_info.data.name, - ), - multiplayer=Multiplayer( - history=History( - data=data, - max_value=values.value_max, - min_value=values.value_min, - split_interval=(split := get_split(value_bound=values, min_value=0)).split_value, - offset=split.offset, - ), - rating=round(float(user_info.data.rating_now), 2), - rd=round(float(user_info.data.rd_now), 2), - lpm=metrics.lpm, - pps=metrics.pps, - lpm_trending=Trending.KEEP, - apm=metrics.apm, - apl=metrics.apl, - apm_trending=Trending.KEEP, - adpm=metrics.adpm, - vs=metrics.vs, - adpl=metrics.adpl, - adpm_trending=Trending.KEEP, - app=(app := (metrics.apm / (60 * metrics.pps))), - or_=game_data.or_, - dspp=game_data.dspp, - ci=150 * game_data.dspp - 125 * app + 50 * (metrics.vs / metrics.apm) - 25, - ge=game_data.ge, - ), - singleplayer=Singleplayer( - sprint=sprint_value, - challenge=f'{int(user_info.data.pb_challenge):,}' if user_info.data.pb_challenge != '0' else 'N/A', - marathon=f'{int(user_info.data.pb_marathon):,}' if user_info.data.pb_marathon != '0' else 'N/A', - ), - lang=get_lang(), + return await render_image( + Info( + user=People( + avatar=await get_avatar(event_user_info, 'Data URI', None) + if event_user_info is not None + else get_random_avatar(user_info.data.teaid), + name=user_info.data.name, ), - ) - ) as page_hash: - return await screenshot(f'http://{get_self_netloc()}/host/{page_hash}.html') + multiplayer=Multiplayer( + history=History( + data=data, + max_value=values.value_max, + min_value=values.value_min, + split_interval=(split := get_split(value_bound=values, min_value=0)).split_value, + offset=split.offset, + ), + rating=round(float(user_info.data.rating_now), 2), + rd=round(float(user_info.data.rd_now), 2), + lpm=metrics.lpm, + pps=metrics.pps, + lpm_trending=Trending.KEEP, + apm=metrics.apm, + apl=metrics.apl, + apm_trending=Trending.KEEP, + adpm=metrics.adpm, + vs=metrics.vs, + adpl=metrics.adpl, + adpm_trending=Trending.KEEP, + app=(app := (metrics.apm / (60 * metrics.pps))), + or_=game_data.or_, + dspp=game_data.dspp, + ci=150 * game_data.dspp - 125 * app + 50 * (metrics.vs / metrics.apm) - 25, + ge=game_data.ge, + ), + singleplayer=Singleplayer( + sprint=sprint_value, + challenge=f'{int(user_info.data.pb_challenge):,}' if user_info.data.pb_challenge != '0' else 'N/A', + marathon=f'{int(user_info.data.pb_marathon):,}' if user_info.data.pb_marathon != '0' else 'N/A', + ), + lang=get_lang(), + ), + ) def make_query_text(user_info: UserInfoSuccess, game_data: GameData | None) -> UniMessage: diff --git a/nonebot_plugin_tetris_stats/games/tos/unbind.py b/nonebot_plugin_tetris_stats/games/tos/unbind.py index a6dfddf..69e3209 100644 --- a/nonebot_plugin_tetris_stats/games/tos/unbind.py +++ b/nonebot_plugin_tetris_stats/games/tos/unbind.py @@ -10,12 +10,11 @@ from nonebot_plugin_waiter import suggest # type: ignore[import-untyped] from ...config.config import global_config from ...db import query_bind_info, remove_bind, trigger -from ...utils.host import HostPage, get_self_netloc from ...utils.image import get_avatar from ...utils.lang import get_lang -from ...utils.render import Bind, render +from ...utils.render import render_image from ...utils.render.schemas.base import People -from ...utils.screenshot import screenshot +from ...utils.render.schemas.bind import Bind from . import alc from .api import Player from .constant import GAME_TYPE @@ -43,10 +42,8 @@ async def _( return player = Player(user_name=bind.game_account, trust=True) user = await player.user - netloc = get_self_netloc() - async with HostPage( - await render( - 'v1/binding', + await UniMessage.image( + raw=await render_image( Bind( platform='TOS', type='unlink', @@ -69,6 +66,5 @@ async def _( lang=get_lang(), ), ) - ) as page_hash: - await UniMessage.image(raw=await screenshot(f'http://{netloc}/host/{page_hash}.html')).send() + ).send() await remove_bind(session=session, user=nb_user, game_platform=GAME_TYPE) diff --git a/nonebot_plugin_tetris_stats/utils/render/__init__.py b/nonebot_plugin_tetris_stats/utils/render/__init__.py index c0c9250..67350b8 100644 --- a/nonebot_plugin_tetris_stats/utils/render/__init__.py +++ b/nonebot_plugin_tetris_stats/utils/render/__init__.py @@ -1,22 +1,10 @@ -from typing import Literal, overload - from jinja2 import Environment, FileSystemLoader from nonebot.compat import PYDANTIC_V2 +from ..host import HostPage, get_self_netloc +from ..screenshot import screenshot from ..templates import TEMPLATES_DIR from .schemas.base import Base -from .schemas.bind import Bind -from .schemas.v1.tetrio.rank import Data as TETRIORankDataV1 -from .schemas.v1.tetrio.user.info import Info as TETRIOUserInfoV1 -from .schemas.v1.top.info import Info as TOPInfoV1 -from .schemas.v1.tos.info import Info as TOSInfoV1 -from .schemas.v2.tetrio.rank import Data as TETRIORankDataV2 -from .schemas.v2.tetrio.rank.detail import Data as TETRIORankDetailDataV2 -from .schemas.v2.tetrio.record.blitz import Record as TETRIORecordBlitzV2 -from .schemas.v2.tetrio.record.sprint import Record as TETRIORecordSprintV2 -from .schemas.v2.tetrio.tetra_league import Data as TETRIOTetraLeagueDataV2 -from .schemas.v2.tetrio.user.info import Info as TETRIOUserInfoV2 -from .schemas.v2.tetrio.user.list import List as TETRIOUserListV2 env = Environment( loader=FileSystemLoader(TEMPLATES_DIR), @@ -27,39 +15,19 @@ env = Environment( ) -@overload -async def render(render_type: Literal['v1/binding'], data: Bind) -> str: ... -@overload -async def render(render_type: Literal['v1/tetrio/info'], data: TETRIOUserInfoV1) -> str: ... -@overload -async def render(render_type: Literal['v1/tetrio/rank'], data: TETRIORankDataV1) -> str: ... -@overload -async def render(render_type: Literal['v1/top/info'], data: TOPInfoV1) -> str: ... -@overload -async def render(render_type: Literal['v1/tos/info'], data: TOSInfoV1) -> str: ... -@overload -async def render(render_type: Literal['v2/tetrio/rank'], data: TETRIORankDataV2) -> str: ... -@overload -async def render(render_type: Literal['v2/tetrio/rank/detail'], data: TETRIORankDetailDataV2) -> str: ... -@overload -async def render(render_type: Literal['v2/tetrio/record/blitz'], data: TETRIORecordBlitzV2) -> str: ... -@overload -async def render(render_type: Literal['v2/tetrio/record/sprint'], data: TETRIORecordSprintV2) -> str: ... -@overload -async def render(render_type: Literal['v2/tetrio/tetra-league'], data: TETRIOTetraLeagueDataV2) -> str: ... -@overload -async def render(render_type: Literal['v2/tetrio/user/info'], data: TETRIOUserInfoV2) -> str: ... -@overload -async def render(render_type: Literal['v2/tetrio/user/list'], data: TETRIOUserListV2) -> str: ... async def render( - render_type: str, data: Base, ) -> str: if PYDANTIC_V2: - return await env.get_template('index.html').render_async( - path=render_type, data=data.model_dump_json(by_alias=True) - ) - return await env.get_template('index.html').render_async(path=render_type, data=data.json(by_alias=True)) + return await env.get_template('index.html').render_async(data=data.model_dump_json(by_alias=True)) + return await env.get_template('index.html').render_async(data=data.json(by_alias=True)) + + +async def render_image( + data: Base, +) -> bytes: + async with HostPage(page=await render(data)) as page_hash: + return await screenshot(f'http://{get_self_netloc()}/host/{page_hash}.html#/{data.path}') __all__ = ['render'] diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/base.py b/nonebot_plugin_tetris_stats/utils/render/schemas/base.py index 22b13d2..e240e0b 100644 --- a/nonebot_plugin_tetris_stats/utils/render/schemas/base.py +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/base.py @@ -1,3 +1,4 @@ +from abc import abstractmethod from datetime import datetime from typing import Literal @@ -8,6 +9,11 @@ from ...typedefs import Lang, Number class Base(BaseModel): + @property + @abstractmethod + def path(self) -> str: + raise NotImplementedError + lang: Lang diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/bind.py b/nonebot_plugin_tetris_stats/utils/render/schemas/bind.py index e090640..cc3595f 100644 --- a/nonebot_plugin_tetris_stats/utils/render/schemas/bind.py +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/bind.py @@ -1,9 +1,16 @@ from typing import Literal +from typing_extensions import override + from .base import Base, People class Bind(Base): + @property + @override + def path(self) -> str: + return 'v1/binding' + platform: Literal['TETR.IO', 'TOP', 'TOS'] type: Literal['success', 'unknown', 'unlink', 'unverified', 'error'] user: People diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/v1/tetrio/user/info.py b/nonebot_plugin_tetris_stats/utils/render/schemas/v1/tetrio/info.py similarity index 69% rename from nonebot_plugin_tetris_stats/utils/render/schemas/v1/tetrio/user/info.py rename to nonebot_plugin_tetris_stats/utils/render/schemas/v1/tetrio/info.py index 0633763..be2cd34 100644 --- a/nonebot_plugin_tetris_stats/utils/render/schemas/v1/tetrio/user/info.py +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/v1/tetrio/info.py @@ -1,9 +1,10 @@ from pydantic import BaseModel +from typing_extensions import override -from .......games.tetrio.api.typedefs import Rank -from ......typedefs import Number -from ....base import Base, People, Trending -from ...base import History +from ......games.tetrio.api.typedefs import Rank +from .....typedefs import Number +from ...base import Base, People, Trending +from ..base import History class User(People): @@ -45,6 +46,11 @@ class Singleplayer(BaseModel): class Info(Base): + @property + @override + def path(self) -> str: + return 'v1/tetrio/info' + user: User multiplayer: Multiplayer singleplayer: Singleplayer diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/v1/tetrio/rank.py b/nonebot_plugin_tetris_stats/utils/render/schemas/v1/tetrio/rank.py index 7d9238c..d441592 100644 --- a/nonebot_plugin_tetris_stats/utils/render/schemas/v1/tetrio/rank.py +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/v1/tetrio/rank.py @@ -1,6 +1,7 @@ from datetime import datetime from pydantic import BaseModel +from typing_extensions import override from ......games.tetrio.api.typedefs import ValidRank from ...base import Base @@ -13,5 +14,10 @@ class ItemData(BaseModel): class Data(Base): + @property + @override + def path(self) -> str: + return 'v1/tetrio/rank' + items: dict[ValidRank, ItemData] updated_at: datetime diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/v1/top/info.py b/nonebot_plugin_tetris_stats/utils/render/schemas/v1/top/info.py index a4083d3..81b1f34 100644 --- a/nonebot_plugin_tetris_stats/utils/render/schemas/v1/top/info.py +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/v1/top/info.py @@ -1,4 +1,5 @@ from pydantic import BaseModel +from typing_extensions import override from .....typedefs import Number from ...base import Base, People, Trending @@ -14,6 +15,11 @@ class Data(BaseModel): class Info(Base): + @property + @override + def path(self) -> str: + return 'v1/top/info' + user: People today: Data historical: Data diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/v1/tos/info.py b/nonebot_plugin_tetris_stats/utils/render/schemas/v1/tos/info.py index 43b6c84..5c9b904 100644 --- a/nonebot_plugin_tetris_stats/utils/render/schemas/v1/tos/info.py +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/v1/tos/info.py @@ -1,4 +1,5 @@ from pydantic import BaseModel, Field +from typing_extensions import override from .....typedefs import Number from ...base import Base, People, Trending @@ -37,6 +38,11 @@ class Singleplayer(BaseModel): class Info(Base): + @property + @override + def path(self) -> str: + return 'v1/tos/info' + user: People multiplayer: Multiplayer singleplayer: Singleplayer diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/rank/__init__.py b/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/rank/__init__.py index 072c26d..851b929 100644 --- a/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/rank/__init__.py +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/rank/__init__.py @@ -1,6 +1,7 @@ from datetime import datetime from pydantic import BaseModel +from typing_extensions import override from .......games.tetrio.api.typedefs import ValidRank from ......typedefs import Number @@ -23,5 +24,10 @@ class ItemData(BaseModel): class Data(Base): + @property + @override + def path(self) -> str: + return 'v2/tetrio/rank' + items: dict[ValidRank, ItemData] updated_at: datetime diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/rank/detail.py b/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/rank/detail.py index f93dd17..c3fee46 100644 --- a/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/rank/detail.py +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/rank/detail.py @@ -1,6 +1,7 @@ from datetime import datetime from pydantic import BaseModel +from typing_extensions import override from .......games.tetrio.api.typedefs import ValidRank from ......typedefs import Number @@ -21,6 +22,11 @@ class SpecialData(BaseModel): class Data(Base): + @property + @override + def path(self) -> str: + return 'v2/tetrio/rank/detail' + name: ValidRank trending: Number require_tr: Number diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/record/blitz.py b/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/record/blitz.py index b3a2b87..5fd8fc2 100644 --- a/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/record/blitz.py +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/record/blitz.py @@ -1,3 +1,5 @@ +from typing_extensions import override + from .base import Record as BaseRecord from .base import Statistic as BaseStatistic @@ -9,4 +11,9 @@ class Statistic(BaseStatistic): class Record(BaseRecord): + @property + @override + def path(self) -> str: + return 'v2/tetrio/record/blitz' + statistic: Statistic diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/record/sprint.py b/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/record/sprint.py index 09b1063..356fc53 100644 --- a/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/record/sprint.py +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/record/sprint.py @@ -1,7 +1,14 @@ +from typing_extensions import override + from .base import Record as BaseRecord from .base import Statistic class Record(BaseRecord): + @property + @override + def path(self) -> str: + return 'v2/tetrio/record/sprint' + statistic: Statistic time: str diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/tetra_league.py b/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/tetra_league.py index 176b4c7..4cc3265 100644 --- a/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/tetra_league.py +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/tetra_league.py @@ -1,6 +1,7 @@ from datetime import datetime from pydantic import BaseModel +from typing_extensions import override from .....typedefs import Number from ...base import Base @@ -34,6 +35,11 @@ class Game(BaseModel): class Data(Base): + @property + @override + def path(self) -> str: + return 'v2/tetrio/tetra-league' + replay_id: str games: list[Game] play_at: datetime diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/user/info.py b/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/user/info.py index 65f03ff..1c78896 100644 --- a/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/user/info.py +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/user/info.py @@ -2,6 +2,7 @@ from datetime import datetime from typing import Literal from pydantic import BaseModel +from typing_extensions import override from .......games.tetrio.api.schemas.summaries.achievements import ArType, RankType from .......games.tetrio.api.schemas.summaries.achievements import Rank as AchievementRank @@ -132,6 +133,11 @@ class Zenith(BaseModel): class Info(Base): + @property + @override + def path(self) -> str: + return 'v2/tetrio/user/info' + user: User tetra_league: TetraLeague | None zenith: Zenith | None diff --git a/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/user/list.py b/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/user/list.py index 1dd1104..264053a 100644 --- a/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/user/list.py +++ b/nonebot_plugin_tetris_stats/utils/render/schemas/v2/tetrio/user/list.py @@ -1,4 +1,5 @@ from pydantic import BaseModel +from typing_extensions import override from .......games.tetrio.api.typedefs import Rank from ......typedefs import Number @@ -34,5 +35,10 @@ class Data(BaseModel): class List(Base): + @property + @override + def path(self) -> str: + return 'v2/tetrio/user/list' + show_index: bool data: list[Data]