mirror of
https://github.com/A-Minos/nonebot-plugin-tetris-stats.git
synced 2026-03-05 05:36:54 +08:00
148 lines
5.6 KiB
Python
148 lines
5.6 KiB
Python
from datetime import timedelta, timezone
|
|
from zoneinfo import ZoneInfo
|
|
|
|
from arclet.alconna import Arg
|
|
from nonebot import get_driver
|
|
from nonebot_plugin_alconna import Option, UniMessage
|
|
from nonebot_plugin_orm import get_session
|
|
from nonebot_plugin_uninfo import Uninfo
|
|
from nonebot_plugin_uninfo.orm import get_session_persist_id
|
|
from sqlalchemy import select
|
|
from sqlalchemy.orm import selectinload
|
|
|
|
from ....db import trigger
|
|
from ....utils.lang import get_lang
|
|
from ....utils.metrics import get_metrics
|
|
from ....utils.render import render_image
|
|
from ....utils.render.schemas.v2.tetrio.rank.detail import Data, SpecialData
|
|
from .. import alc
|
|
from ..api.typedefs import ValidRank
|
|
from ..constant import GAME_TYPE
|
|
from ..models import TETRIOLeagueStats
|
|
from . import command
|
|
|
|
UTC = timezone.utc
|
|
|
|
driver = get_driver()
|
|
|
|
command.add(Option('--detail', Arg('rank', ValidRank), alias=['-D']))
|
|
|
|
|
|
@alc.assign('TETRIO.rank')
|
|
async def _(rank: ValidRank, event_session: Uninfo):
|
|
async with trigger(
|
|
session_persist_id=await get_session_persist_id(event_session),
|
|
game_platform=GAME_TYPE,
|
|
command_type='rank',
|
|
command_args=[f'--detail {rank}'],
|
|
):
|
|
async with get_session() as session:
|
|
# 获取最新记录
|
|
latest_data = (
|
|
await session.scalars(
|
|
select(TETRIOLeagueStats)
|
|
.order_by(TETRIOLeagueStats.id.desc())
|
|
.limit(1)
|
|
.options(selectinload(TETRIOLeagueStats.fields))
|
|
)
|
|
).one()
|
|
|
|
# 计算目标时间点 (24小时前)
|
|
target_time = latest_data.update_time - timedelta(hours=24)
|
|
|
|
# 查询目标时间点之前的最近记录
|
|
before = (
|
|
await session.scalar(
|
|
select(TETRIOLeagueStats)
|
|
.where(TETRIOLeagueStats.update_time <= target_time)
|
|
.order_by(TETRIOLeagueStats.update_time.desc())
|
|
.limit(1)
|
|
.options(selectinload(TETRIOLeagueStats.fields))
|
|
)
|
|
or latest_data # 回退到最新记录
|
|
)
|
|
|
|
# 查询目标时间点之后的最近记录
|
|
after = (
|
|
await session.scalar(
|
|
select(TETRIOLeagueStats)
|
|
.where(TETRIOLeagueStats.update_time >= target_time)
|
|
.order_by(TETRIOLeagueStats.update_time.asc())
|
|
.limit(1)
|
|
.options(selectinload(TETRIOLeagueStats.fields))
|
|
)
|
|
or latest_data # 回退到最新记录
|
|
)
|
|
|
|
# 确定最接近的记录
|
|
compare_data = (
|
|
before
|
|
if abs((target_time - before.update_time).total_seconds())
|
|
< abs((target_time - after.update_time).total_seconds())
|
|
else after
|
|
)
|
|
await UniMessage.image(
|
|
raw=await make_image(
|
|
rank,
|
|
latest_data,
|
|
compare_data,
|
|
)
|
|
).finish()
|
|
|
|
|
|
async def make_image(rank: ValidRank, latest: TETRIOLeagueStats, compare: TETRIOLeagueStats) -> bytes:
|
|
latest_data = next(filter(lambda x: x.rank == rank, latest.fields))
|
|
compare_data = next(filter(lambda x: x.rank == rank, compare.fields))
|
|
avg = get_metrics(pps=latest_data.avg_pps, apm=latest_data.avg_apm, vs=latest_data.avg_vs)
|
|
low_pps = get_metrics(
|
|
pps=latest_data.low_pps.league.pps, apm=latest_data.low_pps.league.apm, vs=latest_data.low_pps.league.vs
|
|
)
|
|
low_apm = get_metrics(
|
|
pps=latest_data.low_apm.league.pps, apm=latest_data.low_apm.league.apm, vs=latest_data.low_apm.league.vs
|
|
)
|
|
low_vs = get_metrics(
|
|
pps=latest_data.low_vs.league.pps, apm=latest_data.low_vs.league.apm, vs=latest_data.low_vs.league.vs
|
|
)
|
|
max_pps = get_metrics(
|
|
pps=latest_data.high_pps.league.pps, apm=latest_data.high_pps.league.apm, vs=latest_data.high_pps.league.vs
|
|
)
|
|
max_apm = get_metrics(
|
|
pps=latest_data.high_apm.league.pps, apm=latest_data.high_apm.league.apm, vs=latest_data.high_apm.league.vs
|
|
)
|
|
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
|
|
)
|
|
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(),
|
|
),
|
|
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(),
|
|
),
|
|
)
|