mirror of
https://github.com/A-Minos/nonebot-plugin-tetris-stats.git
synced 2026-03-05 05:36:54 +08:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fbe018e56a | |||
| ab046fe786 | |||
| ce95d8f977 | |||
| fa05b80e61 | |||
| 0ab0d11a98 | |||
| 7f469540b2 | |||
| 21bee29146 | |||
|
|
c2dd9c5d86 | ||
|
|
5927cb2bb5 | ||
|
|
4a4a215b61 | ||
| bfe931d3bf | |||
| b7b152d84d | |||
| b6f6eb1170 | |||
| 934800aae0 | |||
|
|
d19c37e99a | ||
|
|
43167fe9bd | ||
|
|
db8de88667 |
@@ -5,8 +5,9 @@ require('nonebot_plugin_alconna')
|
||||
require('nonebot_plugin_apscheduler')
|
||||
require('nonebot_plugin_localstore')
|
||||
require('nonebot_plugin_orm')
|
||||
require('nonebot_plugin_session')
|
||||
require('nonebot_plugin_session_orm')
|
||||
require('nonebot_plugin_session')
|
||||
require('nonebot_plugin_user')
|
||||
|
||||
from nonebot_plugin_alconna import namespace # noqa: E402
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
"""Migrate to nonobot-plugin-user
|
||||
|
||||
迁移 ID: b15844837693
|
||||
父迁移: 3c25a5a8c050
|
||||
创建时间: 2024-06-08 02:27:35.227596
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Sequence
|
||||
|
||||
revision: str = 'b15844837693'
|
||||
down_revision: str | Sequence[str] | None = '3c25a5a8c050'
|
||||
branch_labels: str | Sequence[str] | None = None
|
||||
depends_on: str | Sequence[str] | None = None
|
||||
|
||||
|
||||
def upgrade(name: str = '') -> None:
|
||||
if name:
|
||||
return
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('nonebot_plugin_tetris_stats_bind', schema=None) as batch_op:
|
||||
batch_op.drop_index('ix_nonebot_plugin_tetris_stats_bind_chat_account')
|
||||
batch_op.drop_index('ix_nonebot_plugin_tetris_stats_bind_chat_platform')
|
||||
|
||||
op.drop_table('nonebot_plugin_tetris_stats_bind')
|
||||
|
||||
op.create_table(
|
||||
'nonebot_plugin_tetris_stats_bind',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('user_id', sa.Integer(), nullable=False),
|
||||
sa.Column('game_platform', sa.String(length=32), nullable=False),
|
||||
sa.Column('game_account', sa.String(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id', name=op.f('pk_nonebot_plugin_tetris_stats_bind')),
|
||||
info={'bind_key': 'nonebot_plugin_tetris_stats'},
|
||||
)
|
||||
with op.batch_alter_table('nonebot_plugin_tetris_stats_bind', schema=None) as batch_op:
|
||||
batch_op.create_index(batch_op.f('ix_nonebot_plugin_tetris_stats_bind_user_id'), ['user_id'], unique=False)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade(name: str = '') -> None:
|
||||
if name:
|
||||
return
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('nonebot_plugin_tetris_stats_bind', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_nonebot_plugin_tetris_stats_bind_user_id'))
|
||||
|
||||
op.drop_table('nonebot_plugin_tetris_stats_bind')
|
||||
|
||||
op.create_table(
|
||||
'nonebot_plugin_tetris_stats_bind',
|
||||
sa.Column('id', sa.INTEGER(), nullable=False),
|
||||
sa.Column('chat_platform', sa.VARCHAR(length=32), nullable=False),
|
||||
sa.Column('chat_account', sa.VARCHAR(), nullable=False),
|
||||
sa.Column('game_platform', sa.VARCHAR(length=32), nullable=False),
|
||||
sa.Column('game_account', sa.VARCHAR(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id', name='pk_nonebot_plugin_tetris_stats_bind'),
|
||||
)
|
||||
with op.batch_alter_table('nonebot_plugin_tetris_stats_bind', schema=None) as batch_op:
|
||||
batch_op.create_index('ix_nonebot_plugin_tetris_stats_bind_chat_platform', ['chat_platform'], unique=False)
|
||||
batch_op.create_index('ix_nonebot_plugin_tetris_stats_bind_chat_account', ['chat_account'], unique=False)
|
||||
|
||||
# ### end Alembic commands ###
|
||||
@@ -8,6 +8,7 @@ from typing import TYPE_CHECKING, Literal, TypeVar, overload
|
||||
from nonebot.exception import FinishedException
|
||||
from nonebot.log import logger
|
||||
from nonebot_plugin_orm import AsyncSession, get_session
|
||||
from nonebot_plugin_user import User # type: ignore[import-untyped]
|
||||
from sqlalchemy import select
|
||||
|
||||
from ..utils.typing import CommandType, GameType
|
||||
@@ -28,37 +29,28 @@ class BindStatus(Enum):
|
||||
|
||||
async def query_bind_info(
|
||||
session: AsyncSession,
|
||||
chat_platform: str,
|
||||
chat_account: str,
|
||||
user: User,
|
||||
game_platform: GameType,
|
||||
) -> Bind | None:
|
||||
return (
|
||||
await session.scalars(
|
||||
select(Bind)
|
||||
.where(Bind.chat_platform == chat_platform)
|
||||
.where(Bind.chat_account == chat_account)
|
||||
.where(Bind.game_platform == game_platform)
|
||||
)
|
||||
await session.scalars(select(Bind).where(Bind.user_id == user.id).where(Bind.game_platform == game_platform))
|
||||
).one_or_none()
|
||||
|
||||
|
||||
async def create_or_update_bind(
|
||||
session: AsyncSession,
|
||||
chat_platform: str,
|
||||
chat_account: str,
|
||||
user: User,
|
||||
game_platform: GameType,
|
||||
game_account: str,
|
||||
) -> BindStatus:
|
||||
bind = await query_bind_info(
|
||||
session=session,
|
||||
chat_platform=chat_platform,
|
||||
chat_account=chat_account,
|
||||
user=user,
|
||||
game_platform=game_platform,
|
||||
)
|
||||
if bind is None:
|
||||
bind = Bind(
|
||||
chat_platform=chat_platform,
|
||||
chat_account=chat_account,
|
||||
user_id=user.id,
|
||||
game_platform=game_platform,
|
||||
game_account=game_account,
|
||||
)
|
||||
|
||||
@@ -66,8 +66,7 @@ class PydanticType(TypeDecorator):
|
||||
|
||||
class Bind(MappedAsDataclass, Model):
|
||||
id: Mapped[int] = mapped_column(init=False, primary_key=True)
|
||||
chat_platform: Mapped[str] = mapped_column(String(32), index=True)
|
||||
chat_account: Mapped[str] = mapped_column(index=True)
|
||||
user_id: Mapped[int] = mapped_column(index=True)
|
||||
game_platform: Mapped[GameType] = mapped_column(String(32))
|
||||
game_account: Mapped[str]
|
||||
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
from hashlib import md5
|
||||
from urllib.parse import urlunparse
|
||||
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot_plugin_alconna.uniseg import UniMessage
|
||||
from nonebot_plugin_orm import get_session
|
||||
from nonebot_plugin_session import EventSession # type: ignore[import-untyped]
|
||||
from nonebot_plugin_session_orm import get_session_persist_id # type: ignore[import-untyped]
|
||||
from nonebot_plugin_user import User # type: ignore[import-untyped]
|
||||
from nonebot_plugin_userinfo import BotUserInfo, UserInfo # type: ignore[import-untyped]
|
||||
|
||||
from ...db import BindStatus, create_or_update_bind, trigger
|
||||
from ...utils.avatar import get_avatar
|
||||
from ...utils.host import HostPage, get_self_netloc
|
||||
from ...utils.platform import get_platform
|
||||
from ...utils.render import Bind, render
|
||||
from ...utils.render.schemas.base import Avatar, People
|
||||
from ...utils.screenshot import screenshot
|
||||
@@ -21,7 +20,7 @@ from .constant import GAME_TYPE
|
||||
|
||||
|
||||
@alc.assign('bind')
|
||||
async def _(bot: Bot, event: Event, account: Player, event_session: EventSession, bot_info: UserInfo = BotUserInfo()): # noqa: B008
|
||||
async def _(nb_user: User, account: Player, event_session: EventSession, bot_info: UserInfo = BotUserInfo()): # noqa: B008
|
||||
async with trigger(
|
||||
session_persist_id=await get_session_persist_id(event_session),
|
||||
game_platform=GAME_TYPE,
|
||||
@@ -32,8 +31,7 @@ async def _(bot: Bot, event: Event, account: Player, event_session: EventSession
|
||||
async with get_session() as session:
|
||||
bind_status = await create_or_update_bind(
|
||||
session=session,
|
||||
chat_platform=get_platform(bot),
|
||||
chat_account=event.get_user_id(),
|
||||
user=nb_user,
|
||||
game_platform=GAME_TYPE,
|
||||
game_account=user.unique_identifier,
|
||||
)
|
||||
@@ -41,7 +39,7 @@ async def _(bot: Bot, event: Event, account: Player, event_session: EventSession
|
||||
if bind_status in (BindStatus.SUCCESS, BindStatus.UPDATE):
|
||||
async with HostPage(
|
||||
await render(
|
||||
'binding',
|
||||
'v1/binding',
|
||||
Bind(
|
||||
platform='TETR.IO',
|
||||
status='unknown',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import contextlib
|
||||
from asyncio import gather
|
||||
from collections import defaultdict
|
||||
from contextlib import suppress
|
||||
from datetime import date, datetime, timedelta, timezone
|
||||
from hashlib import md5
|
||||
from math import ceil, floor
|
||||
@@ -10,7 +10,7 @@ from zoneinfo import ZoneInfo
|
||||
|
||||
from aiofiles import open
|
||||
from nonebot import get_driver
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.adapters import Event
|
||||
from nonebot.compat import type_validate_json
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot_plugin_alconna import At
|
||||
@@ -20,12 +20,12 @@ from nonebot_plugin_localstore import get_data_file # type: ignore[import-untyp
|
||||
from nonebot_plugin_orm import get_session
|
||||
from nonebot_plugin_session import EventSession # type: ignore[import-untyped]
|
||||
from nonebot_plugin_session_orm import get_session_persist_id # type: ignore[import-untyped]
|
||||
from nonebot_plugin_user import get_user # type: ignore[import-untyped]
|
||||
from sqlalchemy import select
|
||||
from zstandard import ZstdDecompressor
|
||||
|
||||
from ...db import query_bind_info, trigger
|
||||
from ...utils.host import HostPage, get_self_netloc
|
||||
from ...utils.platform import get_platform
|
||||
from ...utils.render import render
|
||||
from ...utils.render.schemas.base import Avatar, Ranking
|
||||
from ...utils.render.schemas.tetrio_info import Data, Info, Radar, TetraLeague, TetraLeagueHistory
|
||||
@@ -48,7 +48,7 @@ driver = get_driver()
|
||||
|
||||
|
||||
@alc.assign('query')
|
||||
async def _(bot: Bot, event: Event, matcher: Matcher, target: At | Me, event_session: EventSession):
|
||||
async def _(event: Event, matcher: Matcher, target: At | Me, event_session: EventSession):
|
||||
async with trigger(
|
||||
session_persist_id=await get_session_persist_id(event_session),
|
||||
game_platform=GAME_TYPE,
|
||||
@@ -58,8 +58,9 @@ async def _(bot: Bot, event: Event, matcher: Matcher, target: At | Me, event_ses
|
||||
async with get_session() as session:
|
||||
bind = await query_bind_info(
|
||||
session=session,
|
||||
chat_platform=get_platform(bot),
|
||||
chat_account=(target.target if isinstance(target, At) else event.get_user_id()),
|
||||
user=await get_user(
|
||||
event_session.platform, target.target if isinstance(target, At) else event.get_user_id()
|
||||
),
|
||||
game_platform=GAME_TYPE,
|
||||
)
|
||||
if bind is None:
|
||||
@@ -69,8 +70,8 @@ async def _(bot: Bot, event: Event, matcher: Matcher, target: At | Me, event_ses
|
||||
user, user_info, user_records = await gather(player.user, player.get_info(), player.get_records())
|
||||
sprint = user_records.data.records.sprint
|
||||
blitz = user_records.data.records.blitz
|
||||
with contextlib.suppress(TypeError):
|
||||
message += UniMessage.image(raw=await make_query_image(user, user_info, sprint.record, blitz.record))
|
||||
with suppress(TypeError):
|
||||
message.image(raw=await make_query_image(user, user_info, sprint.record, blitz.record))
|
||||
await message.finish()
|
||||
message += make_query_text(user_info, sprint, blitz)
|
||||
await message.finish()
|
||||
@@ -87,7 +88,7 @@ async def _(account: Player, event_session: EventSession):
|
||||
user, user_info, user_records = await gather(account.user, account.get_info(), account.get_records())
|
||||
sprint = user_records.data.records.sprint
|
||||
blitz = user_records.data.records.blitz
|
||||
with contextlib.suppress(TypeError):
|
||||
with suppress(TypeError):
|
||||
await UniMessage.image(raw=await make_query_image(user, user_info, sprint.record, blitz.record)).finish()
|
||||
await make_query_text(user_info, sprint, blitz).finish()
|
||||
|
||||
@@ -223,13 +224,13 @@ async def make_query_image(
|
||||
split_value, offset = get_split(value_max, value_min)
|
||||
if sprint is not None:
|
||||
duration = timedelta(milliseconds=sprint.endcontext.final_time).total_seconds()
|
||||
sprint_value = f'{duration:.1f}s' if duration < 60 else f'{duration // 60:.0f}m {duration % 60:.1f}s' # noqa: PLR2004
|
||||
sprint_value = f'{duration:.3f}s' if duration < 60 else f'{duration // 60:.0f}m {duration % 60:.3f}s' # noqa: PLR2004
|
||||
else:
|
||||
sprint_value = 'N/A'
|
||||
blitz_value = f'{blitz.endcontext.score:,}' if blitz is not None else 'N/A'
|
||||
async with HostPage(
|
||||
await render(
|
||||
'tetrio/info',
|
||||
'v1/tetrio/info',
|
||||
Info(
|
||||
user=TemplateUser(
|
||||
avatar=f'https://tetr.io/user-content/avatars/{user_info.data.user.id}.jpg?rv={user_info.data.user.avatar_revision}'
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
from urllib.parse import urlunparse
|
||||
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot_plugin_alconna.uniseg import UniMessage
|
||||
from nonebot_plugin_orm import get_session
|
||||
from nonebot_plugin_session import EventSession # type: ignore[import-untyped]
|
||||
from nonebot_plugin_session_orm import get_session_persist_id # type: ignore[import-untyped]
|
||||
from nonebot_plugin_user import User # type: ignore[import-untyped]
|
||||
from nonebot_plugin_userinfo import BotUserInfo, EventUserInfo, UserInfo # type: ignore[import-untyped]
|
||||
|
||||
from ...db import BindStatus, create_or_update_bind, trigger
|
||||
from ...utils.avatar import get_avatar
|
||||
from ...utils.host import HostPage, get_self_netloc
|
||||
from ...utils.platform import get_platform
|
||||
from ...utils.render import Bind, render
|
||||
from ...utils.render.schemas.base import People
|
||||
from ...utils.screenshot import screenshot
|
||||
@@ -21,11 +20,11 @@ from .constant import GAME_TYPE
|
||||
|
||||
@alc.assign('bind')
|
||||
async def _(
|
||||
bot: Bot,
|
||||
nb_user: User,
|
||||
account: Player,
|
||||
event_session: EventSession,
|
||||
bot_info: UserInfo = BotUserInfo(), # noqa: B008
|
||||
event_user_info: UserInfo = EventUserInfo(), # noqa: B008
|
||||
bot_info: UserInfo = BotUserInfo(), # noqa: B008
|
||||
):
|
||||
async with trigger(
|
||||
session_persist_id=await get_session_persist_id(event_session),
|
||||
@@ -37,15 +36,14 @@ async def _(
|
||||
async with get_session() as session:
|
||||
bind_status = await create_or_update_bind(
|
||||
session=session,
|
||||
chat_platform=get_platform(bot),
|
||||
chat_account=event_user_info.user_id,
|
||||
user=nb_user,
|
||||
game_platform=GAME_TYPE,
|
||||
game_account=user.unique_identifier,
|
||||
)
|
||||
if bind_status in (BindStatus.SUCCESS, BindStatus.UPDATE):
|
||||
async with HostPage(
|
||||
await render(
|
||||
'binding',
|
||||
'v1/binding',
|
||||
Bind(
|
||||
platform=GAME_TYPE,
|
||||
status='unknown',
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.adapters import Event
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot_plugin_alconna import At
|
||||
from nonebot_plugin_alconna.uniseg import UniMessage
|
||||
from nonebot_plugin_orm import get_session
|
||||
from nonebot_plugin_session import EventSession # type: ignore[import-untyped]
|
||||
from nonebot_plugin_session_orm import get_session_persist_id # type: ignore[import-untyped]
|
||||
from nonebot_plugin_user import get_user # type: ignore[import-untyped]
|
||||
|
||||
from ...db import query_bind_info, trigger
|
||||
from ...utils.metrics import get_metrics
|
||||
from ...utils.platform import get_platform
|
||||
from ...utils.typing import Me
|
||||
from ..constant import CANT_VERIFY_MESSAGE
|
||||
from . import alc
|
||||
@@ -18,7 +18,7 @@ from .constant import GAME_TYPE
|
||||
|
||||
|
||||
@alc.assign('query')
|
||||
async def _(bot: Bot, event: Event, matcher: Matcher, target: At | Me, event_session: EventSession):
|
||||
async def _(event: Event, matcher: Matcher, target: At | Me, event_session: EventSession):
|
||||
async with trigger(
|
||||
session_persist_id=await get_session_persist_id(event_session),
|
||||
game_platform=GAME_TYPE,
|
||||
@@ -28,8 +28,9 @@ async def _(bot: Bot, event: Event, matcher: Matcher, target: At | Me, event_ses
|
||||
async with get_session() as session:
|
||||
bind = await query_bind_info(
|
||||
session=session,
|
||||
chat_platform=get_platform(bot),
|
||||
chat_account=(target.target if isinstance(target, At) else event.get_user_id()),
|
||||
user=await get_user(
|
||||
event_session.platform, target.target if isinstance(target, At) else event.get_user_id()
|
||||
),
|
||||
game_platform=GAME_TYPE,
|
||||
)
|
||||
if bind is None:
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
from urllib.parse import urlunparse
|
||||
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot_plugin_alconna.uniseg import UniMessage
|
||||
from nonebot_plugin_orm import get_session
|
||||
from nonebot_plugin_session import EventSession # type: ignore[import-untyped]
|
||||
from nonebot_plugin_session_orm import get_session_persist_id # type: ignore[import-untyped]
|
||||
from nonebot_plugin_user import User # type: ignore[import-untyped]
|
||||
from nonebot_plugin_userinfo import BotUserInfo, EventUserInfo, UserInfo # type: ignore[import-untyped]
|
||||
|
||||
from ...db import BindStatus, create_or_update_bind, trigger
|
||||
from ...utils.avatar import get_avatar
|
||||
from ...utils.host import HostPage, get_self_netloc
|
||||
from ...utils.platform import get_platform
|
||||
from ...utils.render import Bind, render
|
||||
from ...utils.render.schemas.base import People
|
||||
from ...utils.screenshot import screenshot
|
||||
@@ -21,11 +20,11 @@ from .constant import GAME_TYPE
|
||||
|
||||
@alc.assign('bind')
|
||||
async def _(
|
||||
bot: Bot,
|
||||
nb_user: User,
|
||||
account: Player,
|
||||
event_session: EventSession,
|
||||
bot_info: UserInfo = BotUserInfo(), # noqa: B008
|
||||
event_user_info: UserInfo = EventUserInfo(), # noqa: B008
|
||||
bot_info: UserInfo = BotUserInfo(), # noqa: B008
|
||||
):
|
||||
async with trigger(
|
||||
session_persist_id=await get_session_persist_id(event_session),
|
||||
@@ -37,8 +36,7 @@ async def _(
|
||||
async with get_session() as session:
|
||||
bind_status = await create_or_update_bind(
|
||||
session=session,
|
||||
chat_platform=get_platform(bot),
|
||||
chat_account=event_user_info.user_id,
|
||||
user=nb_user,
|
||||
game_platform=GAME_TYPE,
|
||||
game_account=user.unique_identifier,
|
||||
)
|
||||
@@ -46,7 +44,7 @@ async def _(
|
||||
if bind_status in (BindStatus.SUCCESS, BindStatus.UPDATE):
|
||||
async with HostPage(
|
||||
await render(
|
||||
'binding',
|
||||
'v1/binding',
|
||||
Bind(
|
||||
platform=GAME_TYPE,
|
||||
status='unknown',
|
||||
|
||||
@@ -4,13 +4,14 @@ from http import HTTPStatus
|
||||
from typing import Literal, NamedTuple
|
||||
from urllib.parse import urlunparse
|
||||
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.adapters import Event
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot_plugin_alconna import At
|
||||
from nonebot_plugin_alconna.uniseg import UniMessage
|
||||
from nonebot_plugin_orm import get_session
|
||||
from nonebot_plugin_session import EventSession # type: ignore[import-untyped] # type: ignore[import-untyped]
|
||||
from nonebot_plugin_session import EventSession # type: ignore[import-untyped]
|
||||
from nonebot_plugin_session_orm import get_session_persist_id # type: ignore[import-untyped]
|
||||
from nonebot_plugin_user import get_user # type: ignore[import-untyped]
|
||||
from nonebot_plugin_userinfo import EventUserInfo, UserInfo # type: ignore[import-untyped]
|
||||
|
||||
from ...db import query_bind_info, trigger
|
||||
@@ -18,7 +19,6 @@ from ...utils.avatar import get_avatar
|
||||
from ...utils.exception import RequestError
|
||||
from ...utils.host import HostPage, get_self_netloc
|
||||
from ...utils.metrics import TetrisMetricsProWithLPMADPM, get_metrics
|
||||
from ...utils.platform import get_platform
|
||||
from ...utils.render import render
|
||||
from ...utils.render.schemas.base import People, Ranking
|
||||
from ...utils.render.schemas.tos_info import Info, Multiplayer, Radar
|
||||
@@ -60,7 +60,7 @@ def add_special_handlers(
|
||||
await UniMessage.image(
|
||||
raw=await make_query_image(user_info, game_data, event_user_info)
|
||||
).finish()
|
||||
await (await make_query_text(user_info, game_data)).finish()
|
||||
await make_query_text(user_info, game_data).finish()
|
||||
except RequestError as e:
|
||||
if e.status_code == HTTPStatus.BAD_REQUEST and '未找到此用户' in e.message:
|
||||
return
|
||||
@@ -99,8 +99,7 @@ except ImportError:
|
||||
|
||||
|
||||
@alc.assign('query')
|
||||
async def _( # noqa: PLR0913
|
||||
bot: Bot,
|
||||
async def _(
|
||||
event: Event,
|
||||
matcher: Matcher,
|
||||
target: At | Me,
|
||||
@@ -116,8 +115,9 @@ async def _( # noqa: PLR0913
|
||||
async with get_session() as session:
|
||||
bind = await query_bind_info(
|
||||
session=session,
|
||||
chat_platform=get_platform(bot),
|
||||
chat_account=(target.target if isinstance(target, At) else event.get_user_id()),
|
||||
user=await get_user(
|
||||
event_session.platform, target.target if isinstance(target, At) else event.get_user_id()
|
||||
),
|
||||
game_platform=GAME_TYPE,
|
||||
)
|
||||
if bind is None:
|
||||
@@ -129,7 +129,7 @@ async def _( # noqa: PLR0913
|
||||
await (
|
||||
message + UniMessage.image(raw=await make_query_image(user_info, game_data, event_user_info))
|
||||
).finish()
|
||||
await (message + await make_query_text(user_info, game_data)).finish()
|
||||
await (message + make_query_text(user_info, game_data)).finish()
|
||||
|
||||
|
||||
@alc.assign('query')
|
||||
@@ -143,7 +143,7 @@ async def _(account: Player, event_session: EventSession, event_user_info: UserI
|
||||
user_info, game_data = await gather(account.get_info(), get_game_data(account))
|
||||
if game_data is not None:
|
||||
await UniMessage.image(raw=await make_query_image(user_info, game_data, event_user_info)).finish()
|
||||
await (await make_query_text(user_info, game_data)).finish()
|
||||
await make_query_text(user_info, game_data).finish()
|
||||
|
||||
|
||||
class GameData(NamedTuple):
|
||||
@@ -201,10 +201,10 @@ async def get_game_data(player: Player, query_num: int = 50) -> GameData | None:
|
||||
async def make_query_image(user_info: UserInfoSuccess, game_data: GameData, event_user_info: UserInfo) -> bytes:
|
||||
metrics = game_data.metrics
|
||||
duration = timedelta(milliseconds=float(user_info.data.pb_sprint)).total_seconds()
|
||||
sprint_value = f'{duration:.1f}s' if duration < 60 else f'{duration // 60:.0f}m {duration % 60:.1f}s' # noqa: PLR2004
|
||||
sprint_value = f'{duration:.3f}s' if duration < 60 else f'{duration // 60:.0f}m {duration % 60:.3f}s' # noqa: PLR2004
|
||||
async with HostPage(
|
||||
await render(
|
||||
'tos/info',
|
||||
'v1/tos/info',
|
||||
Info(
|
||||
user=People(avatar=await get_avatar(event_user_info, 'Data URI', None), name=user_info.data.name),
|
||||
ranking=Ranking(rating=float(user_info.data.ranking), rd=round(float(user_info.data.rd_now), 2)),
|
||||
@@ -233,7 +233,7 @@ async def make_query_image(user_info: UserInfoSuccess, game_data: GameData, even
|
||||
return await screenshot(urlunparse(('http', get_self_netloc(), f'/host/{page_hash}.html', '', '', '')))
|
||||
|
||||
|
||||
async def make_query_text(user_info: UserInfoSuccess, game_data: GameData | None) -> UniMessage:
|
||||
def make_query_text(user_info: UserInfoSuccess, game_data: GameData | None) -> UniMessage:
|
||||
user_data = user_info.data
|
||||
message = f'用户 {user_data.name} ({user_data.teaid}) '
|
||||
if user_data.ranked_games == '0':
|
||||
|
||||
@@ -6,6 +6,7 @@ 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.top_info import Info as TOPInfo
|
||||
from .schemas.tos_info import Info as TOSInfo
|
||||
|
||||
@@ -15,23 +16,28 @@ env = Environment(
|
||||
|
||||
|
||||
@overload
|
||||
async def render(render_type: Literal['binding'], data: Bind) -> str: ...
|
||||
async def render(render_type: Literal['v1/binding'], data: Bind) -> str: ...
|
||||
|
||||
|
||||
@overload
|
||||
async def render(render_type: Literal['tetrio/info'], data: TETRIOInfo) -> str: ...
|
||||
async def render(render_type: Literal['v1/tetrio/info'], data: TETRIOInfo) -> str: ...
|
||||
|
||||
|
||||
@overload
|
||||
async def render(render_type: Literal['top/info'], data: TOPInfo) -> str: ...
|
||||
async def render(render_type: Literal['v2/tetrio/info'], data: TETRIOInfoV2) -> str: ...
|
||||
|
||||
|
||||
@overload
|
||||
async def render(render_type: Literal['tos/info'], data: TOSInfo) -> str: ...
|
||||
async def render(render_type: Literal['v1/top/info'], data: TOPInfo) -> str: ...
|
||||
|
||||
|
||||
@overload
|
||||
async def render(render_type: Literal['v1/tos/info'], data: TOSInfo) -> str: ...
|
||||
|
||||
|
||||
async def render(
|
||||
render_type: Literal['binding', 'tetrio/info', 'top/info', 'tos/info'], data: Bind | TETRIOInfo | TOPInfo | TOSInfo
|
||||
render_type: Literal['v1/binding', 'v1/tetrio/info', 'v2/tetrio/info', 'v1/top/info', 'v1/tos/info'],
|
||||
data: Bind | TETRIOInfo | TETRIOInfoV2 | TOPInfo | TOSInfo,
|
||||
) -> str:
|
||||
if PYDANTIC_V2:
|
||||
return await env.get_template('index.html').render_async(
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ....games.tetrio.api.typing import Rank
|
||||
from ...typing import Number
|
||||
from .base import Avatar
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
country: str | None
|
||||
|
||||
avatar: str | Avatar
|
||||
banner: str | None
|
||||
|
||||
bio: str | None
|
||||
|
||||
friend_count: int
|
||||
supporter_tier: int
|
||||
|
||||
verified: bool
|
||||
bad_standing: bool
|
||||
|
||||
badges: list[str]
|
||||
xp: Number
|
||||
|
||||
playtime: str
|
||||
join_at: datetime | None
|
||||
|
||||
|
||||
class Statistic(BaseModel):
|
||||
total: int
|
||||
wins: int
|
||||
|
||||
|
||||
class TetraLeague(BaseModel):
|
||||
rank: Rank
|
||||
highest_rank: Rank
|
||||
|
||||
tr: Number
|
||||
|
||||
glicko: Number
|
||||
rd: Number
|
||||
|
||||
global_rank: int
|
||||
country_rank: int
|
||||
|
||||
pps: Number
|
||||
|
||||
apm: Number
|
||||
adpm: Number
|
||||
|
||||
vs: Number
|
||||
adpl: Number
|
||||
|
||||
statistic: Statistic
|
||||
|
||||
|
||||
class Sprint(BaseModel):
|
||||
time: str
|
||||
global_rank: int | None
|
||||
play_at: datetime
|
||||
|
||||
|
||||
class Blitz(BaseModel):
|
||||
score: int
|
||||
global_rank: int | None
|
||||
play_at: datetime
|
||||
|
||||
|
||||
class Zen(BaseModel):
|
||||
score: int
|
||||
level: int
|
||||
|
||||
|
||||
class Info(BaseModel):
|
||||
user: User
|
||||
tetra_league: TetraLeague | None
|
||||
statistic: Statistic | None
|
||||
sprint: Sprint | None
|
||||
blitz: Blitz | None
|
||||
zen: Zen
|
||||
@@ -1,38 +1,44 @@
|
||||
from asyncio import sleep
|
||||
from collections.abc import Awaitable, Callable
|
||||
from collections.abc import Callable, Coroutine
|
||||
from contextlib import suppress
|
||||
from datetime import timedelta
|
||||
from functools import wraps
|
||||
from typing import TypeVar, cast
|
||||
from typing import Any, ParamSpec, TypeVar
|
||||
|
||||
from nonebot.log import logger
|
||||
from nonebot_plugin_alconna.uniseg import SerializeFailed, UniMessage
|
||||
|
||||
T = TypeVar('T')
|
||||
P = ParamSpec('P')
|
||||
|
||||
|
||||
def retry(
|
||||
max_attempts: int = 3,
|
||||
exception_type: type[BaseException] | tuple[type[BaseException], ...] = Exception,
|
||||
delay: timedelta | None = None,
|
||||
) -> Callable[[Callable[..., Awaitable[T]]], Callable[..., Awaitable[T]]]:
|
||||
def decorator(func: Callable[..., Awaitable[T]]) -> Callable[..., Awaitable[T]]:
|
||||
reply: str | UniMessage | None = None,
|
||||
) -> Callable[[Callable[P, Coroutine[Any, Any, T]]], Callable[P, Coroutine[Any, Any, T]]]:
|
||||
def decorator(func: Callable[P, Coroutine[Any, Any, T]]) -> Callable[P, Coroutine[Any, Any, T]]:
|
||||
@wraps(func)
|
||||
async def wrapper(*args, **kwargs) -> T: # noqa: ANN002, ANN003
|
||||
attempts = 0
|
||||
while attempts < max_attempts + 1:
|
||||
async def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
|
||||
for i in range(max_attempts + 1):
|
||||
if i > 0:
|
||||
message = f'Retrying: {func.__name__} ({i}/{max_attempts})'
|
||||
logger.debug(message)
|
||||
with suppress(SerializeFailed):
|
||||
await UniMessage(reply or message).send()
|
||||
if i == max_attempts:
|
||||
break
|
||||
try:
|
||||
return await func(*args, **kwargs)
|
||||
except exception_type as e: # noqa: PERF203
|
||||
except exception_type as e:
|
||||
if i == max_attempts:
|
||||
raise
|
||||
logger.exception(e)
|
||||
attempts += 1
|
||||
if attempts <= max_attempts:
|
||||
if delay is not None:
|
||||
await sleep(delay.total_seconds())
|
||||
logger.debug(f'Retrying: {func.__name__} ({attempts}/{max_attempts})')
|
||||
continue
|
||||
raise
|
||||
msg = 'Unexpectedly reached the end of the retry loop'
|
||||
raise RuntimeError(msg)
|
||||
if delay is not None:
|
||||
await sleep(delay.total_seconds())
|
||||
return await func(*args, **kwargs)
|
||||
|
||||
return cast(Callable[..., Awaitable[T]], wrapper)
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
from playwright.async_api import TimeoutError
|
||||
|
||||
from .browser import BrowserManager
|
||||
from .retry import retry
|
||||
|
||||
|
||||
@retry(exception_type=TimeoutError, reply='截图失败, 重试中')
|
||||
async def screenshot(url: str) -> bytes:
|
||||
browser = await BrowserManager.get_browser()
|
||||
async with (
|
||||
await browser.new_page(no_viewport=True, viewport={'width': 0, 'height': 0}) as page,
|
||||
await browser.new_page(viewport={'width': 3000, 'height': 3000}) as page,
|
||||
):
|
||||
await page.goto(url)
|
||||
await page.wait_for_load_state('networkidle')
|
||||
return await page.screenshot(full_page=True, type='png')
|
||||
await page.wait_for_load_state('networkidle', timeout=5000)
|
||||
return await page.locator('id=content').screenshot(timeout=5000, type='png')
|
||||
|
||||
124
poetry.lock
generated
124
poetry.lock
generated
@@ -1,4 +1,4 @@
|
||||
# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "aiocache"
|
||||
@@ -254,13 +254,13 @@ zookeeper = ["kazoo"]
|
||||
|
||||
[[package]]
|
||||
name = "arclet-alconna"
|
||||
version = "1.8.13"
|
||||
version = "1.8.14"
|
||||
description = "A High-performance, Generality, Humane Command Line Arguments Parser Library."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "arclet_alconna-1.8.13-py3-none-any.whl", hash = "sha256:7a85d51aa588c40e525f5df3a2e23db757cd051e06dd266401ddb6346cc857db"},
|
||||
{file = "arclet_alconna-1.8.13.tar.gz", hash = "sha256:19aba65958578b3287af9afcf051da903104553460c6198d3f9398de4b8371f7"},
|
||||
{file = "arclet_alconna-1.8.14-py3-none-any.whl", hash = "sha256:e74ec1d0ca6829592a15768f48c6af9e5d9bb75a4476a763550d71594f7019d7"},
|
||||
{file = "arclet_alconna-1.8.14.tar.gz", hash = "sha256:77b4b15b1c6b9873554b0990310f587016d9982b086680150febc21fa17390d6"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -643,6 +643,20 @@ files = [
|
||||
[package.extras]
|
||||
test = ["pytest (>=6)"]
|
||||
|
||||
[[package]]
|
||||
name = "expiringdict"
|
||||
version = "1.2.2"
|
||||
description = "Dictionary with auto-expiring values for caching purposes"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "expiringdict-1.2.2-py3-none-any.whl", hash = "sha256:09a5d20bc361163e6432a874edd3179676e935eb81b925eccef48d409a8a45e8"},
|
||||
{file = "expiringdict-1.2.2.tar.gz", hash = "sha256:300fb92a7e98f15b05cf9a856c1415b3bc4f2e132be07daa326da6414c23ee09"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
tests = ["coverage", "coveralls", "dill", "mock", "nose"]
|
||||
|
||||
[[package]]
|
||||
name = "fastapi"
|
||||
version = "0.111.0"
|
||||
@@ -1204,13 +1218,9 @@ files = [
|
||||
{file = "lxml-5.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:edcfa83e03370032a489430215c1e7783128808fd3e2e0a3225deee278585196"},
|
||||
{file = "lxml-5.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:28bf95177400066596cdbcfc933312493799382879da504633d16cf60bba735b"},
|
||||
{file = "lxml-5.2.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a745cc98d504d5bd2c19b10c79c61c7c3df9222629f1b6210c0368177589fb8"},
|
||||
{file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b590b39ef90c6b22ec0be925b211298e810b4856909c8ca60d27ffbca6c12e6"},
|
||||
{file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b336b0416828022bfd5a2e3083e7f5ba54b96242159f83c7e3eebaec752f1716"},
|
||||
{file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:c2faf60c583af0d135e853c86ac2735ce178f0e338a3c7f9ae8f622fd2eb788c"},
|
||||
{file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:4bc6cb140a7a0ad1f7bc37e018d0ed690b7b6520ade518285dc3171f7a117905"},
|
||||
{file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7ff762670cada8e05b32bf1e4dc50b140790909caa8303cfddc4d702b71ea184"},
|
||||
{file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:57f0a0bbc9868e10ebe874e9f129d2917750adf008fe7b9c1598c0fbbfdde6a6"},
|
||||
{file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:a6d2092797b388342c1bc932077ad232f914351932353e2e8706851c870bca1f"},
|
||||
{file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:60499fe961b21264e17a471ec296dcbf4365fbea611bf9e303ab69db7159ce61"},
|
||||
{file = "lxml-5.2.2-cp37-cp37m-win32.whl", hash = "sha256:d9b342c76003c6b9336a80efcc766748a333573abf9350f4094ee46b006ec18f"},
|
||||
{file = "lxml-5.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b16db2770517b8799c79aa80f4053cd6f8b716f21f8aca962725a9565ce3ee40"},
|
||||
@@ -1734,20 +1744,21 @@ nonebot2 = ">=2.2.0"
|
||||
|
||||
[[package]]
|
||||
name = "nonebot-plugin-alconna"
|
||||
version = "0.46.1"
|
||||
version = "0.46.4"
|
||||
description = "Alconna Adapter for Nonebot"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "nonebot_plugin_alconna-0.46.1-py3-none-any.whl", hash = "sha256:4737e2036929f012181c832823a9d6d8e9992b939a0116ab5a81b49763565292"},
|
||||
{file = "nonebot_plugin_alconna-0.46.1.tar.gz", hash = "sha256:e5e7b8b61cb472e51546c72a29a254a5152b55ddbf1e1b8a249382b9d2db13a1"},
|
||||
{file = "nonebot_plugin_alconna-0.46.4-py3-none-any.whl", hash = "sha256:332aa98056f02b63aa194536cfac42387496d8ece29f354d5499418ca33fe83d"},
|
||||
{file = "nonebot_plugin_alconna-0.46.4.tar.gz", hash = "sha256:60f6bf93d82117cca52948cfaa5f4563ee8ed6c942d1993634d88a14ada8c27f"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
arclet-alconna = ">=1.8.12"
|
||||
arclet-alconna = ">=1.8.14"
|
||||
arclet-alconna-tools = ">=0.7.4"
|
||||
importlib-metadata = ">=4.13.0"
|
||||
nepattern = ">=0.7.4"
|
||||
nonebot-plugin-waiter = ">=0.6.0"
|
||||
nonebot2 = ">=2.3.0"
|
||||
|
||||
[[package]]
|
||||
@@ -1784,13 +1795,13 @@ typing-extensions = ">=4.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "nonebot-plugin-orm"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
description = "SQLAlchemy ORM support for nonebot"
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.8"
|
||||
files = [
|
||||
{file = "nonebot_plugin_orm-0.7.2-py3-none-any.whl", hash = "sha256:a9fce44d7d80a98b7e07125abe26529995fde967e1f9dd390180d70734f9c596"},
|
||||
{file = "nonebot_plugin_orm-0.7.2.tar.gz", hash = "sha256:12f12e8b1be5d5f75bba0a630e5112ad4041b0ef67469dbcd7ac6557faec0953"},
|
||||
{file = "nonebot_plugin_orm-0.7.3-py3-none-any.whl", hash = "sha256:9b0d114a4e7b2e452cb333e7147ae4216dff2f9685df616e5fa1f3f892d8795b"},
|
||||
{file = "nonebot_plugin_orm-0.7.3.tar.gz", hash = "sha256:cbb573598d0ecef2d0e75b5bdebd05297c68a2b368029a8763660f2a45381a2c"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -1847,6 +1858,24 @@ nonebot-plugin-orm = ">=0.7.0,<1.0.0"
|
||||
nonebot-plugin-session = ">=0.3.0,<0.4.0"
|
||||
nonebot2 = {version = ">=2.2.0,<3.0.0", extras = ["fastapi"]}
|
||||
|
||||
[[package]]
|
||||
name = "nonebot-plugin-user"
|
||||
version = "0.2.0"
|
||||
description = "适用于 Nonebot2 的用户插件"
|
||||
optional = false
|
||||
python-versions = ">=3.8,<4.0"
|
||||
files = [
|
||||
{file = "nonebot_plugin_user-0.2.0-py3-none-any.whl", hash = "sha256:9b052551b13fd8f8fab39023a8088637b0447b0ef42d87f54a0e7e2c3c371740"},
|
||||
{file = "nonebot_plugin_user-0.2.0.tar.gz", hash = "sha256:f2f559e3381deb20a067fb2004a92f3625b1777da076ecfb956e334bdbe0f7d5"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
expiringdict = ">=1.2.2,<2.0.0"
|
||||
nonebot-plugin-alconna = ">=0.37.1"
|
||||
nonebot-plugin-orm = ">=0.7.0"
|
||||
nonebot-plugin-session = ">=0.3.0,<0.4.0"
|
||||
nonebot2 = ">=2.2.0,<3.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "nonebot-plugin-userinfo"
|
||||
version = "0.2.4"
|
||||
@@ -1865,6 +1894,20 @@ httpx = ">=0.20.0,<1.0.0"
|
||||
nonebot2 = ">=2.0.0,<3.0.0"
|
||||
strenum = ">=0.4.8,<0.5.0"
|
||||
|
||||
[[package]]
|
||||
name = "nonebot-plugin-waiter"
|
||||
version = "0.6.1"
|
||||
description = "An alternative for got-and-reject in Nonebot"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "nonebot_plugin_waiter-0.6.1-py3-none-any.whl", hash = "sha256:0abd678ff7671a2f5cee53b8c96fdbb700a78bbff921e8f37ab1e9388bdc8649"},
|
||||
{file = "nonebot_plugin_waiter-0.6.1.tar.gz", hash = "sha256:ba4da15694ef4eeb23329e7ecde7e9e56df5cbf8e0dc03b8f98747658bbc138f"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
nonebot2 = ">=2.3.0"
|
||||
|
||||
[[package]]
|
||||
name = "nonebot2"
|
||||
version = "2.3.1"
|
||||
@@ -2018,7 +2061,6 @@ optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "pandas-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce"},
|
||||
{file = "pandas-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238"},
|
||||
{file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08"},
|
||||
{file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0"},
|
||||
{file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51"},
|
||||
@@ -2039,7 +2081,6 @@ files = [
|
||||
{file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32"},
|
||||
{file = "pandas-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a"},
|
||||
@@ -2085,17 +2126,20 @@ xml = ["lxml (>=4.9.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "pandas-stubs"
|
||||
version = "2.2.2.240514"
|
||||
version = "2.2.2.240603"
|
||||
description = "Type annotations for pandas"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "pandas_stubs-2.2.2.240514-py3-none-any.whl", hash = "sha256:5d6f64d45a98bc94152a0f76fa648e598cd2b9ba72302fd34602479f0c391a53"},
|
||||
{file = "pandas_stubs-2.2.2.240514.tar.gz", hash = "sha256:85b20da44a62c80eb8389bcf4cbfe31cce1cafa8cca4bf1fc75ec45892e72ce8"},
|
||||
{file = "pandas_stubs-2.2.2.240603-py3-none-any.whl", hash = "sha256:e08ce7f602a4da2bff5a67475ba881c39f2a4d4f7fccc1cba57c6f35a379c6c0"},
|
||||
{file = "pandas_stubs-2.2.2.240603.tar.gz", hash = "sha256:2dcc86e8fa6ea41535a4561c1f08b3942ba5267b464eff2e99caeee66f9e4cd1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
numpy = {version = ">=1.26.0", markers = "python_version < \"3.13\""}
|
||||
numpy = [
|
||||
{version = ">=1.23.5", markers = "python_version >= \"3.9\" and python_version < \"3.12\""},
|
||||
{version = ">=1.26.0", markers = "python_version >= \"3.12\" and python_version < \"3.13\""},
|
||||
]
|
||||
types-pytz = ">=2022.1.1"
|
||||
|
||||
[[package]]
|
||||
@@ -2631,28 +2675,28 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.4.4"
|
||||
version = "0.4.8"
|
||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "ruff-0.4.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:29d44ef5bb6a08e235c8249294fa8d431adc1426bfda99ed493119e6f9ea1bf6"},
|
||||
{file = "ruff-0.4.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c4efe62b5bbb24178c950732ddd40712b878a9b96b1d02b0ff0b08a090cbd891"},
|
||||
{file = "ruff-0.4.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c8e2f1e8fc12d07ab521a9005d68a969e167b589cbcaee354cb61e9d9de9c15"},
|
||||
{file = "ruff-0.4.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60ed88b636a463214905c002fa3eaab19795679ed55529f91e488db3fe8976ab"},
|
||||
{file = "ruff-0.4.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b90fc5e170fc71c712cc4d9ab0e24ea505c6a9e4ebf346787a67e691dfb72e85"},
|
||||
{file = "ruff-0.4.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:8e7e6ebc10ef16dcdc77fd5557ee60647512b400e4a60bdc4849468f076f6eef"},
|
||||
{file = "ruff-0.4.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9ddb2c494fb79fc208cd15ffe08f32b7682519e067413dbaf5f4b01a6087bcd"},
|
||||
{file = "ruff-0.4.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c51c928a14f9f0a871082603e25a1588059b7e08a920f2f9fa7157b5bf08cfe9"},
|
||||
{file = "ruff-0.4.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5eb0a4bfd6400b7d07c09a7725e1a98c3b838be557fee229ac0f84d9aa49c36"},
|
||||
{file = "ruff-0.4.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b1867ee9bf3acc21778dcb293db504692eda5f7a11a6e6cc40890182a9f9e595"},
|
||||
{file = "ruff-0.4.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1aecced1269481ef2894cc495647392a34b0bf3e28ff53ed95a385b13aa45768"},
|
||||
{file = "ruff-0.4.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9da73eb616b3241a307b837f32756dc20a0b07e2bcb694fec73699c93d04a69e"},
|
||||
{file = "ruff-0.4.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:958b4ea5589706a81065e2a776237de2ecc3e763342e5cc8e02a4a4d8a5e6f95"},
|
||||
{file = "ruff-0.4.4-py3-none-win32.whl", hash = "sha256:cb53473849f011bca6e754f2cdf47cafc9c4f4ff4570003a0dad0b9b6890e876"},
|
||||
{file = "ruff-0.4.4-py3-none-win_amd64.whl", hash = "sha256:424e5b72597482543b684c11def82669cc6b395aa8cc69acc1858b5ef3e5daae"},
|
||||
{file = "ruff-0.4.4-py3-none-win_arm64.whl", hash = "sha256:39df0537b47d3b597293edbb95baf54ff5b49589eb7ff41926d8243caa995ea6"},
|
||||
{file = "ruff-0.4.4.tar.gz", hash = "sha256:f87ea42d5cdebdc6a69761a9d0bc83ae9b3b30d0ad78952005ba6568d6c022af"},
|
||||
{file = "ruff-0.4.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7663a6d78f6adb0eab270fa9cf1ff2d28618ca3a652b60f2a234d92b9ec89066"},
|
||||
{file = "ruff-0.4.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eeceb78da8afb6de0ddada93112869852d04f1cd0f6b80fe464fd4e35c330913"},
|
||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aad360893e92486662ef3be0a339c5ca3c1b109e0134fcd37d534d4be9fb8de3"},
|
||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:284c2e3f3396fb05f5f803c9fffb53ebbe09a3ebe7dda2929ed8d73ded736deb"},
|
||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7354f921e3fbe04d2a62d46707e569f9315e1a613307f7311a935743c51a764"},
|
||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:72584676164e15a68a15778fd1b17c28a519e7a0622161eb2debdcdabdc71883"},
|
||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9678d5c9b43315f323af2233a04d747409d1e3aa6789620083a82d1066a35199"},
|
||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704977a658131651a22b5ebeb28b717ef42ac6ee3b11e91dc87b633b5d83142b"},
|
||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05f8d6f0c3cce5026cecd83b7a143dcad503045857bc49662f736437380ad45"},
|
||||
{file = "ruff-0.4.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6ea874950daca5697309d976c9afba830d3bf0ed66887481d6bca1673fc5b66a"},
|
||||
{file = "ruff-0.4.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fc95aac2943ddf360376be9aa3107c8cf9640083940a8c5bd824be692d2216dc"},
|
||||
{file = "ruff-0.4.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:384154a1c3f4bf537bac69f33720957ee49ac8d484bfc91720cc94172026ceed"},
|
||||
{file = "ruff-0.4.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e9d5ce97cacc99878aa0d084c626a15cd21e6b3d53fd6f9112b7fc485918e1fa"},
|
||||
{file = "ruff-0.4.8-py3-none-win32.whl", hash = "sha256:6d795d7639212c2dfd01991259460101c22aabf420d9b943f153ab9d9706e6a9"},
|
||||
{file = "ruff-0.4.8-py3-none-win_amd64.whl", hash = "sha256:e14a3a095d07560a9d6769a72f781d73259655919d9b396c650fc98a8157555d"},
|
||||
{file = "ruff-0.4.8-py3-none-win_arm64.whl", hash = "sha256:14019a06dbe29b608f6b7cbcec300e3170a8d86efaddb7b23405cb7f7dcaf780"},
|
||||
{file = "ruff-0.4.8.tar.gz", hash = "sha256:16d717b1d57b2e2fd68bd0bf80fb43931b79d05a7131aa477d66fc40fbd86268"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3638,4 +3682,4 @@ cffi = ["cffi (>=1.11)"]
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "f073f9fbc693de09d1db3f326451e3fa1b1233af5b04965d658cae297886cdd9"
|
||||
content-hash = "7eeac60a63bedc7ebff1466657b02fca9e6c4dcc6b525feca23c5bd664f92bdd"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = 'nonebot-plugin-tetris-stats'
|
||||
version = '1.2.10'
|
||||
version = '1.2.11'
|
||||
description = '一款基于 NoneBot2 的用于查询 Tetris 相关游戏数据的插件'
|
||||
authors = ['scdhh <wallfjjd@gmail.com>']
|
||||
readme = 'README.md'
|
||||
@@ -17,6 +17,7 @@ nonebot-plugin-localstore = "^0.6.0"
|
||||
nonebot-plugin-orm = ">=0.1.1,<0.8.0"
|
||||
nonebot-plugin-session = "^0.3.1"
|
||||
nonebot-plugin-session-orm = "^0.2.0"
|
||||
nonebot-plugin-user = "^0.2.0"
|
||||
nonebot-plugin-userinfo = "^0.2.4"
|
||||
aiocache = "^0.12.2"
|
||||
aiofiles = "^23.2.1"
|
||||
@@ -128,3 +129,4 @@ quote-style = 'single'
|
||||
|
||||
[tool.nonebot]
|
||||
plugins = ['nonebot_plugin_tetris_stats']
|
||||
# plugins = ['test_user']
|
||||
|
||||
Reference in New Issue
Block a user