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>
83 lines
2.5 KiB
Python
83 lines
2.5 KiB
Python
from hashlib import sha256
|
|
from ipaddress import IPv4Address, IPv6Address
|
|
from typing import ClassVar
|
|
|
|
from aiofiles import open
|
|
from fastapi import FastAPI, Query, Response, status
|
|
from fastapi.responses import FileResponse, HTMLResponse
|
|
from fastapi.staticfiles import StaticFiles
|
|
from nonebot import get_app, get_driver
|
|
from nonebot.log import logger
|
|
from nonebot_plugin_localstore import get_cache_dir # type: ignore[import-untyped]
|
|
from pydantic import IPvAnyAddress
|
|
|
|
from ..templates import path
|
|
from .avatar import generate_identicon
|
|
|
|
app = get_app()
|
|
|
|
driver = get_driver()
|
|
|
|
global_config = driver.config
|
|
|
|
cache_dir = get_cache_dir('nonebot_plugin_tetris_stats')
|
|
|
|
if not isinstance(app, FastAPI):
|
|
raise RuntimeError('本插件需要 FastAPI 驱动器才能运行') # noqa: TRY004
|
|
|
|
NOT_FOUND = HTMLResponse('404 Not Found', status_code=status.HTTP_404_NOT_FOUND)
|
|
|
|
|
|
class HostPage:
|
|
pages: ClassVar[dict[str, str]] = {}
|
|
|
|
def __init__(self, page: str) -> None:
|
|
self.page_hash = sha256(page.encode()).hexdigest()
|
|
self.pages[self.page_hash] = page
|
|
|
|
async def __aenter__(self) -> str:
|
|
return self.page_hash
|
|
|
|
async def __aexit__(self, exc_type, exc, tb) -> None: # noqa: ANN001
|
|
self.pages.pop(self.page_hash, None)
|
|
|
|
|
|
app.mount(
|
|
'/static',
|
|
StaticFiles(directory=path),
|
|
name='static',
|
|
)
|
|
|
|
|
|
@app.get('/host/page/{page_hash}.html', status_code=status.HTTP_200_OK)
|
|
async def _(page_hash: str) -> HTMLResponse:
|
|
if page_hash in HostPage.pages:
|
|
return HTMLResponse(HostPage.pages[page_hash])
|
|
return NOT_FOUND
|
|
|
|
|
|
@app.get('/identicon')
|
|
async def _(md5: str = Query(regex=r'^[a-fA-F0-9]{32}$')):
|
|
identicon_path = cache_dir / 'identicon' / f'{md5}.svg'
|
|
if identicon_path.exists() is False:
|
|
identicon_path.parent.mkdir(parents=True, exist_ok=True)
|
|
result = await generate_identicon(md5)
|
|
async with open(identicon_path, mode='xb') as file:
|
|
await file.write(result)
|
|
return Response(result, media_type='image/svg+xml')
|
|
logger.debug('Identicon Cache hit!')
|
|
return FileResponse(identicon_path, media_type='image/svg+xml')
|
|
|
|
|
|
def get_self_netloc() -> str:
|
|
host: IPv4Address | IPv6Address | IPvAnyAddress = global_config.host
|
|
if isinstance(host, IPv4Address):
|
|
if host == IPv4Address('0.0.0.0'): # noqa: S104
|
|
host = IPv4Address('127.0.0.1')
|
|
netloc = f'{host}:{global_config.port}'
|
|
else:
|
|
if host == IPv6Address('::'):
|
|
host = IPv6Address('::1')
|
|
netloc = f'[{host}]:{global_config.port}'
|
|
return netloc
|