mirror of
https://github.com/A-Minos/nonebot-plugin-tetris-stats.git
synced 2026-03-05 05:36:54 +08:00
* 🚧 查数据图初版测试 Co-authored-by: C1ystal <m17687496044@163.com> Co-authored-by: C29H25N3O5 <michaelgu495@gmail.com> * 🙈 添加一些 ignore 文件 * 🎨 格式化代码 * 🐛 修复格式化导致的样式爆炸 * 💄 优化曲线图观感 * 💄 将雷达图的指示器名称旋转显示 * 💄 查数据图第二版 Co-authored-by: C29H25N3O5 <michaelgu495@gmail.com> * ✏️ 修复 typo * 💄 把用户头像文件的引用放到 html 里 * 💄 账户绑定图第一版 Co-authored-by: C1ystal <m17687496044@163.com> Co-authored-by: C29H25N3O5 <michaelgu495@gmail.com> * 🚧 模板化测试 * ➕ 添加依赖 fastapi * ✨ 通过 FastAPI 提供静态文件 * ➕ 添加依赖 jinja2 * 💄 更新数据图模板 (#291) * feat(template): show actual value * feat(template): add user avatar * feat(template): fix radar * feat(style): fix name container width fixed caused display misplacement * feat(style): fix vs value wrap display * feat(template): make check data length in template * feat(template): update radar data * feat(jinja): update data * fix(template): fix typo * feat(style): prevent sign too long * feat(template): turn off echarts animation * chore(deps): add identicon.js * fix(template): fix typo * 🙈 更新.gitignore * 🏗️ 大部分重构为 flex 布局 --------- Co-authored-by: shoucandanghehe <wallfjjd@gmail.com> Co-authored-by: 呵呵です <51957264+shoucandanghehe@users.noreply.github.com> * ➕ 添加依赖 nonebot_plugin_userinfo * ✨ 通过 FastAPI 托管渲染后的模板 * ✨ 新增头像 api 使用 playwright 生成 * ✨ 修正模板资源文件引用路径 被托管后的正确路径 * 💄 将绑定图模板化 * 💄 重命名变量 * 🚚 重命名资源 * ✨ 使用 jinja2 渲染模板 * ✨ 使用 playwright 渲染网页 * 🩹 渲染模板时对 IO 进行一些额外处理 * ➕ 添加依赖 pillow * 🚚 修改托管页面的路由路径 * 💬 优化绑定图文案 * ✨ 新增获取自身网络位置的方法 * 🍱 更新 unknown.svg * ✨ 新增获取用户头像的方法 * ✨ 绑定消息使用图片回复 * ✨ 为 identicon api 添加缓存 * 🔥 删除旧文件 * 🚚 重命名模板 * 📄 添加字体 License * 🙈 更新.gitignore --------- Co-authored-by: C1ystal <m17687496044@163.com> Co-authored-by: C29H25N3O5 <michaelgu495@gmail.com> Co-authored-by: 渣渣120 <WOSHIZHAZHA120@qq.com>
This commit is contained in:
@@ -4,6 +4,8 @@ from typing import Any
|
||||
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot_plugin_alconna import AlcMatches, AlconnaMatcher
|
||||
from nonebot_plugin_alconna.uniseg import UniMessage
|
||||
from nonebot_plugin_userinfo import UserInfo # type: ignore[import-untyped]
|
||||
|
||||
from ..utils.exception import MessageFormatError
|
||||
from ..utils.recorder import Recorder
|
||||
@@ -41,7 +43,14 @@ class Processor(ABC):
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
async def handle_bind(self, platform: str, account: str) -> str:
|
||||
async def handle_bind(
|
||||
self,
|
||||
platform: str,
|
||||
account: str,
|
||||
bot_info: UserInfo,
|
||||
*args: Any, # noqa: ANN401
|
||||
**kwargs: Any, # noqa: ANN401
|
||||
) -> UniMessage:
|
||||
"""处理绑定消息"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ from nonebot.adapters import Bot, Event
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot_plugin_alconna import At, on_alconna
|
||||
from nonebot_plugin_orm import get_session
|
||||
from nonebot_plugin_userinfo import BotUserInfo, UserInfo # type: ignore[import-untyped]
|
||||
from sqlalchemy import func, select
|
||||
|
||||
from ...db import query_bind_info
|
||||
@@ -86,17 +87,16 @@ alc.shortcut('fkosk', {'command': 'io查', 'args': ['我']})
|
||||
|
||||
|
||||
@alc.assign('bind')
|
||||
async def _(bot: Bot, event: Event, matcher: Matcher, account: User):
|
||||
proc = Processor(
|
||||
event_id=id(event),
|
||||
user=account,
|
||||
command_args=[],
|
||||
)
|
||||
async def _(bot: Bot, event: Event, matcher: Matcher, account: User, bot_info: UserInfo = BotUserInfo()): # noqa: B008
|
||||
proc = Processor(event_id=id(event), user=account, command_args=[])
|
||||
try:
|
||||
await matcher.finish(await proc.handle_bind(platform=get_platform(bot), account=event.get_user_id()))
|
||||
await (
|
||||
await proc.handle_bind(platform=get_platform(bot), account=event.get_user_id(), bot_info=bot_info)
|
||||
).send()
|
||||
except NeedCatchError as e:
|
||||
await matcher.send(str(e))
|
||||
raise HandleNotFinishedError from e
|
||||
await matcher.finish()
|
||||
|
||||
|
||||
@alc.assign('query')
|
||||
|
||||
@@ -1,26 +1,33 @@
|
||||
from collections import defaultdict
|
||||
from collections.abc import Callable
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from hashlib import sha512
|
||||
from hashlib import md5, sha512
|
||||
from math import floor
|
||||
from re import match
|
||||
from statistics import mean
|
||||
from typing import Literal
|
||||
from urllib.parse import urlunparse
|
||||
|
||||
from aiofiles import open
|
||||
from nonebot import get_driver
|
||||
from nonebot.compat import type_validate_json
|
||||
from nonebot.utils import run_sync
|
||||
from nonebot_plugin_alconna.uniseg import UniMessage
|
||||
from nonebot_plugin_apscheduler import scheduler # type: ignore[import-untyped]
|
||||
from nonebot_plugin_localstore import get_data_file # type: ignore[import-untyped]
|
||||
from nonebot_plugin_orm import get_session
|
||||
from nonebot_plugin_userinfo import UserInfo as NBUserInfo # type: ignore[import-untyped]
|
||||
from sqlalchemy import select
|
||||
from zstandard import ZstdCompressor
|
||||
|
||||
from ...db import create_or_update_bind
|
||||
from ...db import BindStatus, create_or_update_bind
|
||||
from ...utils.avatar import get_avatar
|
||||
from ...utils.exception import MessageFormatError, RequestError, WhatTheFuckError
|
||||
from ...utils.host import HostPage, get_self_netloc
|
||||
from ...utils.render import render
|
||||
from ...utils.request import splice_url
|
||||
from ...utils.retry import retry
|
||||
from ...utils.screenshot import screenshot
|
||||
from .. import Processor as ProcessorMeta
|
||||
from .cache import Cache
|
||||
from .constant import BASE_URL, GAME_TYPE, RANK_PERCENTILE
|
||||
@@ -65,20 +72,43 @@ class Processor(ProcessorMeta):
|
||||
def game_platform(self) -> Literal['IO']:
|
||||
return GAME_TYPE
|
||||
|
||||
async def handle_bind(self, platform: str, account: str) -> str:
|
||||
async def handle_bind(self, platform: str, account: str, bot_info: NBUserInfo) -> UniMessage:
|
||||
"""处理绑定消息"""
|
||||
self.command_type = 'bind'
|
||||
await self.get_user()
|
||||
if self.user.ID is None:
|
||||
raise # FIXME: 不知道怎么才能把这类型给变过来了
|
||||
async with get_session() as session:
|
||||
return await create_or_update_bind(
|
||||
bind_status = await create_or_update_bind(
|
||||
session=session,
|
||||
chat_platform=platform,
|
||||
chat_account=account,
|
||||
game_platform=GAME_TYPE,
|
||||
game_account=self.user.ID,
|
||||
)
|
||||
bot_avatar = await get_avatar(bot_info, 'Data URI', '../../static/logo/logo.svg')
|
||||
user_info = await self.get_user_info()
|
||||
if bind_status in (BindStatus.SUCCESS, BindStatus.UPDATE):
|
||||
async with HostPage(
|
||||
await render(
|
||||
'bind.j2.html',
|
||||
user_avatar=f'https://tetr.io/user-content/avatars/{user_info.data.user.id}.jpg?rv={user_info.data.user.avatar_revision}'
|
||||
if user_info.data.user.avatar_revision is not None
|
||||
else f'../../identicon?md5={md5(user_info.data.user.id.encode()).hexdigest()}', # noqa: S324
|
||||
state='unknown',
|
||||
bot_avatar=bot_avatar,
|
||||
game_type=self.game_platform,
|
||||
user_name=user_info.data.user.username.upper(),
|
||||
bot_name=bot_info.user_name,
|
||||
command='io查我',
|
||||
)
|
||||
) as page_hash:
|
||||
message = UniMessage.image(
|
||||
raw=await screenshot(
|
||||
urlunparse(('http', get_self_netloc(), f'/host/page/{page_hash}.html', '', '', ''))
|
||||
)
|
||||
)
|
||||
return message
|
||||
|
||||
async def handle_query(self) -> str:
|
||||
"""处理查询消息"""
|
||||
|
||||
@@ -3,6 +3,7 @@ from nonebot.adapters import Bot, Event
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot_plugin_alconna import At, on_alconna
|
||||
from nonebot_plugin_orm import get_session
|
||||
from nonebot_plugin_userinfo import BotUserInfo, EventUserInfo, UserInfo # type: ignore[import-untyped]
|
||||
|
||||
from ...db import query_bind_info
|
||||
from ...utils.exception import HandleNotFinishedError, NeedCatchError
|
||||
@@ -67,17 +68,29 @@ alc = on_alconna(
|
||||
|
||||
|
||||
@alc.assign('bind')
|
||||
async def _(bot: Bot, event: Event, matcher: Matcher, account: User):
|
||||
async def _( # noqa: PLR0913
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
matcher: Matcher,
|
||||
account: User,
|
||||
bot_info: UserInfo = BotUserInfo(), # noqa: B008
|
||||
user_info: UserInfo = EventUserInfo(), # noqa: B008
|
||||
):
|
||||
proc = Processor(
|
||||
event_id=id(event),
|
||||
user=account,
|
||||
command_args=[],
|
||||
)
|
||||
try:
|
||||
await matcher.finish(await proc.handle_bind(platform=get_platform(bot), account=event.get_user_id()))
|
||||
await (
|
||||
await proc.handle_bind(
|
||||
platform=get_platform(bot), account=event.get_user_id(), bot_info=bot_info, user_info=user_info
|
||||
)
|
||||
).send()
|
||||
except NeedCatchError as e:
|
||||
await matcher.send(str(e))
|
||||
raise HandleNotFinishedError from e
|
||||
await matcher.finish()
|
||||
|
||||
|
||||
@alc.assign('query')
|
||||
|
||||
@@ -3,15 +3,21 @@ from dataclasses import dataclass
|
||||
from io import StringIO
|
||||
from re import match
|
||||
from typing import Literal
|
||||
from urllib.parse import urlencode
|
||||
from urllib.parse import urlencode, urlunparse
|
||||
|
||||
from lxml import etree
|
||||
from nonebot_plugin_alconna.uniseg import UniMessage
|
||||
from nonebot_plugin_orm import get_session
|
||||
from nonebot_plugin_userinfo import UserInfo # type: ignore[import-untyped]
|
||||
from pandas import read_html
|
||||
|
||||
from ...db import create_or_update_bind
|
||||
from ...db import BindStatus, create_or_update_bind
|
||||
from ...utils.avatar import get_avatar
|
||||
from ...utils.exception import MessageFormatError, RequestError
|
||||
from ...utils.host import HostPage, get_self_netloc
|
||||
from ...utils.render import render
|
||||
from ...utils.request import Request, splice_url
|
||||
from ...utils.screenshot import screenshot
|
||||
from .. import Processor as ProcessorMeta
|
||||
from ..schemas import BaseUser
|
||||
from .constant import BASE_URL, GAME_TYPE
|
||||
@@ -60,18 +66,38 @@ class Processor(ProcessorMeta):
|
||||
def game_platform(self) -> Literal['TOP']:
|
||||
return GAME_TYPE
|
||||
|
||||
async def handle_bind(self, platform: str, account: str) -> str:
|
||||
async def handle_bind(self, platform: str, account: str, bot_info: UserInfo, user_info: UserInfo) -> UniMessage:
|
||||
"""处理绑定消息"""
|
||||
self.command_type = 'bind'
|
||||
await self.check_user()
|
||||
async with get_session() as session:
|
||||
return await create_or_update_bind(
|
||||
bind_status = await create_or_update_bind(
|
||||
session=session,
|
||||
chat_platform=platform,
|
||||
chat_account=account,
|
||||
game_platform=GAME_TYPE,
|
||||
game_account=self.user.name,
|
||||
)
|
||||
bot_avatar = await get_avatar(bot_info, 'Data URI', '../../static/logo/logo.svg')
|
||||
if bind_status in (BindStatus.SUCCESS, BindStatus.UPDATE):
|
||||
async with HostPage(
|
||||
await render(
|
||||
'bind.j2.html',
|
||||
user_avatar='../../static/static/logo/top.ico',
|
||||
state='unknown',
|
||||
bot_avatar=bot_avatar,
|
||||
game_type=self.game_platform,
|
||||
user_name=(await self.get_user_name()).upper(),
|
||||
bot_name=bot_info.user_name,
|
||||
command='top查我',
|
||||
)
|
||||
) as page_hash:
|
||||
message = UniMessage.image(
|
||||
raw=await screenshot(
|
||||
urlunparse(('http', get_self_netloc(), f'/host/page/{page_hash}.html', '', '', ''))
|
||||
)
|
||||
)
|
||||
return message
|
||||
|
||||
async def handle_query(self) -> str:
|
||||
"""处理查询消息"""
|
||||
|
||||
@@ -5,6 +5,7 @@ from nonebot.adapters import Bot, Event
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot_plugin_alconna import At, on_alconna
|
||||
from nonebot_plugin_orm import get_session
|
||||
from nonebot_plugin_userinfo import BotUserInfo, UserInfo # type: ignore[import-untyped]
|
||||
|
||||
from ...db import query_bind_info
|
||||
from ...utils.exception import HandleNotFinishedError, NeedCatchError, RequestError
|
||||
@@ -130,17 +131,20 @@ except ImportError:
|
||||
|
||||
|
||||
@alc.assign('bind')
|
||||
async def _(bot: Bot, event: Event, matcher: Matcher, account: User):
|
||||
async def _(bot: Bot, event: Event, matcher: Matcher, account: User, bot_info: UserInfo = BotUserInfo()): # noqa: B008
|
||||
proc = Processor(
|
||||
event_id=id(event),
|
||||
user=account,
|
||||
command_args=[],
|
||||
)
|
||||
try:
|
||||
await matcher.finish(await proc.handle_bind(platform=get_platform(bot), account=event.get_user_id()))
|
||||
await (
|
||||
await proc.handle_bind(platform=get_platform(bot), account=event.get_user_id(), bot_info=bot_info)
|
||||
).send()
|
||||
except NeedCatchError as e:
|
||||
await matcher.send(str(e))
|
||||
raise HandleNotFinishedError from e
|
||||
await matcher.finish()
|
||||
|
||||
|
||||
@alc.assign('query')
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
from dataclasses import dataclass
|
||||
from re import match
|
||||
from typing import Literal
|
||||
from urllib.parse import urlencode
|
||||
from urllib.parse import urlencode, urlunparse
|
||||
|
||||
from httpx import TimeoutException
|
||||
from nonebot.compat import type_validate_json
|
||||
from nonebot_plugin_alconna.uniseg import UniMessage
|
||||
from nonebot_plugin_orm import get_session
|
||||
from nonebot_plugin_userinfo import UserInfo as NBUserInfo # type: ignore[import-untyped]
|
||||
|
||||
from ...db import create_or_update_bind
|
||||
from ...db import BindStatus, create_or_update_bind
|
||||
from ...utils.avatar import get_avatar
|
||||
from ...utils.exception import MessageFormatError, RequestError
|
||||
from ...utils.host import HostPage, get_self_netloc
|
||||
from ...utils.render import render
|
||||
from ...utils.request import Request, splice_url
|
||||
from ...utils.screenshot import screenshot
|
||||
from .. import Processor as ProcessorMeta
|
||||
from ..schemas import BaseUser
|
||||
from .constant import BASE_URL, GAME_TYPE
|
||||
@@ -73,18 +79,39 @@ class Processor(ProcessorMeta):
|
||||
def game_platform(self) -> Literal['TOS']:
|
||||
return GAME_TYPE
|
||||
|
||||
async def handle_bind(self, platform: str, account: str) -> str:
|
||||
async def handle_bind(self, platform: str, account: str, bot_info: NBUserInfo) -> UniMessage:
|
||||
"""处理绑定消息"""
|
||||
self.command_type = 'bind'
|
||||
await self.get_user()
|
||||
async with get_session() as session:
|
||||
return await create_or_update_bind(
|
||||
bind_status = await create_or_update_bind(
|
||||
session=session,
|
||||
chat_platform=platform,
|
||||
chat_account=account,
|
||||
game_platform=GAME_TYPE,
|
||||
game_account=self.user.unique_identifier,
|
||||
)
|
||||
bot_avatar = await get_avatar(bot_info, 'Data URI', '../../static/logo/logo.svg')
|
||||
user_info = await self.get_user_info()
|
||||
if bind_status in (BindStatus.SUCCESS, BindStatus.UPDATE):
|
||||
async with HostPage(
|
||||
await render(
|
||||
'bind.j2.html',
|
||||
user_avatar='../../static/static/logo/tos.ico',
|
||||
state='unknown',
|
||||
bot_avatar=bot_avatar,
|
||||
game_type=self.game_platform,
|
||||
user_name=user_info.data.name.upper(),
|
||||
bot_name=bot_info.user_name,
|
||||
command='茶服查我',
|
||||
)
|
||||
) as page_hash:
|
||||
message = UniMessage.image(
|
||||
raw=await screenshot(
|
||||
urlunparse(('http', get_self_netloc(), f'/host/page/{page_hash}.html', '', '', ''))
|
||||
)
|
||||
)
|
||||
return message
|
||||
|
||||
async def handle_query(self) -> str:
|
||||
"""处理查询消息"""
|
||||
|
||||
Reference in New Issue
Block a user