diff --git a/.vscode/settings.json b/.vscode/settings.json
index 69e2b4b..8c89b82 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -4,6 +4,7 @@
"apscheduler",
"arclet",
"Arparma",
+ "bnum",
"cesaa",
"chatdatanum",
"chatrecorder",
@@ -15,6 +16,7 @@
"pygal",
"sqlalchemy",
"userinfo",
+ "whereclause",
"xaxis",
"yaxis"
]
diff --git a/nonebot_plugin_dialectlist/__init__.py b/nonebot_plugin_dialectlist/__init__.py
index 2ce7ad9..41af1f3 100644
--- a/nonebot_plugin_dialectlist/__init__.py
+++ b/nonebot_plugin_dialectlist/__init__.py
@@ -8,12 +8,9 @@ require("nonebot_plugin_alconna")
require("nonebot_plugin_cesaa")
import re
+import os
import nonebot_plugin_saa as saa
-from pyecharts.charts import Bar
-from pyecharts import options as opts
-from pyecharts.globals import ThemeType
-
from typing import Union, Optional, List
from datetime import datetime, timedelta
from arclet.alconna import ArparmaBehavior
@@ -50,13 +47,13 @@ from nonebot_plugin_session import Session, SessionIdType, extract_session
# from .function import *
from .config import Config, plugin_config
from .usage import __usage__
+from .time import get_datetime_fromisoformat_with_timezone, get_datetime_now_with_timezone,parse_datetime
+from .model import UserRankInfo
from .utils import (
- get_datetime_fromisoformat_with_timezone,
- get_datetime_now_with_timezone,
got_rank,
msg_counter,
persist_id2user_id,
- parse_datetime,
+ get_rank_image
)
__plugin_meta__ = PluginMetadata(
@@ -92,9 +89,9 @@ rank_cmd = on_alconna(
Alconna(
"B话榜",
Args["type?", ["今日", "昨日", "本周", "上周", "本月", "上月", "年度", "历史"]][
- "time?",
- str,
- ]["group_id?", str],
+ "time?",str,][
+ "group_id?", str
+ ],
behaviors=[SameTime()],
),
aliases={"废话榜"},
@@ -223,42 +220,45 @@ async def handle_rank(
time_stop=stop,
exclude_id1s=plugin_config.excluded_people,
)
-
rank = got_rank(msg_counter(messages))
+ rank2: List[UserRankInfo] = []
ids = await persist_id2user_id([int(i[0]) for i in rank])
for i in range(len(rank)):
rank[i][0] = str(ids[i])
+ logger.debug(rank[i])
+
+ total = sum([i[1] for i in rank])
- string: str = ""
- nicknames: List = []
for i in rank:
if user_info := await get_user_info(bot, event, user_id=str(i[0])):
- (
- nicknames.append(user_info.user_displayname)
- if user_info.user_displayname
- else (
- nicknames.append(user_info.user_name)
- if user_info.user_name
- else nicknames.append(user_info.user_id)
- )
+ user_nickname = user_info.user_displayname\
+ if user_info.user_displayname\
+ else user_info.user_name\
+ if user_info.user_name\
+ else\
+ user_info.user_id
+ user_avatar = await user_info.user_avatar.get_image()\
+ if user_info.user_avatar\
+ else open(os.path.dirname(os.path.abspath(__file__))+"/template/avatar/default.jpg", "rb").read()
+ user = UserRankInfo(**user_info.model_dump(),
+ user_bnum=i[1],
+ user_proportion= round(i[1] / total * 100, 2),
+ user_index= rank.index(i) + 1,
+ user_nickname=user_nickname,
+ user_avatar_bytes= user_avatar,
)
- else:
- nicknames.append(None)
- logger.debug(nicknames)
+ user.user_gender="她" if user_info.user_gender == "female" else "他" if user_info.user_gender == "male" else "ta"
+ rank2.append(user)
+
+ string: str = ""
for i in range(len(rank)):
- index = i + 1
- nickname, chatdatanum = nicknames[i], rank[i][1]
str_example = plugin_config.string_format.format(
- index=index, nickname=nickname, chatdatanum=chatdatanum
+ index=rank2[i].user_index,
+ nickname=rank2[i].user_nickname,
+ chatdatanum=rank2[i].user_bnum
)
string += str_example
-
- bar = Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
- bar.add_xaxis(nicknames)
- bar.add_yaxis("B话数量", [i[1] for i in rank]) # type: ignore
- bar.render(str(get_cache_file("nonebot_plugin_dialectlist", "cache.html")))
- with open(get_cache_file("nonebot_plugin_dialectlist", "cache.html")) as f:
- a = f.read()
- image = await html_to_pic(a, device_scale_factor=3.2)
+
+ image = await get_rank_image(rank2)
await (saa.Text(string) + saa.Image(image)).finish(reply=True)
diff --git a/nonebot_plugin_dialectlist/config.py b/nonebot_plugin_dialectlist/config.py
index 770d6af..ee2baab 100644
--- a/nonebot_plugin_dialectlist/config.py
+++ b/nonebot_plugin_dialectlist/config.py
@@ -9,6 +9,7 @@ class ScopedConfig(BaseModel):
timezone: Optional[str] = "Asia/Shanghai"
excluded_self: bool = True
string_format: str = "第{index}名:\n{nickname},{chatdatanum}条消息\n" # 消息格式
+ template_path: str = "./template/rank_template.j2" # 模板路径
visualization: bool = True # 是否可视化
excluded_people: List[str] = [] # 排除的人的QQ号
visualization_type: Literal["饼图", "圆环图", "柱状图"] = "圆环图" # 可视化方案
diff --git a/nonebot_plugin_dialectlist/model.py b/nonebot_plugin_dialectlist/model.py
new file mode 100644
index 0000000..ce8ca37
--- /dev/null
+++ b/nonebot_plugin_dialectlist/model.py
@@ -0,0 +1,11 @@
+from typing import Optional, Literal, List, Union
+from pydantic import BaseModel
+from nonebot_plugin_userinfo import get_user_info, UserInfo
+
+
+class UserRankInfo(UserInfo):
+ user_bnum: int
+ user_proportion: float
+ user_nickname: str
+ user_index: Union[int,str]
+ user_avatar_bytes: bytes
\ No newline at end of file
diff --git a/nonebot_plugin_dialectlist/render.py b/nonebot_plugin_dialectlist/render.py
deleted file mode 100644
index 70214e1..0000000
--- a/nonebot_plugin_dialectlist/render.py
+++ /dev/null
@@ -1 +0,0 @@
-# TODO 更好的图片渲染,支持自定义模板渲染。
diff --git a/nonebot_plugin_dialectlist/template/avatar/default.jpg b/nonebot_plugin_dialectlist/template/avatar/default.jpg
new file mode 100644
index 0000000..39f103a
Binary files /dev/null and b/nonebot_plugin_dialectlist/template/avatar/default.jpg differ
diff --git a/nonebot_plugin_dialectlist/temple/cache/头像.jpg b/nonebot_plugin_dialectlist/template/avatar/master.jpg
similarity index 97%
rename from nonebot_plugin_dialectlist/temple/cache/头像.jpg
rename to nonebot_plugin_dialectlist/template/avatar/master.jpg
index 014c344..c909a22 100644
Binary files a/nonebot_plugin_dialectlist/temple/cache/头像.jpg and b/nonebot_plugin_dialectlist/template/avatar/master.jpg differ
diff --git a/nonebot_plugin_dialectlist/temple/css/style.css b/nonebot_plugin_dialectlist/template/css/style.css
similarity index 92%
rename from nonebot_plugin_dialectlist/temple/css/style.css
rename to nonebot_plugin_dialectlist/template/css/style.css
index 9326d3b..206c320 100644
--- a/nonebot_plugin_dialectlist/temple/css/style.css
+++ b/nonebot_plugin_dialectlist/template/css/style.css
@@ -1,10 +1,11 @@
body {
- background-image: url('../img/background.jpg');
+ background-image: url('https://image.anosu.top/pixiv/direct?size=regular');
background-attachment: scroll;
margin: 0;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
+ width: 1024;
}
.container {
@@ -74,8 +75,8 @@ body {
border-radius: 2rem;
/* padding: 20px 40px; */
align-content: center;
- backdrop-filter: blur(30px);
- -webkit-backdrop-filter: blur(30px);
+ backdrop-filter: blur(10px);
+ -webkit-backdrop-filter: blur(10px);
}
.profile{
@@ -88,8 +89,8 @@ body {
}
.profile2{
- width: 4%;
- height: 4%;
+ width: 8%;
+ height: 8%;
border: 3px solid rgba(255, 255, 255, 0.61);
border-radius: 2000px;
background-size: cover;
diff --git a/nonebot_plugin_dialectlist/template/rank_template.j2 b/nonebot_plugin_dialectlist/template/rank_template.j2
new file mode 100644
index 0000000..0c23982
--- /dev/null
+++ b/nonebot_plugin_dialectlist/template/rank_template.j2
@@ -0,0 +1,39 @@
+
+
+
+
+
+ 在 title 里夹一点私货应该不会被发现吧?——ddl 真是太厉害啦!
+
+
+
+
+
+
+
+
+
+ {% for i in users %}
+
+
+
+
第{{ i.user_index }}名:{{ i.user_name }}
+
+
{{ i.user_gender }}一共废话了{{ i.user_bnum }}句,占比{{ i.user_proportion }}%
+
+
+ {% endfor %}
+
+
+
+
+
+
Designed By ChenXu233
+
+
+
+
\ No newline at end of file
diff --git a/nonebot_plugin_dialectlist/temple/img/background.jpg b/nonebot_plugin_dialectlist/temple/img/background.jpg
deleted file mode 100644
index c6b9ca0..0000000
Binary files a/nonebot_plugin_dialectlist/temple/img/background.jpg and /dev/null differ
diff --git a/nonebot_plugin_dialectlist/temple/img/头像.jpg b/nonebot_plugin_dialectlist/temple/img/头像.jpg
deleted file mode 100644
index 014c344..0000000
Binary files a/nonebot_plugin_dialectlist/temple/img/头像.jpg and /dev/null differ
diff --git a/nonebot_plugin_dialectlist/temple/rank_temple.html b/nonebot_plugin_dialectlist/temple/rank_temple.html
deleted file mode 100644
index a121011..0000000
--- a/nonebot_plugin_dialectlist/temple/rank_temple.html
+++ /dev/null
@@ -1,104 +0,0 @@
-
-
-
-
-
- 在 title 里夹一点私货应该不会被发现吧?——ddl 真是太厉害啦!
-
-
-
-
-
-
-
-
-
-
-
第一名:ChenXu233
-
-
ta一共废话了12131231句,占比100%
-
-
-
-
-
-
第一名:ChenXu233
-
-
ta一共废话了12131231句,占比100%
-
-
-
-
-
-
第一名:ChenXu233
-
-
ta一共废话了12131231句,占比100%
-
-
-
-
-
-
第一名:ChenXu233
-
-
ta一共废话了12131231句,占比100%
-
-
-
-
-
-
第一名:ChenXu233
-
-
ta一共废话了12131231句,占比100%
-
-
-
-
-
-
第一名:ChenXu233
-
-
ta一共废话了12131231句,占比100%
-
-
-
-
-
-
第一名:ChenXu233
-
-
ta一共废话了12131231句,占比100%
-
-
-
-
-
-
第一名:ChenXu233
-
-
ta一共废话了12131231句,占比100%
-
-
-
-
-
-
-
Designed By ChenXu233
-
-
-
-
\ No newline at end of file
diff --git a/nonebot_plugin_dialectlist/time.py b/nonebot_plugin_dialectlist/time.py
index 148e153..5cd482b 100644
--- a/nonebot_plugin_dialectlist/time.py
+++ b/nonebot_plugin_dialectlist/time.py
@@ -1 +1,80 @@
# TODO 时间处理模块,用于处理时间相关操作。
+from datetime import datetime, time, tzinfo
+from typing import Optional, Union
+from zoneinfo import ZoneInfo
+
+from nonebot.typing import T_State
+from nonebot.params import Arg
+from nonebot.adapters import Message
+
+from nonebot_plugin_apscheduler import scheduler
+from nonebot_plugin_alconna import AlconnaMatcher
+
+
+from .config import plugin_config
+
+
+def parse_datetime(key: str):
+ """解析数字,并将结果存入 state 中"""
+
+ async def _key_parser(
+ matcher: AlconnaMatcher,
+ state: T_State,
+ input: Union[datetime, Message] = Arg(key),
+ ):
+ if isinstance(input, datetime):
+ return
+
+ plaintext = input.extract_plain_text()
+ try:
+ state[key] = get_datetime_fromisoformat_with_timezone(plaintext)
+ except ValueError:
+ await matcher.reject_arg(key, "请输入正确的日期,不然我没法理解呢!")
+
+ return _key_parser
+
+
+def get_datetime_now_with_timezone() -> datetime:
+ """获取当前时间,并包含时区信息"""
+ if plugin_config.timezone:
+ return datetime.now(ZoneInfo(plugin_config.timezone))
+ else:
+ return datetime.now().astimezone()
+
+
+def get_datetime_fromisoformat_with_timezone(date_string: str) -> datetime:
+ """从 ISO-8601 格式字符串中获取时间,并包含时区信息"""
+ if not plugin_config.timezone:
+ return datetime.fromisoformat(date_string).astimezone()
+ raw = datetime.fromisoformat(date_string)
+ return (
+ raw.astimezone(ZoneInfo(plugin_config.timezone))
+ if raw.tzinfo
+ else raw.replace(tzinfo=ZoneInfo(plugin_config.timezone))
+ )
+
+
+def time_astimezone(time: time, tz: Optional[tzinfo] = None) -> time:
+ """将 time 对象转换为指定时区的 time 对象
+
+ 如果 tz 为 None,则转换为本地时区
+ """
+ local_time = datetime.combine(datetime.today(), time)
+ return local_time.astimezone(tz).timetz()
+
+
+def get_time_fromisoformat_with_timezone(time_string: str) -> time:
+ """从 iso8601 格式字符串中获取时间,并包含时区信息"""
+ if not plugin_config.timezone:
+ return time_astimezone(time.fromisoformat(time_string))
+ raw = time.fromisoformat(time_string)
+ return (
+ time_astimezone(raw, ZoneInfo(plugin_config.timezone))
+ if raw.tzinfo
+ else raw.replace(tzinfo=ZoneInfo(plugin_config.timezone))
+ )
+
+
+def get_time_with_scheduler_timezone(time: time) -> time:
+ """获取转换到 APScheduler 时区的时间"""
+ return time_astimezone(time, scheduler.timezone)
diff --git a/nonebot_plugin_dialectlist/utils.py b/nonebot_plugin_dialectlist/utils.py
index baa4567..af9775d 100644
--- a/nonebot_plugin_dialectlist/utils.py
+++ b/nonebot_plugin_dialectlist/utils.py
@@ -1,6 +1,8 @@
-from datetime import datetime, time, tzinfo
+import os
+import unicodedata
+
from typing import Optional, Dict, List, Union
-from zoneinfo import ZoneInfo
+from pathlib import Path
from sqlalchemy import or_, select
from sqlalchemy.sql import ColumnElement
@@ -14,79 +16,17 @@ from nonebot_plugin_orm import get_session
from nonebot_plugin_session import Session, SessionLevel, extract_session
from nonebot_plugin_session_orm import SessionModel
from nonebot_plugin_userinfo import EventUserInfo, UserInfo
+from nonebot_plugin_htmlrender import html_to_pic,template_to_pic
from nonebot_plugin_apscheduler import scheduler
from nonebot_plugin_chatrecorder import MessageRecord
+from nonebot_plugin_localstore import get_cache_dir
from nonebot_plugin_alconna import AlconnaMatcher
from .config import plugin_config
+from .model import UserRankInfo
-
-def parse_datetime(key: str):
- """解析数字,并将结果存入 state 中"""
-
- async def _key_parser(
- matcher: AlconnaMatcher,
- state: T_State,
- input: Union[datetime, Message] = Arg(key),
- ):
- if isinstance(input, datetime):
- return
-
- plaintext = input.extract_plain_text()
- try:
- state[key] = get_datetime_fromisoformat_with_timezone(plaintext)
- except ValueError:
- await matcher.reject_arg(key, "请输入正确的日期,不然我没法理解呢!")
-
- return _key_parser
-
-
-def get_datetime_now_with_timezone() -> datetime:
- """获取当前时间,并包含时区信息"""
- if plugin_config.timezone:
- return datetime.now(ZoneInfo(plugin_config.timezone))
- else:
- return datetime.now().astimezone()
-
-
-def get_datetime_fromisoformat_with_timezone(date_string: str) -> datetime:
- """从 ISO-8601 格式字符串中获取时间,并包含时区信息"""
- if not plugin_config.timezone:
- return datetime.fromisoformat(date_string).astimezone()
- raw = datetime.fromisoformat(date_string)
- return (
- raw.astimezone(ZoneInfo(plugin_config.timezone))
- if raw.tzinfo
- else raw.replace(tzinfo=ZoneInfo(plugin_config.timezone))
- )
-
-
-def time_astimezone(time: time, tz: Optional[tzinfo] = None) -> time:
- """将 time 对象转换为指定时区的 time 对象
-
- 如果 tz 为 None,则转换为本地时区
- """
- local_time = datetime.combine(datetime.today(), time)
- return local_time.astimezone(tz).timetz()
-
-
-def get_time_fromisoformat_with_timezone(time_string: str) -> time:
- """从 iso8601 格式字符串中获取时间,并包含时区信息"""
- if not plugin_config.timezone:
- return time_astimezone(time.fromisoformat(time_string))
- raw = time.fromisoformat(time_string)
- return (
- time_astimezone(raw, ZoneInfo(plugin_config.timezone))
- if raw.tzinfo
- else raw.replace(tzinfo=ZoneInfo(plugin_config.timezone))
- )
-
-
-def get_time_with_scheduler_timezone(time: time) -> time:
- """获取转换到 APScheduler 时区的时间"""
- return time_astimezone(time, scheduler.timezone)
-
+cache_path = get_cache_dir("nonebot_plugin_dialectlist")
# 暂时不做考虑
# def admin_permission():
@@ -154,7 +94,7 @@ def msg_counter(msg_list: List[MessageRecord]) -> Dict[str, int]:
return lst
-def got_rank(msg_dict: Dict[str, int]) -> List[List[Union[str, int]]]:
+def got_rank(msg_dict: Dict[str, int]) -> List:
"""### 获得排行榜
Args:
@@ -175,34 +115,37 @@ def got_rank(msg_dict: Dict[str, int]) -> List[List[Union[str, int]]]:
plugin_config.get_num, len(rank)
)
)
- break
+ break
return rank
-# def remove_control_characters(string: str) -> str:
-# """### 将字符串中的控制符去除
+def remove_control_characters(string: str) -> str:
+ """### 将字符串中的控制符去除
-# Args:
-# string (str): 需要去除的字符串
+ Args:
+ string (str): 需要去除的字符串
-# Returns:
-# (str): 经过处理的字符串
-# """
-# return "".join(ch for ch in string if unicodedata.category(ch)[0] != "C")
+ Returns:
+ (str): 经过处理的字符串
+ """
+ return "".join(ch for ch in string if unicodedata.category(ch)[0] != "C")
-
-# async def render_template_pic(self) -> bytes:
-# if plugin_config.dialectlist_visualization_type == "圆环图":
-# view = pygal.Pie(inner_radius=0.6, style=style)
-# elif plugin_config.dialectlist_visualization_type == "饼图":
-# view = pygal.Pie(style=style)
-# else:
-# view = pygal.Bar(style=style)
-
-# view.title = "消息可视化"
-# for i, j in zip(self.rank, await self.get_nickname_list()): # type: ignore
-# view.add(str(j), int(i[1]))
-
-# png: bytes = view.render_to_png() # type: ignore
-# self.img = png
-# return png
\ No newline at end of file
+async def get_rank_image(rank: List[UserRankInfo]) -> bytes:
+ for i in rank:
+ if i.user_avatar:
+ try:
+ user_avatar = i.user_avatar_bytes
+ except NotImplementedError:
+ user_avatar = open(os.path.dirname(os.path.abspath(__file__))+"/template/avatar/default.jpg", "rb").read()
+ # if not os.path.exists(cache_path / str(i.user_id)):
+ with open(cache_path / (str(i.user_id) + ".jpg"), "wb") as f:
+ f.write(user_avatar)
+
+ if plugin_config.template_path[:2] == './':
+ path = os.path.dirname(os.path.abspath(__file__)) + plugin_config.template_path[1:]
+ else:
+ path = plugin_config.template_path
+
+ path_dir, filename = os.path.split(path)
+ logger.debug(os.path.dirname(os.path.abspath(__file__)) + plugin_config.template_path[1:])
+ return await template_to_pic(path_dir,filename,{'users': rank, 'cache_path': cache_path, 'file_path': os.path.dirname(os.path.abspath(__file__))})
\ No newline at end of file
diff --git a/pdm.lock b/pdm.lock
index 2cc3ce2..8ea5983 100644
--- a/pdm.lock
+++ b/pdm.lock
@@ -5,7 +5,7 @@
groups = ["default", "dev"]
strategy = ["cross_platform", "inherit_metadata"]
lock_version = "4.4.1"
-content_hash = "sha256:fdb46c5e66cf97af4806bb28cc369a5cfee536532eb9a1b05d581d5856ffcf6d"
+content_hash = "sha256:74fd9abb0888f1ded1c2cef549dd45e68a73c42bab5d7e37c1d3f2e5880a4cdb"
[[package]]
name = "aiofiles"
@@ -39,7 +39,7 @@ name = "annotated-types"
version = "0.7.0"
requires_python = ">=3.8"
summary = "Reusable constraint types to use with typing.Annotated"
-groups = ["default"]
+groups = ["default", "dev"]
files = [
{file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
@@ -50,7 +50,7 @@ name = "anyio"
version = "4.4.0"
requires_python = ">=3.8"
summary = "High level compatibility layer for multiple asynchronous event loop implementations"
-groups = ["default"]
+groups = ["default", "dev"]
dependencies = [
"exceptiongroup>=1.0.2; python_version < \"3.11\"",
"idna>=2.8",
@@ -109,6 +109,21 @@ files = [
{file = "arclet_alconna_tools-0.7.6.tar.gz", hash = "sha256:7cb7dc54c1c2198529c63227739423401051b8489374f1a7a3efa0c4e70b2a22"},
]
+[[package]]
+name = "arrow"
+version = "1.3.0"
+requires_python = ">=3.8"
+summary = "Better dates & times for Python"
+groups = ["dev"]
+dependencies = [
+ "python-dateutil>=2.7.0",
+ "types-python-dateutil>=2.8.10",
+]
+files = [
+ {file = "arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80"},
+ {file = "arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85"},
+]
+
[[package]]
name = "backports-tarfile"
version = "1.2.0"
@@ -121,6 +136,19 @@ files = [
{file = "backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"},
]
+[[package]]
+name = "binaryornot"
+version = "0.4.4"
+summary = "Ultra-lightweight pure Python package to check if a file is binary or text."
+groups = ["dev"]
+dependencies = [
+ "chardet>=3.0.2",
+]
+files = [
+ {file = "binaryornot-0.4.4-py2.py3-none-any.whl", hash = "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4"},
+ {file = "binaryornot-0.4.4.tar.gz", hash = "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061"},
+]
+
[[package]]
name = "cachetools"
version = "5.3.3"
@@ -132,6 +160,17 @@ files = [
{file = "cachetools-5.3.3.tar.gz", hash = "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105"},
]
+[[package]]
+name = "cashews"
+version = "7.1.0"
+requires_python = ">=3.8"
+summary = "cache tools with async power"
+groups = ["dev"]
+files = [
+ {file = "cashews-7.1.0-py3-none-any.whl", hash = "sha256:b7c1ae4d49df6fdbff88e5025d3c1156515f58724c5b96fc9a9d081afada82a8"},
+ {file = "cashews-7.1.0.tar.gz", hash = "sha256:058df55a39cb15697d331e7e41c2882b58d0d323f5671316105cc78668af7705"},
+]
+
[[package]]
name = "certifi"
version = "2024.6.2"
@@ -189,6 +228,17 @@ files = [
{file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"},
]
+[[package]]
+name = "chardet"
+version = "5.2.0"
+requires_python = ">=3.7"
+summary = "Universal encoding detector for Python 3"
+groups = ["dev"]
+files = [
+ {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"},
+ {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"},
+]
+
[[package]]
name = "charset-normalizer"
version = "3.3.2"
@@ -250,7 +300,7 @@ name = "click"
version = "8.1.7"
requires_python = ">=3.7"
summary = "Composable command line interface toolkit"
-groups = ["default"]
+groups = ["default", "dev"]
dependencies = [
"colorama; platform_system == \"Windows\"",
]
@@ -264,13 +314,34 @@ name = "colorama"
version = "0.4.6"
requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
summary = "Cross-platform colored terminal text."
-groups = ["default"]
+groups = ["default", "dev"]
marker = "sys_platform == \"win32\" or platform_system == \"Windows\""
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
+[[package]]
+name = "cookiecutter"
+version = "2.6.0"
+requires_python = ">=3.7"
+summary = "A command-line utility that creates projects from project templates, e.g. creating a Python package project from a Python package project template."
+groups = ["dev"]
+dependencies = [
+ "Jinja2<4.0.0,>=2.7",
+ "arrow",
+ "binaryornot>=0.4.4",
+ "click<9.0.0,>=7.0",
+ "python-slugify>=4.0.0",
+ "pyyaml>=5.3.1",
+ "requests>=2.23.0",
+ "rich",
+]
+files = [
+ {file = "cookiecutter-2.6.0-py3-none-any.whl", hash = "sha256:a54a8e37995e4ed963b3e82831072d1ad4b005af736bb17b99c2cbd9d41b6e2d"},
+ {file = "cookiecutter-2.6.0.tar.gz", hash = "sha256:db21f8169ea4f4fdc2408d48ca44859349de2647fbe494a9d6c3edfc0542c21c"},
+]
+
[[package]]
name = "cryptography"
version = "42.0.8"
@@ -316,6 +387,16 @@ files = [
{file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"},
]
+[[package]]
+name = "distlib"
+version = "0.3.8"
+summary = "Distribution utilities"
+groups = ["dev"]
+files = [
+ {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"},
+ {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
+]
+
[[package]]
name = "dnspython"
version = "2.6.1"
@@ -372,7 +453,7 @@ name = "exceptiongroup"
version = "1.2.1"
requires_python = ">=3.7"
summary = "Backport of PEP 654 (exception groups)"
-groups = ["default"]
+groups = ["default", "dev"]
marker = "python_version < \"3.11\""
files = [
{file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"},
@@ -417,6 +498,17 @@ files = [
{file = "fastapi_cli-0.0.4.tar.gz", hash = "sha256:e2e9ffaffc1f7767f488d6da34b6f5a377751c996f397902eb6abb99a67bde32"},
]
+[[package]]
+name = "filelock"
+version = "3.15.4"
+requires_python = ">=3.8"
+summary = "A platform independent file lock."
+groups = ["dev"]
+files = [
+ {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"},
+ {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"},
+]
+
[[package]]
name = "filetype"
version = "1.2.0"
@@ -469,7 +561,7 @@ name = "h11"
version = "0.14.0"
requires_python = ">=3.7"
summary = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
-groups = ["default"]
+groups = ["default", "dev"]
files = [
{file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
@@ -480,7 +572,7 @@ name = "httpcore"
version = "1.0.5"
requires_python = ">=3.8"
summary = "A minimal low-level HTTP client."
-groups = ["default"]
+groups = ["default", "dev"]
dependencies = [
"certifi",
"h11<0.15,>=0.13",
@@ -526,7 +618,7 @@ name = "httpx"
version = "0.27.0"
requires_python = ">=3.8"
summary = "The next generation HTTP client."
-groups = ["default"]
+groups = ["default", "dev"]
dependencies = [
"anyio",
"certifi",
@@ -635,7 +727,7 @@ name = "jinja2"
version = "3.1.4"
requires_python = ">=3.7"
summary = "A very fast and expressive template engine."
-groups = ["default"]
+groups = ["default", "dev"]
dependencies = [
"MarkupSafe>=2.0",
]
@@ -723,7 +815,7 @@ name = "markupsafe"
version = "2.1.5"
requires_python = ">=3.7"
summary = "Safely add untrusted strings to HTML/XML markup."
-groups = ["default"]
+groups = ["default", "dev"]
files = [
{file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"},
{file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"},
@@ -836,6 +928,33 @@ files = [
{file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"},
]
+[[package]]
+name = "nb-cli"
+version = "1.4.1"
+requires_python = "<4.0,>=3.9"
+summary = "CLI for nonebot2"
+groups = ["dev"]
+dependencies = [
+ "anyio<5.0,>=3.6",
+ "cashews<8.0,>=6.0",
+ "click~=8.1",
+ "cookiecutter~=2.2",
+ "httpx~=0.18",
+ "jinja2~=3.0",
+ "noneprompt<1.0.0,>=0.1.9",
+ "pydantic!=2.5.0,!=2.5.1,<3.0.0,>=1.10.0",
+ "pyfiglet<2.0.0,>=1.0.1",
+ "tomlkit~=0.10",
+ "typing-extensions~=4.4",
+ "virtualenv~=20.21",
+ "watchfiles~=0.16",
+ "wcwidth~=0.2",
+]
+files = [
+ {file = "nb_cli-1.4.1-py3-none-any.whl", hash = "sha256:57b6111773202bce29c0520f4a281edb8a7643fa33692d4afc70ca5b51b10f70"},
+ {file = "nb_cli-1.4.1.tar.gz", hash = "sha256:908dd4cbbf66bf46fe879c23ad1377332f63385cebca1912b627aa686d1816f3"},
+]
+
[[package]]
name = "nepattern"
version = "0.7.4"
@@ -1119,6 +1238,20 @@ files = [
{file = "nonebot2-2.3.1.tar.gz", hash = "sha256:ac5a1a1759f15310e9183b606ce6bdbe52a90287bf36a69201be548e23d41e6c"},
]
+[[package]]
+name = "noneprompt"
+version = "0.1.9"
+requires_python = ">=3.8,<4.0"
+summary = "Prompt toolkit for console interaction"
+groups = ["dev"]
+dependencies = [
+ "prompt-toolkit<4.0.0,>=3.0.19",
+]
+files = [
+ {file = "noneprompt-0.1.9-py3-none-any.whl", hash = "sha256:a54f1e6a19a3da2dedf7f365f80420e9ae49326a0ffe60a8a9c7afdee6b6eeb3"},
+ {file = "noneprompt-0.1.9.tar.gz", hash = "sha256:338b8bb89a8d22ef35f1dedb3aa7c1b228cf139973bdc43c5ffc3eef64457db9"},
+]
+
[[package]]
name = "orjson"
version = "3.10.5"
@@ -1167,6 +1300,17 @@ files = [
{file = "pkginfo-1.11.1.tar.gz", hash = "sha256:2e0dca1cf4c8e39644eed32408ea9966ee15e0d324c62ba899a393b3c6b467aa"},
]
+[[package]]
+name = "platformdirs"
+version = "4.2.2"
+requires_python = ">=3.8"
+summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
+groups = ["dev"]
+files = [
+ {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"},
+ {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"},
+]
+
[[package]]
name = "playwright"
version = "1.44.0"
@@ -1201,6 +1345,20 @@ files = [
{file = "prettytable-3.10.0.tar.gz", hash = "sha256:9665594d137fb08a1117518c25551e0ede1687197cf353a4fdc78d27e1073568"},
]
+[[package]]
+name = "prompt-toolkit"
+version = "3.0.47"
+requires_python = ">=3.7.0"
+summary = "Library for building powerful interactive command lines in Python"
+groups = ["dev"]
+dependencies = [
+ "wcwidth",
+]
+files = [
+ {file = "prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10"},
+ {file = "prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360"},
+]
+
[[package]]
name = "pycparser"
version = "2.22"
@@ -1218,7 +1376,7 @@ name = "pydantic"
version = "2.7.4"
requires_python = ">=3.8"
summary = "Data validation using Python type hints"
-groups = ["default"]
+groups = ["default", "dev"]
dependencies = [
"annotated-types>=0.4.0",
"pydantic-core==2.18.4",
@@ -1234,7 +1392,7 @@ name = "pydantic-core"
version = "2.18.4"
requires_python = ">=3.8"
summary = "Core functionality for Pydantic validation and serialization"
-groups = ["default"]
+groups = ["default", "dev"]
dependencies = [
"typing-extensions!=4.7.0,>=4.6.0",
]
@@ -1325,6 +1483,17 @@ files = [
{file = "pyee-11.1.0.tar.gz", hash = "sha256:b53af98f6990c810edd9b56b87791021a8f54fd13db4edd1142438d44ba2263f"},
]
+[[package]]
+name = "pyfiglet"
+version = "1.0.2"
+requires_python = ">=3.9"
+summary = "Pure-python FIGlet implementation"
+groups = ["dev"]
+files = [
+ {file = "pyfiglet-1.0.2-py3-none-any.whl", hash = "sha256:889b351d79c99e50a3f619c8f8e6ffdb27fd8c939fc43ecbd7559bd57d5f93ea"},
+ {file = "pyfiglet-1.0.2.tar.gz", hash = "sha256:758788018ab8faaddc0984e1ea05ff330d3c64be663c513cc1f105f6a3066dab"},
+]
+
[[package]]
name = "pygal"
version = "3.0.4"
@@ -1375,6 +1544,20 @@ files = [
{file = "pymdown_extensions-10.8.1.tar.gz", hash = "sha256:3ab1db5c9e21728dabf75192d71471f8e50f216627e9a1fa9535ecb0231b9940"},
]
+[[package]]
+name = "python-dateutil"
+version = "2.9.0.post0"
+requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+summary = "Extensions to the standard Python datetime module"
+groups = ["dev"]
+dependencies = [
+ "six>=1.5",
+]
+files = [
+ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
+ {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
+]
+
[[package]]
name = "python-dotenv"
version = "1.0.1"
@@ -1411,6 +1594,20 @@ files = [
{file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"},
]
+[[package]]
+name = "python-slugify"
+version = "8.0.4"
+requires_python = ">=3.7"
+summary = "A Python slugify application that also handles Unicode"
+groups = ["dev"]
+dependencies = [
+ "text-unidecode>=1.3",
+]
+files = [
+ {file = "python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856"},
+ {file = "python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8"},
+]
+
[[package]]
name = "pytz"
version = "2024.1"
@@ -1438,7 +1635,7 @@ name = "pyyaml"
version = "6.0.1"
requires_python = ">=3.6"
summary = "YAML parser and emitter for Python"
-groups = ["default"]
+groups = ["default", "dev"]
files = [
{file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"},
{file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"},
@@ -1658,7 +1855,7 @@ name = "six"
version = "1.16.0"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
summary = "Python 2 and 3 compatibility utilities"
-groups = ["default"]
+groups = ["default", "dev"]
files = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
@@ -1669,7 +1866,7 @@ name = "sniffio"
version = "1.3.1"
requires_python = ">=3.7"
summary = "Sniff out which async library your code is running under"
-groups = ["default"]
+groups = ["default", "dev"]
files = [
{file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
@@ -1779,6 +1976,16 @@ files = [
{file = "tarina-0.5.2.tar.gz", hash = "sha256:7d5d93d73422e97b2409e6a43bf4d11296fe2dac90a5b4dcbc19e56bc1b55298"},
]
+[[package]]
+name = "text-unidecode"
+version = "1.3"
+summary = "The most basic Text::Unidecode port"
+groups = ["dev"]
+files = [
+ {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"},
+ {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"},
+]
+
[[package]]
name = "tomli"
version = "2.0.1"
@@ -1791,6 +1998,17 @@ files = [
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
+[[package]]
+name = "tomlkit"
+version = "0.12.5"
+requires_python = ">=3.7"
+summary = "Style preserving TOML library"
+groups = ["dev"]
+files = [
+ {file = "tomlkit-0.12.5-py3-none-any.whl", hash = "sha256:af914f5a9c59ed9d0762c7b64d3b5d5df007448eb9cd2edc8a46b1eafead172f"},
+ {file = "tomlkit-0.12.5.tar.gz", hash = "sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c"},
+]
+
[[package]]
name = "twine"
version = "5.1.0"
@@ -1830,12 +2048,23 @@ files = [
{file = "typer-0.12.3.tar.gz", hash = "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"},
]
+[[package]]
+name = "types-python-dateutil"
+version = "2.9.0.20240316"
+requires_python = ">=3.8"
+summary = "Typing stubs for python-dateutil"
+groups = ["dev"]
+files = [
+ {file = "types-python-dateutil-2.9.0.20240316.tar.gz", hash = "sha256:5d2f2e240b86905e40944dd787db6da9263f0deabef1076ddaed797351ec0202"},
+ {file = "types_python_dateutil-2.9.0.20240316-py3-none-any.whl", hash = "sha256:6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b"},
+]
+
[[package]]
name = "typing-extensions"
version = "4.12.2"
requires_python = ">=3.8"
summary = "Backported and Experimental Type Hints for Python 3.8+"
-groups = ["default"]
+groups = ["default", "dev"]
files = [
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
@@ -2012,12 +2241,28 @@ files = [
{file = "uvloop-0.19.0.tar.gz", hash = "sha256:0246f4fd1bf2bf702e06b0d45ee91677ee5c31242f39aab4ea6fe0c51aedd0fd"},
]
+[[package]]
+name = "virtualenv"
+version = "20.26.3"
+requires_python = ">=3.7"
+summary = "Virtual Python Environment builder"
+groups = ["dev"]
+dependencies = [
+ "distlib<1,>=0.3.7",
+ "filelock<4,>=3.12.2",
+ "platformdirs<5,>=3.9.1",
+]
+files = [
+ {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"},
+ {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"},
+]
+
[[package]]
name = "watchfiles"
version = "0.22.0"
requires_python = ">=3.8"
summary = "Simple, modern and high performance file watching and code reload in python."
-groups = ["default"]
+groups = ["default", "dev"]
dependencies = [
"anyio>=3.0.0",
]
@@ -2079,7 +2324,7 @@ files = [
name = "wcwidth"
version = "0.2.13"
summary = "Measures the displayed width of unicode strings in a terminal"
-groups = ["default"]
+groups = ["default", "dev"]
files = [
{file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"},
{file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"},
diff --git a/pyproject.toml b/pyproject.toml
index f8b2e0a..7a43d36 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,7 +1,7 @@
[project]
name = "nonebot_plugin_dialectlist"
-version = "2.0.4"
-description = "Default template for PDM package"
+version = "2.1.4"
+description = "看看你群群友有多能说"
authors = [
{name = "Chen_Xu233", email = "woyerpa@outlook.com"},
]
@@ -27,6 +27,7 @@ dev = [
"ruff>=0.4.9",
"setuptools>=70.0.0",
"twine>=5.1.0",
+ "nb-cli>=0.7.6"
]
[tool.pdm]
diff --git a/tests/temple_render.py b/tests/temple_render.py
index 44a8114..cc9f3b7 100644
--- a/tests/temple_render.py
+++ b/tests/temple_render.py
@@ -4,7 +4,9 @@ with sync_playwright() as p:
for browser_type in [p.chromium, p.firefox, p.webkit]:
browser = browser_type.launch(headless=True)
page = browser.new_page()
- page.goto('file:///H:/Bot/%E7%8E%B0%E5%BD%B9Bot/mybot/src/nonebot_plugin_dialectlist/nonebot_plugin_dialectlist/temple/rank_temple.html')
- page.screenshot(path=f'screenshot-{browser_type.name}.png',full_page=True)
+ page.goto(
+ "file:///H:/Bot/%E7%8E%B0%E5%BD%B9Bot/mybot/src/nonebot_plugin_dialectlist/nonebot_plugin_dialectlist/temple/rank_temple.html"
+ )
+ page.screenshot(path=f"screenshot-{browser_type.name}.png", full_page=True)
print(page.title())
- browser.close()
\ No newline at end of file
+ browser.close()