mirror of
https://github.com/ChenXu233/nonebot_plugin_dialectlist.git
synced 2024-12-01 01:24:45 +08:00
🔥 ♻️ 暂时停止图片支持+依照词云重写
This commit is contained in:
parent
97c6bbb219
commit
e6cc909c88
12
.vscode/settings.json
vendored
12
.vscode/settings.json
vendored
@ -1,7 +1,17 @@
|
|||||||
{
|
{
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
|
"Alconna",
|
||||||
|
"apscheduler",
|
||||||
|
"arclet",
|
||||||
|
"Arparma",
|
||||||
|
"cesaa",
|
||||||
|
"chatdatanum",
|
||||||
"chatrecorder",
|
"chatrecorder",
|
||||||
"dialectlist",
|
"dialectlist",
|
||||||
"pygal"
|
"displayname",
|
||||||
|
"parameterless",
|
||||||
|
"pygal",
|
||||||
|
"sqlalchemy",
|
||||||
|
"userinfo"
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -1,185 +1,265 @@
|
|||||||
import re
|
from nonebot import require
|
||||||
import time
|
|
||||||
from typing import Tuple, Union
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
|
|
||||||
from nonebot import on_command, require
|
require("nonebot_plugin_chatrecorder")
|
||||||
|
require("nonebot_plugin_apscheduler")
|
||||||
|
require("nonebot_plugin_userinfo")
|
||||||
|
require("nonebot_plugin_alconna")
|
||||||
|
require("nonebot_plugin_cesaa")
|
||||||
|
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
import nonebot_plugin_saa as saa
|
||||||
|
|
||||||
|
from typing import Tuple, Union, Optional, List
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from arclet.alconna import ArparmaBehavior
|
||||||
|
from arclet.alconna.arparma import Arparma
|
||||||
|
|
||||||
|
from nonebot import on_command, get_driver
|
||||||
from nonebot.log import logger
|
from nonebot.log import logger
|
||||||
from nonebot.params import Command, CommandArg, Arg, Depends
|
from nonebot.params import Command, CommandArg, Arg, Depends
|
||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from nonebot.matcher import Matcher
|
from nonebot.matcher import Matcher
|
||||||
from nonebot.adapters.onebot import V11Bot, V12Bot, V11Event, V12Event, V11Message, V12Message # type: ignore
|
from nonebot import get_driver
|
||||||
|
from nonebot.adapters import Bot, Event, Message
|
||||||
|
from nonebot.params import Arg, Depends
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
from nonebot.plugin import PluginMetadata, inherit_supported_adapters
|
||||||
|
from nonebot.typing import T_State
|
||||||
|
from nonebot_plugin_alconna import (
|
||||||
|
Alconna,
|
||||||
|
AlconnaMatch,
|
||||||
|
AlconnaMatcher,
|
||||||
|
AlconnaQuery,
|
||||||
|
Args,
|
||||||
|
Match,
|
||||||
|
Option,
|
||||||
|
Query,
|
||||||
|
image_fetch,
|
||||||
|
on_alconna,
|
||||||
|
store_true,
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
|
||||||
from zoneinfo import ZoneInfo
|
|
||||||
except ImportError:
|
|
||||||
from backports.zoneinfo import ZoneInfo # type: ignore
|
|
||||||
|
|
||||||
require("nonebot_plugin_chatrecorder")
|
|
||||||
from nonebot_plugin_chatrecorder import get_message_records
|
from nonebot_plugin_chatrecorder import get_message_records
|
||||||
|
from nonebot_plugin_userinfo import EventUserInfo, UserInfo, get_user_info
|
||||||
from .function import *
|
from nonebot_plugin_session import Session, SessionIdType, extract_session
|
||||||
from .config import plugin_config
|
from nonebot_plugin_cesaa import get_messages_plain_text
|
||||||
|
|
||||||
|
|
||||||
ranks = on_command(
|
# from . import migrations #抄词云的部分代码,还不知道这有什么用
|
||||||
"群话痨排行榜",
|
# from .function import *
|
||||||
aliases={
|
from .config import Config, plugin_config
|
||||||
"今日群话痨排行榜",
|
from .utils import (
|
||||||
"昨日群话痨排行榜",
|
get_datetime_fromisoformat_with_timezone,
|
||||||
"本周群话痨排行榜",
|
get_datetime_now_with_timezone,
|
||||||
"上周群话痨排行榜",
|
got_rank,
|
||||||
"本月群话痨排行榜",
|
msg_counter,
|
||||||
"年度群话痨排行榜",
|
persist_id2user_id,
|
||||||
"历史群话痨排行榜",
|
)
|
||||||
},
|
|
||||||
priority=6,
|
with open(os.path.dirname(__file__) + "/usage.md") as f:
|
||||||
block=True,
|
usage = f.read()
|
||||||
|
|
||||||
|
__plugin_meta__ = PluginMetadata(
|
||||||
|
name="B话排行榜",
|
||||||
|
description="调查群U的B话数量,以一定的顺序排序后排序出来。",
|
||||||
|
usage=usage,
|
||||||
|
homepage="https://github.com/ChenXu233/nonebot_plugin_dialectlist",
|
||||||
|
type="application",
|
||||||
|
supported_adapters=inherit_supported_adapters(
|
||||||
|
"nonebot_plugin_chatrecorder", "nonebot_plugin_saa", "nonebot_plugin_alconna"
|
||||||
|
),
|
||||||
|
config=Config,
|
||||||
|
# extra={"orm_version_location": migrations},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ranks.handle()
|
# 抄的词云,不过真的很适合B话榜。
|
||||||
async def _group_message(
|
class SameTime(ArparmaBehavior):
|
||||||
matcher: Matcher,
|
def operate(self, interface: Arparma):
|
||||||
event: Union[
|
type = interface.query("type")
|
||||||
V11Event.GroupMessageEvent,
|
time = interface.query("time")
|
||||||
V12Event.GroupMessageEvent,
|
if type is None and time:
|
||||||
V12Event.ChannelMessageEvent,
|
interface.behave_fail()
|
||||||
|
|
||||||
|
|
||||||
|
rank_cmd = on_alconna(
|
||||||
|
Alconna(
|
||||||
|
"B话榜",
|
||||||
|
Args["type?", ["今日", "昨日", "本周", "上周", "本月", "上月", "年度", "历史"]][
|
||||||
|
"time?", str
|
||||||
],
|
],
|
||||||
|
behaviors=[SameTime()],
|
||||||
|
),
|
||||||
|
use_cmd_start=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def wrapper(slot: Union[int, str], content: Optional[str]) -> str:
|
||||||
|
if slot == "type" and content:
|
||||||
|
return content
|
||||||
|
return "" # pragma: no cover
|
||||||
|
|
||||||
|
|
||||||
|
rank_cmd.shortcut(
|
||||||
|
r"(?P<type>今日|昨日|本周|上周|本月|上月|年度|历史)B话榜",
|
||||||
|
{
|
||||||
|
"prefix": True,
|
||||||
|
"command": "B话榜 ",
|
||||||
|
"wrapper": wrapper,
|
||||||
|
"args": ["{type}"],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_datetime(key: str):
|
||||||
|
"""解析数字,并将结果存入 state 中"""
|
||||||
|
|
||||||
|
async def _key_parser(
|
||||||
|
matcher: AlconnaMatcher,
|
||||||
state: T_State,
|
state: T_State,
|
||||||
commands: Tuple[str, ...] = Command(),
|
input: Union[datetime, Message] = Arg(key),
|
||||||
args: Union[V11Message, V11Message] = CommandArg(),
|
):
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
# TODO 处理函数更新
|
||||||
|
# 参考词云
|
||||||
|
|
||||||
|
|
||||||
|
# 这段函数完全抄的词云
|
||||||
|
@rank_cmd.handle()
|
||||||
|
async def _group_message(
|
||||||
|
state: T_State,
|
||||||
|
type: Optional[str] = None,
|
||||||
|
time: Optional[str] = None,
|
||||||
):
|
):
|
||||||
if isinstance(event, V11Event.GroupMessageEvent):
|
|
||||||
logger.debug("handle command from onebotV11 adapter(qq)")
|
|
||||||
elif isinstance(event, V12Event.GroupMessageEvent):
|
|
||||||
logger.debug("handle command from onebotV12 adapter")
|
|
||||||
|
|
||||||
dt = get_datetime_now_with_timezone()
|
dt = get_datetime_now_with_timezone()
|
||||||
command = commands[0]
|
|
||||||
|
|
||||||
if command == "群话痨排行榜":
|
if not type:
|
||||||
state["start"] = dt.replace(
|
await rank_cmd.finish(__plugin_meta__.usage)
|
||||||
year=2000, month=1, day=1, hour=0, minute=0, second=0, microsecond=0
|
|
||||||
)
|
dt = get_datetime_now_with_timezone()
|
||||||
state["stop"] = dt
|
|
||||||
elif command == "今日群话痨排行榜":
|
if type == "今日":
|
||||||
state["start"] = dt.replace(hour=0, minute=0, second=0, microsecond=0)
|
state["start"] = dt.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
state["stop"] = dt
|
state["stop"] = dt
|
||||||
elif command == "昨日群话痨排行榜":
|
elif type == "昨日":
|
||||||
state["stop"] = dt.replace(hour=0, minute=0, second=0, microsecond=0)
|
state["stop"] = dt.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
state["start"] = state["stop"] - timedelta(days=1)
|
state["start"] = state["stop"] - timedelta(days=1)
|
||||||
elif command == "前日群话痨排行榜":
|
elif type == "本周":
|
||||||
state["stop"] = dt.replace(
|
|
||||||
hour=0, minute=0, second=0, microsecond=0
|
|
||||||
) - timedelta(days=1)
|
|
||||||
state["start"] = state["stop"] - timedelta(days=1)
|
|
||||||
elif command == "本周群话痨排行榜":
|
|
||||||
state["start"] = dt.replace(
|
state["start"] = dt.replace(
|
||||||
hour=0, minute=0, second=0, microsecond=0
|
hour=0, minute=0, second=0, microsecond=0
|
||||||
) - timedelta(days=dt.weekday())
|
) - timedelta(days=dt.weekday())
|
||||||
state["stop"] = dt
|
state["stop"] = dt
|
||||||
elif command == "上周群话痨排行榜":
|
elif type == "上周":
|
||||||
state["start"] = dt.replace(
|
|
||||||
hour=0, minute=0, second=0, microsecond=0
|
|
||||||
) - timedelta(days=dt.weekday() + 7)
|
|
||||||
state["stop"] = dt.replace(
|
state["stop"] = dt.replace(
|
||||||
hour=0, minute=0, second=0, microsecond=0
|
hour=0, minute=0, second=0, microsecond=0
|
||||||
) - timedelta(days=dt.weekday())
|
) - timedelta(days=dt.weekday())
|
||||||
elif command == "本月群话痨排行榜":
|
state["start"] = state["stop"] - timedelta(days=7)
|
||||||
|
elif type == "本月":
|
||||||
state["start"] = dt.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
state["start"] = dt.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
||||||
state["stop"] = dt
|
state["stop"] = dt
|
||||||
elif command == "年度群话痨排行榜":
|
elif type == "上月":
|
||||||
|
state["stop"] = dt.replace(
|
||||||
|
day=1, hour=0, minute=0, second=0, microsecond=0
|
||||||
|
) - timedelta(microseconds=1)
|
||||||
|
state["start"] = state["stop"].replace(
|
||||||
|
day=1, hour=0, minute=0, second=0, microsecond=0
|
||||||
|
)
|
||||||
|
elif type == "年度":
|
||||||
state["start"] = dt.replace(
|
state["start"] = dt.replace(
|
||||||
month=1, day=1, hour=0, minute=0, second=0, microsecond=0
|
month=1, day=1, hour=0, minute=0, second=0, microsecond=0
|
||||||
)
|
)
|
||||||
state["stop"] = dt
|
state["stop"] = dt
|
||||||
elif command == "历史群话痨排行榜":
|
elif type == "历史":
|
||||||
plaintext = args.extract_plain_text().strip()
|
if time:
|
||||||
match = re.match(r"^(.+?)(?:~(.+))?$", plaintext)
|
plaintext = time
|
||||||
if match:
|
if match := re.match(r"^(.+?)(?:~(.+))?$", plaintext):
|
||||||
start = match.group(1)
|
start = match[1]
|
||||||
stop = match.group(2)
|
stop = match[2]
|
||||||
try:
|
try:
|
||||||
state["start"] = get_datetime_fromisoformat_with_timezone(start)
|
state["start"] = get_datetime_fromisoformat_with_timezone(start)
|
||||||
if stop:
|
if stop:
|
||||||
state["stop"] = get_datetime_fromisoformat_with_timezone(stop)
|
state["stop"] = get_datetime_fromisoformat_with_timezone(stop)
|
||||||
else:
|
else:
|
||||||
# 如果没有指定结束日期,则认为是指查询这一天的数据
|
# 如果没有指定结束日期,则认为是所给日期的当天的词云
|
||||||
state["start"] = state["start"].replace(
|
state["start"] = state["start"].replace(
|
||||||
hour=0, minute=0, second=0, microsecond=0
|
hour=0, minute=0, second=0, microsecond=0
|
||||||
)
|
)
|
||||||
state["stop"] = state["start"] + timedelta(days=1)
|
state["stop"] = state["start"] + timedelta(days=1)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
await matcher.finish("请输入正确的日期,不然我没法理解呢!")
|
await rank_cmd.finish("请输入正确的日期,不然我没法理解呢!")
|
||||||
else:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@ranks.handle()
|
@rank_cmd.got(
|
||||||
async def _private_message(
|
|
||||||
matcher: Matcher,
|
|
||||||
event: Union[V11Event.PrivateMessageEvent, V12Event.PrivateMessageEvent],
|
|
||||||
state: T_State,
|
|
||||||
commands: Tuple[str, ...] = Command(),
|
|
||||||
args: Union[V11Message, V12Message] = CommandArg(),
|
|
||||||
):
|
|
||||||
# TODO:支持私聊的查询
|
|
||||||
await matcher.finish("暂不支持私聊查询,今后可能会添加这一项功能")
|
|
||||||
|
|
||||||
|
|
||||||
@ranks.got(
|
|
||||||
"start",
|
"start",
|
||||||
prompt="请输入你要查询的起始日期(如 2022-01-01)",
|
prompt="请输入你要查询的起始日期(如 2022-01-01)",
|
||||||
parameterless=[Depends(parse_datetime("start"))],
|
parameterless=[Depends(parse_datetime("start"))],
|
||||||
)
|
)
|
||||||
@ranks.got(
|
@rank_cmd.got(
|
||||||
"stop",
|
"stop",
|
||||||
prompt="请输入你要查询的结束日期(如 2022-02-22)",
|
prompt="请输入你要查询的结束日期(如 2022-02-22)",
|
||||||
parameterless=[Depends(parse_datetime("stop"))],
|
parameterless=[Depends(parse_datetime("stop"))],
|
||||||
)
|
)
|
||||||
async def handle_message(
|
async def handle_rank(
|
||||||
matcher: Matcher,
|
bot: Bot,
|
||||||
bot: Union[V11Bot, V12Bot],
|
event: Event,
|
||||||
event: Union[
|
session: Session = Depends(extract_session),
|
||||||
V11Event.GroupMessageEvent,
|
|
||||||
V12Event.GroupMessageEvent,
|
|
||||||
V12Event.ChannelMessageEvent,
|
|
||||||
],
|
|
||||||
stop: datetime = Arg(),
|
|
||||||
start: datetime = Arg(),
|
start: datetime = Arg(),
|
||||||
|
stop: datetime = Arg(),
|
||||||
):
|
):
|
||||||
st = time.time()
|
"""生成词云"""
|
||||||
|
messages = await get_message_records(
|
||||||
if plugin_config.dialectlist_excluded_self:
|
session=session,
|
||||||
bot_id = await bot.call_api("get_login_info")
|
id_type=SessionIdType.GROUP,
|
||||||
plugin_config.dialectlist_excluded_people.append(bot_id["user_id"])
|
include_bot_id=False,
|
||||||
msg_list = await get_message_records(
|
include_bot_type=False,
|
||||||
bot_ids=[str(bot.self_id)],
|
types=["message"], # 排除机器人自己发的消息
|
||||||
platforms=['qq']
|
time_start=start,
|
||||||
if isinstance(event, V11Event.GroupMessageEvent)
|
time_stop=stop,
|
||||||
else [str(bot.platform)],
|
exclude_id1s=plugin_config.excluded_people,
|
||||||
group_ids=[str(event.group_id)]
|
|
||||||
if isinstance(event, (V11Event.GroupMessageEvent, V12Event.GroupMessageEvent))
|
|
||||||
else None,
|
|
||||||
guild_ids=[str(event.guild_id)]
|
|
||||||
if isinstance(event, V12Event.ChannelMessageEvent)
|
|
||||||
else None,
|
|
||||||
exclude_user_ids=plugin_config.dialectlist_excluded_people,
|
|
||||||
time_start=start.astimezone(ZoneInfo("UTC")),
|
|
||||||
time_stop=stop.astimezone(ZoneInfo("UTC")),
|
|
||||||
)
|
)
|
||||||
for i in msg_list:
|
|
||||||
logger.debug(i.plain_text)
|
|
||||||
|
|
||||||
if isinstance(event, V11Event.GroupMessageEvent):
|
rank = got_rank(msg_counter(messages))
|
||||||
processer = V11GroupMsgProcesser(bot=bot, gid=str(event.group_id), msg_list=msg_list) # type: ignore
|
ids = await persist_id2user_id([int(i[0]) for i in rank])
|
||||||
elif isinstance(event, V12Event.GroupMessageEvent):
|
for i in range(len(rank)):
|
||||||
processer = V12GroupMsgProcesser(bot=bot, gid=str(event.group_id), msg_list=msg_list) # type: ignore
|
rank[i][0] = str(ids[i])
|
||||||
elif isinstance(event, V12Event.ChannelMessageEvent):
|
|
||||||
processer = V12GuildMsgProcesser(bot=bot, gid=str(event.guild_id), msg_list=msg_list) # type: ignore
|
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)
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError("没支持呢(())")
|
nicknames.append(None)
|
||||||
|
logger.debug(nicknames)
|
||||||
|
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
|
||||||
|
)
|
||||||
|
string += str_example
|
||||||
|
|
||||||
msg = await processer.get_send_msg() # type: ignore
|
await saa.Text(string).finish(reply=True)
|
||||||
await matcher.send(msg)
|
|
||||||
|
@ -1,18 +1,29 @@
|
|||||||
from typing import Optional, Literal, List
|
from typing import Optional, Literal, List
|
||||||
from nonebot import get_driver
|
from nonebot import get_driver, get_plugin_config
|
||||||
from pydantic import BaseModel, Extra
|
from pydantic import BaseModel, field_validator
|
||||||
|
|
||||||
|
|
||||||
class Config(BaseModel, extra=Extra.ignore):
|
class ScopedConfig(BaseModel):
|
||||||
timezone: Optional[str]
|
font: str = "SimHei" # 字体格式
|
||||||
dialectlist_string_format: str = "第{index}名:\n{nickname},{chatdatanum}条消息\n" # 消息格式
|
get_num: int = 5 # 获取人数数量
|
||||||
dialectlist_get_num: int = 5 # 获取人数数量
|
timezone: Optional[str] = "Asia/Shanghai"
|
||||||
dialectlist_visualization: bool = True # 是否可视化
|
excluded_self: bool = True
|
||||||
dialectlist_visualization_type: Literal["饼图", "圆环图", "柱状图"] = "圆环图" # 可视化方案
|
string_format: str = "第{index}名:\n{nickname},{chatdatanum}条消息\n" # 消息格式
|
||||||
dialectlist_font: str = "SimHei" # 字体格式
|
visualization: bool = True # 是否可视化
|
||||||
dialectlist_excluded_people: List[str] = [] # 排除的人的QQ号
|
excluded_people: List[str] = [] # 排除的人的QQ号
|
||||||
dialectlist_excluded_self: bool = True
|
visualization_type: Literal["饼图", "圆环图", "柱状图"] = "圆环图" # 可视化方案
|
||||||
|
|
||||||
|
@field_validator("get_num")
|
||||||
|
@classmethod
|
||||||
|
def check_priority(cls, v: int) -> int:
|
||||||
|
if v >= 1:
|
||||||
|
return v
|
||||||
|
raise ValueError("表中的人数必须大于一")
|
||||||
|
|
||||||
|
|
||||||
|
class Config(BaseModel):
|
||||||
|
dialectlist: ScopedConfig = ScopedConfig()
|
||||||
|
|
||||||
|
|
||||||
global_config = get_driver().config
|
global_config = get_driver().config
|
||||||
plugin_config = Config(**global_config.dict())
|
plugin_config = get_plugin_config(Config).dialectlist
|
||||||
|
@ -1,294 +0,0 @@
|
|||||||
import abc
|
|
||||||
import pygal
|
|
||||||
import unicodedata
|
|
||||||
import requests
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from typing import List, Dict, Union
|
|
||||||
from pygal.style import Style
|
|
||||||
|
|
||||||
from nonebot import require
|
|
||||||
from nonebot.log import logger
|
|
||||||
from nonebot.params import Arg
|
|
||||||
from nonebot.typing import T_State
|
|
||||||
from nonebot.matcher import Matcher
|
|
||||||
from nonebot.adapters import Bot, Message
|
|
||||||
from nonebot.adapters.onebot import V11Bot, V12Bot, V11Message, V12Message, V11MessageSegment, V12MessageSegment # type: ignore
|
|
||||||
from nonebot.exception import ActionFailed
|
|
||||||
|
|
||||||
try:
|
|
||||||
from zoneinfo import ZoneInfo
|
|
||||||
except ImportError:
|
|
||||||
from backports.zoneinfo import ZoneInfo # type: ignore
|
|
||||||
|
|
||||||
require("nonebot_plugin_chatrecorder")
|
|
||||||
from nonebot_plugin_chatrecorder import get_message_records
|
|
||||||
from nonebot_plugin_chatrecorder.model import MessageRecord
|
|
||||||
|
|
||||||
from .config import plugin_config
|
|
||||||
|
|
||||||
style = Style(font_family=plugin_config.dialectlist_font)
|
|
||||||
|
|
||||||
|
|
||||||
def remove_control_characters(string: str) -> str:
|
|
||||||
"""### 将字符串中的控制符去除
|
|
||||||
|
|
||||||
Args:
|
|
||||||
string (str): 需要去除的字符串
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
(str): 经过处理的字符串
|
|
||||||
"""
|
|
||||||
return "".join(ch for ch in string if unicodedata.category(ch)[0] != "C")
|
|
||||||
|
|
||||||
|
|
||||||
def parse_datetime(key: str):
|
|
||||||
"""解析数字,并将结果存入 state 中"""
|
|
||||||
|
|
||||||
async def _key_parser(
|
|
||||||
matcher: Matcher,
|
|
||||||
state: T_State,
|
|
||||||
input: Union[datetime, Union[V11Message, V12Message]] = 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:
|
|
||||||
"""从 iso8601 格式字符串中获取时间,并包含时区信息"""
|
|
||||||
if plugin_config.timezone:
|
|
||||||
return datetime.fromisoformat(date_string).astimezone(
|
|
||||||
ZoneInfo(plugin_config.timezone)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return datetime.fromisoformat(date_string).astimezone()
|
|
||||||
|
|
||||||
|
|
||||||
def msg_counter(msg_list: List[MessageRecord]) -> Dict[str, int]:
|
|
||||||
"""### 计算每个人的消息量
|
|
||||||
|
|
||||||
Args:
|
|
||||||
msg_list (list[MessageRecord]): 需要处理的消息列表
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
(dict[str,int]): 处理后的消息数量字典,键为用户,值为消息数量
|
|
||||||
"""
|
|
||||||
|
|
||||||
lst: Dict[str, int] = {}
|
|
||||||
msg_len = len(msg_list)
|
|
||||||
logger.info("wow , there are {} msgs to count !!!".format(msg_len))
|
|
||||||
|
|
||||||
for i in msg_list:
|
|
||||||
try:
|
|
||||||
lst[i.user_id] += 1
|
|
||||||
except KeyError:
|
|
||||||
lst[i.user_id] = 1
|
|
||||||
|
|
||||||
logger.debug(lst)
|
|
||||||
|
|
||||||
return lst
|
|
||||||
|
|
||||||
|
|
||||||
def got_rank(msg_dict: Dict[str, int]) -> List[List[Union[str, int]]]:
|
|
||||||
"""### 获得排行榜
|
|
||||||
|
|
||||||
Args:
|
|
||||||
msg_dict (Dict[str,int]): 要处理的字典
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
List[Tuple[str,int]]: 排行榜列表(已排序)
|
|
||||||
"""
|
|
||||||
rank = []
|
|
||||||
while len(rank) < plugin_config.dialectlist_get_num:
|
|
||||||
try:
|
|
||||||
max_key = max(msg_dict.items(), key=lambda x: x[1])
|
|
||||||
rank.append(list(max_key))
|
|
||||||
msg_dict.pop(max_key[0])
|
|
||||||
except ValueError:
|
|
||||||
rank.append(["null", 0])
|
|
||||||
continue
|
|
||||||
|
|
||||||
return rank
|
|
||||||
|
|
||||||
|
|
||||||
class MsgProcesser(abc.ABC):
|
|
||||||
def __init__(self, bot: Bot, gid: str, msg_list: List[MessageRecord]) -> None:
|
|
||||||
if isinstance(bot, Bot):
|
|
||||||
self.bot = bot
|
|
||||||
else:
|
|
||||||
self.bot = None
|
|
||||||
self.gid = gid
|
|
||||||
self.rank = got_rank(msg_counter(msg_list))
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
async def get_nickname_list(self) -> List:
|
|
||||||
"""
|
|
||||||
### 获得昵称
|
|
||||||
#### 抽象原因
|
|
||||||
要对onebot协议不同版本进行适配
|
|
||||||
"""
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_head_portrait_urls(self) -> List:
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
async def get_send_msg(self) -> Message:
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
async def get_msg(self) -> List[Union[str, bytes, None]]:
|
|
||||||
str_msg = await self.render_template_msg()
|
|
||||||
pic_msg = None
|
|
||||||
if plugin_config.dialectlist_visualization:
|
|
||||||
try:
|
|
||||||
pic_msg = await self.render_template_pic()
|
|
||||||
except OSError:
|
|
||||||
plugin_config.dialectlist_visualization = False
|
|
||||||
str_msg += "\n\n无法发送可视化图片,请检查是否安装GTK+,详细安装教程可见github\nhttps://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer \n若不想安装这个软件,再次使用这个指令不会显示这个提示"
|
|
||||||
return [str_msg, pic_msg]
|
|
||||||
|
|
||||||
async def render_template_msg(self) -> str:
|
|
||||||
"""渲染文字"""
|
|
||||||
string: str = ""
|
|
||||||
rank: List = self.rank
|
|
||||||
nicknames: List = await self.get_nickname_list()
|
|
||||||
for i in range(len(rank)):
|
|
||||||
index = i + 1
|
|
||||||
nickname, chatdatanum = nicknames[i], rank[i][1]
|
|
||||||
str_example = plugin_config.dialectlist_string_format.format(
|
|
||||||
index=index, nickname=nickname, chatdatanum=chatdatanum
|
|
||||||
)
|
|
||||||
string += str_example
|
|
||||||
|
|
||||||
return string
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
class V11GroupMsgProcesser(MsgProcesser):
|
|
||||||
def __init__(self, bot: V11Bot, gid: str, msg_list: List[MessageRecord]) -> None:
|
|
||||||
super().__init__(bot, gid, msg_list)
|
|
||||||
self.bot = bot
|
|
||||||
|
|
||||||
async def get_nickname_list(self) -> List:
|
|
||||||
nicknames = []
|
|
||||||
for i in range(len(self.rank)):
|
|
||||||
try:
|
|
||||||
member_info = await self.bot.get_group_member_info(
|
|
||||||
group_id=int(self.gid), user_id=int(self.rank[i][0]), no_cache=True
|
|
||||||
)
|
|
||||||
nickname=(
|
|
||||||
member_info["nickname"]
|
|
||||||
if not member_info["card"]
|
|
||||||
else member_info["card"]
|
|
||||||
)
|
|
||||||
nicknames.append(remove_control_characters(nickname))
|
|
||||||
except (ActionFailed,ValueError) as e:
|
|
||||||
nicknames.append("{}这家伙不在群里了".format(self.rank[i][0]))
|
|
||||||
|
|
||||||
return nicknames
|
|
||||||
|
|
||||||
def get_head_portrait_urls(self) -> List:
|
|
||||||
self.portrait_urls = [
|
|
||||||
"http://q2.qlogo.cn/headimg_dl?dst_uin={}&spec=640".format(i[0])
|
|
||||||
for i in self.rank
|
|
||||||
]
|
|
||||||
return self.portrait_urls
|
|
||||||
|
|
||||||
async def get_send_msg(self) -> V11Message:
|
|
||||||
msgs: List = await self.get_msg()
|
|
||||||
msg = V11Message()
|
|
||||||
msg += V11MessageSegment.text(msgs[0]) # type: ignore
|
|
||||||
msg += V11MessageSegment.image(msgs[1]) # type: ignore
|
|
||||||
return msg
|
|
||||||
|
|
||||||
|
|
||||||
class V12MsgProcesser(MsgProcesser):
|
|
||||||
def __init__(self, bot: V12Bot, gid: str, msg_list: List[MessageRecord]) -> None:
|
|
||||||
super().__init__(bot, gid, msg_list)
|
|
||||||
self.bot = bot
|
|
||||||
|
|
||||||
async def get_send_msg(self) -> V12Message:
|
|
||||||
msgs: List = await self.get_msg()
|
|
||||||
msg = V12Message()
|
|
||||||
msg += V12MessageSegment.text(msgs[0]) # type: ignore
|
|
||||||
msg += V12MessageSegment.image(msgs[1]) # type: ignore
|
|
||||||
return msg
|
|
||||||
|
|
||||||
def get_head_portrait_urls(self) -> List:
|
|
||||||
return super().get_head_portrait_urls()
|
|
||||||
|
|
||||||
|
|
||||||
class V12GroupMsgProcesser(V12MsgProcesser):
|
|
||||||
def __init__(self, bot: V12Bot, gid: str, msg_list: List[MessageRecord]) -> None:
|
|
||||||
super().__init__(bot, gid, msg_list)
|
|
||||||
|
|
||||||
async def get_nickname_list(self) -> List:
|
|
||||||
nicknames = []
|
|
||||||
for i in range(len(self.rank)):
|
|
||||||
try:
|
|
||||||
member_info = await self.bot.get_group_member_info(
|
|
||||||
group_id=str(self.gid), user_id=str(self.rank[i][0]), no_cache=True
|
|
||||||
)
|
|
||||||
nickname=(
|
|
||||||
member_info["user_displayname"]
|
|
||||||
if member_info["user_displayname"]
|
|
||||||
else member_info["user_name"]
|
|
||||||
)
|
|
||||||
nicknames.append(remove_control_characters(nickname))
|
|
||||||
except ActionFailed as e:
|
|
||||||
nicknames.append("{}这家伙不在群里了".format(self.rank[i][0]))
|
|
||||||
return nicknames
|
|
||||||
|
|
||||||
|
|
||||||
class V12GuildMsgProcesser(V12MsgProcesser):
|
|
||||||
def __init__(self, bot: V12Bot, gid: str, msg_list: List[MessageRecord]) -> None:
|
|
||||||
super().__init__(bot, gid, msg_list)
|
|
||||||
|
|
||||||
async def get_nickname_list(self) -> List:
|
|
||||||
nicknames = []
|
|
||||||
for i in range(len(self.rank)):
|
|
||||||
try:
|
|
||||||
member_info = await self.bot.get_guild_member_info(
|
|
||||||
guild_id=str(self.gid), user_id=str(self.rank[i][0]), no_cache=True
|
|
||||||
)
|
|
||||||
nickname=(
|
|
||||||
member_info["user_displayname"]
|
|
||||||
if member_info["user_displayname"]
|
|
||||||
else member_info["user_name"]
|
|
||||||
)
|
|
||||||
nicknames.append(remove_control_characters(nickname))
|
|
||||||
except ActionFailed as e:
|
|
||||||
nicknames.append("{}这家伙不在群里了".format(self.rank[i][0]))
|
|
||||||
return nicknames
|
|
0
nonebot_plugin_dialectlist/usage.md
Normal file
0
nonebot_plugin_dialectlist/usage.md
Normal file
442
nonebot_plugin_dialectlist/utils.py
Normal file
442
nonebot_plugin_dialectlist/utils.py
Normal file
@ -0,0 +1,442 @@
|
|||||||
|
import contextlib
|
||||||
|
from datetime import datetime, time, tzinfo
|
||||||
|
from typing import Optional, Dict, List, Union
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
from sqlalchemy import or_, select
|
||||||
|
from sqlalchemy.sql import ColumnElement
|
||||||
|
|
||||||
|
from nonebot.log import logger
|
||||||
|
from nonebot.params import Depends
|
||||||
|
from nonebot.compat import model_dump
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
|
||||||
|
# from nonebot.permission import SUPERUSER
|
||||||
|
|
||||||
|
from nonebot_plugin_orm import get_session
|
||||||
|
from nonebot_plugin_saa import PlatformTarget, get_target
|
||||||
|
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_apscheduler import scheduler
|
||||||
|
from nonebot_plugin_chatrecorder import MessageRecord
|
||||||
|
|
||||||
|
|
||||||
|
from .config import plugin_config
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
# 暂时不做考虑
|
||||||
|
# def admin_permission():
|
||||||
|
# permission = SUPERUSER
|
||||||
|
# with contextlib.suppress(ImportError):
|
||||||
|
# from nonebot.adapters.onebot.v11.permission import GROUP_ADMIN, GROUP_OWNER
|
||||||
|
|
||||||
|
# permission = permission | GROUP_ADMIN | GROUP_OWNER
|
||||||
|
|
||||||
|
# return permission
|
||||||
|
|
||||||
|
|
||||||
|
async def ensure_group(matcher: Matcher, session: Session = Depends(extract_session)):
|
||||||
|
"""确保在群组中使用"""
|
||||||
|
if session.level not in [SessionLevel.LEVEL2, SessionLevel.LEVEL3]:
|
||||||
|
await matcher.finish("请在群组中使用!")
|
||||||
|
|
||||||
|
|
||||||
|
async def persist_id2user_id(ids: List) -> List[str]:
|
||||||
|
whereclause: List[ColumnElement[bool]] = []
|
||||||
|
whereclause.append(or_(*[SessionModel.id == id for id in ids]))
|
||||||
|
statement = (
|
||||||
|
select(SessionModel).where(*whereclause)
|
||||||
|
# .join(SessionModel, SessionModel.id == MessageRecord.session_persist_id)
|
||||||
|
)
|
||||||
|
async with get_session() as db_session:
|
||||||
|
records = (await db_session.scalars(statement)).all()
|
||||||
|
return [i.id1 for i in records]
|
||||||
|
|
||||||
|
|
||||||
|
def msg_counter(msg_list: List[MessageRecord]) -> Dict[str, int]:
|
||||||
|
"""### 计算每个人的消息量
|
||||||
|
|
||||||
|
Args:
|
||||||
|
msg_list (list[MessageRecord]): 需要处理的消息列表
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(dict[str,int]): 处理后的消息数量字典,键为用户,值为消息数量
|
||||||
|
"""
|
||||||
|
|
||||||
|
lst: Dict[str, int] = {}
|
||||||
|
msg_len = len(msg_list)
|
||||||
|
logger.info("wow , there are {} msgs to count !!!".format(msg_len))
|
||||||
|
|
||||||
|
for i in msg_list:
|
||||||
|
logger.debug(i.session_persist_id)
|
||||||
|
try:
|
||||||
|
lst[str(i.session_persist_id)] += 1
|
||||||
|
except KeyError:
|
||||||
|
lst[str(i.session_persist_id)] = 1
|
||||||
|
|
||||||
|
logger.debug(lst)
|
||||||
|
|
||||||
|
return lst
|
||||||
|
|
||||||
|
|
||||||
|
def got_rank(msg_dict: Dict[str, int]) -> List[List[Union[str, int]]]:
|
||||||
|
"""### 获得排行榜
|
||||||
|
|
||||||
|
Args:
|
||||||
|
msg_dict (Dict[str,int]): 要处理的字典
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[Tuple[str,int]]: 排行榜列表(已排序)
|
||||||
|
"""
|
||||||
|
rank = []
|
||||||
|
while len(rank) < plugin_config.get_num:
|
||||||
|
try:
|
||||||
|
max_key = max(msg_dict.items(), key=lambda x: x[1])
|
||||||
|
rank.append(list(max_key))
|
||||||
|
msg_dict.pop(max_key[0])
|
||||||
|
except ValueError:
|
||||||
|
break
|
||||||
|
|
||||||
|
return rank
|
||||||
|
|
||||||
|
|
||||||
|
# import abc
|
||||||
|
# import pygal
|
||||||
|
# import unicodedata
|
||||||
|
# import requests
|
||||||
|
# from datetime import datetime
|
||||||
|
|
||||||
|
# from typing import List, Dict, Union
|
||||||
|
# from pygal.style import Style
|
||||||
|
|
||||||
|
# from nonebot import require
|
||||||
|
# from nonebot.log import logger
|
||||||
|
# from nonebot.params import Arg
|
||||||
|
# from nonebot.typing import T_State
|
||||||
|
# from nonebot.matcher import Matcher
|
||||||
|
# from nonebot.adapters import Bot, Message
|
||||||
|
# from nonebot.adapters.onebot import V11Bot, V12Bot, V11Message, V12Message, V11MessageSegment, V12MessageSegment # type: ignore
|
||||||
|
# from nonebot.exception import ActionFailed
|
||||||
|
|
||||||
|
# try:
|
||||||
|
# from zoneinfo import ZoneInfo
|
||||||
|
# except ImportError:
|
||||||
|
# from backports.zoneinfo import ZoneInfo # type: ignore
|
||||||
|
|
||||||
|
# require("nonebot_plugin_chatrecorder")
|
||||||
|
# from nonebot_plugin_chatrecorder import get_message_records
|
||||||
|
# from nonebot_plugin_chatrecorder.model import MessageRecord
|
||||||
|
|
||||||
|
# from .config import plugin_config
|
||||||
|
|
||||||
|
# style = Style(font_family=plugin_config.dialectlist_font)
|
||||||
|
|
||||||
|
|
||||||
|
# def remove_control_characters(string: str) -> str:
|
||||||
|
# """### 将字符串中的控制符去除
|
||||||
|
|
||||||
|
# Args:
|
||||||
|
# string (str): 需要去除的字符串
|
||||||
|
|
||||||
|
# Returns:
|
||||||
|
# (str): 经过处理的字符串
|
||||||
|
# """
|
||||||
|
# return "".join(ch for ch in string if unicodedata.category(ch)[0] != "C")
|
||||||
|
|
||||||
|
|
||||||
|
# def parse_datetime(key: str):
|
||||||
|
# """解析数字,并将结果存入 state 中"""
|
||||||
|
|
||||||
|
# async def _key_parser(
|
||||||
|
# matcher: Matcher,
|
||||||
|
# state: T_State,
|
||||||
|
# input: Union[datetime, Union[V11Message, V12Message]] = 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:
|
||||||
|
# """从 iso8601 格式字符串中获取时间,并包含时区信息"""
|
||||||
|
# if plugin_config.timezone:
|
||||||
|
# return datetime.fromisoformat(date_string).astimezone(
|
||||||
|
# ZoneInfo(plugin_config.timezone)
|
||||||
|
# )
|
||||||
|
# else:
|
||||||
|
# return datetime.fromisoformat(date_string).astimezone()
|
||||||
|
|
||||||
|
|
||||||
|
# def msg_counter(msg_list: List[MessageRecord]) -> Dict[str, int]:
|
||||||
|
# """### 计算每个人的消息量
|
||||||
|
|
||||||
|
# Args:
|
||||||
|
# msg_list (list[MessageRecord]): 需要处理的消息列表
|
||||||
|
|
||||||
|
# Returns:
|
||||||
|
# (dict[str,int]): 处理后的消息数量字典,键为用户,值为消息数量
|
||||||
|
# """
|
||||||
|
|
||||||
|
# lst: Dict[str, int] = {}
|
||||||
|
# msg_len = len(msg_list)
|
||||||
|
# logger.info("wow , there are {} msgs to count !!!".format(msg_len))
|
||||||
|
|
||||||
|
# for i in msg_list:
|
||||||
|
# try:
|
||||||
|
# lst[i.user_id] += 1
|
||||||
|
# except KeyError:
|
||||||
|
# lst[i.user_id] = 1
|
||||||
|
|
||||||
|
# logger.debug(lst)
|
||||||
|
|
||||||
|
# return lst
|
||||||
|
|
||||||
|
|
||||||
|
# def got_rank(msg_dict: Dict[str, int]) -> List[List[Union[str, int]]]:
|
||||||
|
# """### 获得排行榜
|
||||||
|
|
||||||
|
# Args:
|
||||||
|
# msg_dict (Dict[str,int]): 要处理的字典
|
||||||
|
|
||||||
|
# Returns:
|
||||||
|
# List[Tuple[str,int]]: 排行榜列表(已排序)
|
||||||
|
# """
|
||||||
|
# rank = []
|
||||||
|
# while len(rank) < plugin_config.dialectlist_get_num:
|
||||||
|
# try:
|
||||||
|
# max_key = max(msg_dict.items(), key=lambda x: x[1])
|
||||||
|
# rank.append(list(max_key))
|
||||||
|
# msg_dict.pop(max_key[0])
|
||||||
|
# except ValueError:
|
||||||
|
# rank.append(["null", 0])
|
||||||
|
# continue
|
||||||
|
|
||||||
|
# return rank
|
||||||
|
|
||||||
|
|
||||||
|
# class MsgProcesser(abc.ABC):
|
||||||
|
# def __init__(self, bot: Bot, gid: str, msg_list: List[MessageRecord]) -> None:
|
||||||
|
# if isinstance(bot, Bot):
|
||||||
|
# self.bot = bot
|
||||||
|
# else:
|
||||||
|
# self.bot = None
|
||||||
|
# self.gid = gid
|
||||||
|
# self.rank = got_rank(msg_counter(msg_list))
|
||||||
|
|
||||||
|
# @abc.abstractmethod
|
||||||
|
# async def get_nickname_list(self) -> List:
|
||||||
|
# """
|
||||||
|
# ### 获得昵称
|
||||||
|
# #### 抽象原因
|
||||||
|
# 要对onebot协议不同版本进行适配
|
||||||
|
# """
|
||||||
|
# raise NotImplementedError
|
||||||
|
|
||||||
|
# @abc.abstractmethod
|
||||||
|
# def get_head_portrait_urls(self) -> List:
|
||||||
|
# raise NotImplementedError
|
||||||
|
|
||||||
|
# @abc.abstractmethod
|
||||||
|
# async def get_send_msg(self) -> Message:
|
||||||
|
# raise NotImplementedError
|
||||||
|
|
||||||
|
# async def get_msg(self) -> List[Union[str, bytes, None]]:
|
||||||
|
# str_msg = await self.render_template_msg()
|
||||||
|
# pic_msg = None
|
||||||
|
# if plugin_config.dialectlist_visualization:
|
||||||
|
# try:
|
||||||
|
# pic_msg = await self.render_template_pic()
|
||||||
|
# except OSError:
|
||||||
|
# plugin_config.dialectlist_visualization = False
|
||||||
|
# str_msg += "\n\n无法发送可视化图片,请检查是否安装GTK+,详细安装教程可见github\nhttps://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer \n若不想安装这个软件,再次使用这个指令不会显示这个提示"
|
||||||
|
# return [str_msg, pic_msg]
|
||||||
|
|
||||||
|
# async def render_template_msg(self) -> str:
|
||||||
|
# """渲染文字"""
|
||||||
|
# string: str = ""
|
||||||
|
# rank: List = self.rank
|
||||||
|
# nicknames: List = await self.get_nickname_list()
|
||||||
|
# for i in range(len(rank)):
|
||||||
|
# index = i + 1
|
||||||
|
# nickname, chatdatanum = nicknames[i], rank[i][1]
|
||||||
|
# str_example = plugin_config.dialectlist_string_format.format(
|
||||||
|
# index=index, nickname=nickname, chatdatanum=chatdatanum
|
||||||
|
# )
|
||||||
|
# string += str_example
|
||||||
|
|
||||||
|
# return string
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
# class V11GroupMsgProcesser(MsgProcesser):
|
||||||
|
# def __init__(self, bot: V11Bot, gid: str, msg_list: List[MessageRecord]) -> None:
|
||||||
|
# super().__init__(bot, gid, msg_list)
|
||||||
|
# self.bot = bot
|
||||||
|
|
||||||
|
# async def get_nickname_list(self) -> List:
|
||||||
|
# nicknames = []
|
||||||
|
# for i in range(len(self.rank)):
|
||||||
|
# try:
|
||||||
|
# member_info = await self.bot.get_group_member_info(
|
||||||
|
# group_id=int(self.gid), user_id=int(self.rank[i][0]), no_cache=True
|
||||||
|
# )
|
||||||
|
# nickname=(
|
||||||
|
# member_info["nickname"]
|
||||||
|
# if not member_info["card"]
|
||||||
|
# else member_info["card"]
|
||||||
|
# )
|
||||||
|
# nicknames.append(remove_control_characters(nickname))
|
||||||
|
# except (ActionFailed,ValueError) as e:
|
||||||
|
# nicknames.append("{}这家伙不在群里了".format(self.rank[i][0]))
|
||||||
|
|
||||||
|
# return nicknames
|
||||||
|
|
||||||
|
# def get_head_portrait_urls(self) -> List:
|
||||||
|
# self.portrait_urls = [
|
||||||
|
# "http://q2.qlogo.cn/headimg_dl?dst_uin={}&spec=640".format(i[0])
|
||||||
|
# for i in self.rank
|
||||||
|
# ]
|
||||||
|
# return self.portrait_urls
|
||||||
|
|
||||||
|
# async def get_send_msg(self) -> V11Message:
|
||||||
|
# msgs: List = await self.get_msg()
|
||||||
|
# msg = V11Message()
|
||||||
|
# msg += V11MessageSegment.text(msgs[0]) # type: ignore
|
||||||
|
# msg += V11MessageSegment.image(msgs[1]) # type: ignore
|
||||||
|
# return msg
|
||||||
|
|
||||||
|
|
||||||
|
# class V12MsgProcesser(MsgProcesser):
|
||||||
|
# def __init__(self, bot: V12Bot, gid: str, msg_list: List[MessageRecord]) -> None:
|
||||||
|
# super().__init__(bot, gid, msg_list)
|
||||||
|
# self.bot = bot
|
||||||
|
|
||||||
|
# async def get_send_msg(self) -> V12Message:
|
||||||
|
# msgs: List = await self.get_msg()
|
||||||
|
# msg = V12Message()
|
||||||
|
# msg += V12MessageSegment.text(msgs[0]) # type: ignore
|
||||||
|
# msg += V12MessageSegment.image(msgs[1]) # type: ignore
|
||||||
|
# return msg
|
||||||
|
|
||||||
|
# def get_head_portrait_urls(self) -> List:
|
||||||
|
# return super().get_head_portrait_urls()
|
||||||
|
|
||||||
|
|
||||||
|
# class V12GroupMsgProcesser(V12MsgProcesser):
|
||||||
|
# def __init__(self, bot: V12Bot, gid: str, msg_list: List[MessageRecord]) -> None:
|
||||||
|
# super().__init__(bot, gid, msg_list)
|
||||||
|
|
||||||
|
# async def get_nickname_list(self) -> List:
|
||||||
|
# nicknames = []
|
||||||
|
# for i in range(len(self.rank)):
|
||||||
|
# try:
|
||||||
|
# member_info = await self.bot.get_group_member_info(
|
||||||
|
# group_id=str(self.gid), user_id=str(self.rank[i][0]), no_cache=True
|
||||||
|
# )
|
||||||
|
# nickname=(
|
||||||
|
# member_info["user_displayname"]
|
||||||
|
# if member_info["user_displayname"]
|
||||||
|
# else member_info["user_name"]
|
||||||
|
# )
|
||||||
|
# nicknames.append(remove_control_characters(nickname))
|
||||||
|
# except ActionFailed as e:
|
||||||
|
# nicknames.append("{}这家伙不在群里了".format(self.rank[i][0]))
|
||||||
|
# return nicknames
|
||||||
|
|
||||||
|
|
||||||
|
# class V12GuildMsgProcesser(V12MsgProcesser):
|
||||||
|
# def __init__(self, bot: V12Bot, gid: str, msg_list: List[MessageRecord]) -> None:
|
||||||
|
# super().__init__(bot, gid, msg_list)
|
||||||
|
|
||||||
|
# async def get_nickname_list(self) -> List:
|
||||||
|
# nicknames = []
|
||||||
|
# for i in range(len(self.rank)):
|
||||||
|
# try:
|
||||||
|
# member_info = await self.bot.get_guild_member_info(
|
||||||
|
# guild_id=str(self.gid), user_id=str(self.rank[i][0]), no_cache=True
|
||||||
|
# )
|
||||||
|
# nickname=(
|
||||||
|
# member_info["user_displayname"]
|
||||||
|
# if member_info["user_displayname"]
|
||||||
|
# else member_info["user_name"]
|
||||||
|
# )
|
||||||
|
# nicknames.append(remove_control_characters(nickname))
|
||||||
|
# except ActionFailed as e:
|
||||||
|
# nicknames.append("{}这家伙不在群里了".format(self.rank[i][0]))
|
||||||
|
# return nicknames
|
316
pdm.lock
316
pdm.lock
@ -2,10 +2,10 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
groups = ["default"]
|
groups = ["default", "dev"]
|
||||||
strategy = ["cross_platform", "inherit_metadata"]
|
strategy = ["cross_platform", "inherit_metadata"]
|
||||||
lock_version = "4.4.1"
|
lock_version = "4.4.1"
|
||||||
content_hash = "sha256:24ead5cb6a13a6971197f92131e83f11ae3f8897fe5d7133ced7fa0533258ae4"
|
content_hash = "sha256:8ea64a585f788e2d455dd3c08f7252ac05328ad42e8d010eb357ddc1aed96869"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alembic"
|
name = "alembic"
|
||||||
@ -51,6 +51,64 @@ files = [
|
|||||||
{file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"},
|
{file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "apscheduler"
|
||||||
|
version = "3.10.4"
|
||||||
|
requires_python = ">=3.6"
|
||||||
|
summary = "In-process task scheduler with Cron-like capabilities"
|
||||||
|
groups = ["default"]
|
||||||
|
dependencies = [
|
||||||
|
"pytz",
|
||||||
|
"six>=1.4.0",
|
||||||
|
"tzlocal!=3.*,>=2.0",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "APScheduler-3.10.4-py3-none-any.whl", hash = "sha256:fb91e8a768632a4756a585f79ec834e0e27aad5860bac7eaa523d9ccefd87661"},
|
||||||
|
{file = "APScheduler-3.10.4.tar.gz", hash = "sha256:e6df071b27d9be898e486bc7940a7be50b4af2e9da7c08f0744a96d4bd4cef4a"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arclet-alconna"
|
||||||
|
version = "1.8.15"
|
||||||
|
requires_python = ">=3.8"
|
||||||
|
summary = "A High-performance, Generality, Humane Command Line Arguments Parser Library."
|
||||||
|
groups = ["default"]
|
||||||
|
dependencies = [
|
||||||
|
"nepattern<1.0.0,>=0.7.3",
|
||||||
|
"tarina>=0.5.0",
|
||||||
|
"typing-extensions>=4.5.0",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "arclet_alconna-1.8.15-py3-none-any.whl", hash = "sha256:9cc010e42f00a5201439318df3b2000234dce27fdc90d26813c3a295125e54e8"},
|
||||||
|
{file = "arclet_alconna-1.8.15.tar.gz", hash = "sha256:713a57bdfed3c3959600384e46358154ce33eec012615554beb5634d436507bc"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arclet-alconna-tools"
|
||||||
|
version = "0.7.6"
|
||||||
|
requires_python = ">=3.8"
|
||||||
|
summary = "Builtin Tools for Alconna"
|
||||||
|
groups = ["default"]
|
||||||
|
dependencies = [
|
||||||
|
"arclet-alconna>=1.8.15",
|
||||||
|
"nepattern<1.0.0,>=0.7.3",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "arclet_alconna_tools-0.7.6-py3-none-any.whl", hash = "sha256:fdd1cb900603ce6bb00295bf7bf7f60dfdb764f0614abe248cdcb754e5149edd"},
|
||||||
|
{file = "arclet_alconna_tools-0.7.6.tar.gz", hash = "sha256:7cb7dc54c1c2198529c63227739423401051b8489374f1a7a3efa0c4e70b2a22"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cachetools"
|
||||||
|
version = "5.3.3"
|
||||||
|
requires_python = ">=3.7"
|
||||||
|
summary = "Extensible memoizing collections and decorators"
|
||||||
|
groups = ["default"]
|
||||||
|
files = [
|
||||||
|
{file = "cachetools-5.3.3-py3-none-any.whl", hash = "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945"},
|
||||||
|
{file = "cachetools-5.3.3.tar.gz", hash = "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "certifi"
|
name = "certifi"
|
||||||
version = "2024.6.2"
|
version = "2024.6.2"
|
||||||
@ -170,6 +228,20 @@ files = [
|
|||||||
{file = "email_validator-2.1.1.tar.gz", hash = "sha256:200a70680ba08904be6d1eef729205cc0d687634399a5924d842533efb824b84"},
|
{file = "email_validator-2.1.1.tar.gz", hash = "sha256:200a70680ba08904be6d1eef729205cc0d687634399a5924d842533efb824b84"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "emoji"
|
||||||
|
version = "2.12.1"
|
||||||
|
requires_python = ">=3.7"
|
||||||
|
summary = "Emoji for Python"
|
||||||
|
groups = ["default"]
|
||||||
|
dependencies = [
|
||||||
|
"typing-extensions>=4.7.0",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "emoji-2.12.1-py3-none-any.whl", hash = "sha256:a00d62173bdadc2510967a381810101624a2f0986145b8da0cffa42e29430235"},
|
||||||
|
{file = "emoji-2.12.1.tar.gz", hash = "sha256:4aa0488817691aa58d83764b6c209f8a27c0b3ab3f89d1b8dceca1a62e4973eb"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "exceptiongroup"
|
name = "exceptiongroup"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
@ -220,6 +292,16 @@ files = [
|
|||||||
{file = "fastapi_cli-0.0.4.tar.gz", hash = "sha256:e2e9ffaffc1f7767f488d6da34b6f5a377751c996f397902eb6abb99a67bde32"},
|
{file = "fastapi_cli-0.0.4.tar.gz", hash = "sha256:e2e9ffaffc1f7767f488d6da34b6f5a377751c996f397902eb6abb99a67bde32"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "filetype"
|
||||||
|
version = "1.2.0"
|
||||||
|
summary = "Infer file type and MIME type of any file/buffer. No external dependencies."
|
||||||
|
groups = ["default"]
|
||||||
|
files = [
|
||||||
|
{file = "filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25"},
|
||||||
|
{file = "filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "greenlet"
|
name = "greenlet"
|
||||||
version = "3.0.3"
|
version = "3.0.3"
|
||||||
@ -534,6 +616,72 @@ files = [
|
|||||||
{file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"},
|
{file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nepattern"
|
||||||
|
version = "0.7.4"
|
||||||
|
requires_python = ">=3.8"
|
||||||
|
summary = "a complex pattern, support typing"
|
||||||
|
groups = ["default"]
|
||||||
|
dependencies = [
|
||||||
|
"tarina>=0.5.1",
|
||||||
|
"typing-extensions>=4.5.0",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "nepattern-0.7.4-py3-none-any.whl", hash = "sha256:ad7287ee2ff46f010b8c758bf9ed8fd8141aa1afce29c5d5a4f94cc85d277e6e"},
|
||||||
|
{file = "nepattern-0.7.4.tar.gz", hash = "sha256:255a042b45e9d2b04f3c2d73b81912c6b856fae1a10a6e4df30b08ed892d2f9c"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nonebot-plugin-alconna"
|
||||||
|
version = "0.46.6"
|
||||||
|
requires_python = ">=3.9"
|
||||||
|
summary = "Alconna Adapter for Nonebot"
|
||||||
|
groups = ["default"]
|
||||||
|
dependencies = [
|
||||||
|
"arclet-alconna-tools>=0.7.6",
|
||||||
|
"arclet-alconna>=1.8.15",
|
||||||
|
"importlib-metadata>=4.13.0",
|
||||||
|
"nepattern>=0.7.4",
|
||||||
|
"nonebot-plugin-waiter>=0.6.0",
|
||||||
|
"nonebot2>=2.3.0",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "nonebot_plugin_alconna-0.46.6-py3-none-any.whl", hash = "sha256:1fc6ccd47b589b7edc342b241e76a877c36328f85a2f97c120b96d23e16fbbb7"},
|
||||||
|
{file = "nonebot_plugin_alconna-0.46.6.tar.gz", hash = "sha256:f0161aa7ca055b74b4a23c828def6f77942ab852a0e22ae477520b8dd0ef03a9"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nonebot-plugin-apscheduler"
|
||||||
|
version = "0.4.0"
|
||||||
|
requires_python = ">=3.8,<4.0"
|
||||||
|
summary = "APScheduler Support for NoneBot2"
|
||||||
|
groups = ["default"]
|
||||||
|
dependencies = [
|
||||||
|
"apscheduler<4.0.0,>=3.7.0",
|
||||||
|
"nonebot2<3.0.0,>=2.2.0",
|
||||||
|
"pydantic!=2.5.0,!=2.5.1,<3.0.0,>=1.10.0",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "nonebot_plugin_apscheduler-0.4.0-py3-none-any.whl", hash = "sha256:f01bb418a5ecf9f04dcadbbc2ff5ba565a48177eb0a758c8c46b13048ac5680c"},
|
||||||
|
{file = "nonebot_plugin_apscheduler-0.4.0.tar.gz", hash = "sha256:ba91e68809a38e6dbe28906366d47f37f754ded360944b938cd5ac62029a0eb6"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nonebot-plugin-cesaa"
|
||||||
|
version = "0.4.0"
|
||||||
|
requires_python = ">=3.8,<4.0"
|
||||||
|
summary = "为 chatrecorder 添加 send-anything-anywhere 的 PlatformTarget 支持"
|
||||||
|
groups = ["default"]
|
||||||
|
dependencies = [
|
||||||
|
"nonebot-plugin-chatrecorder<1.0.0,>=0.6.0",
|
||||||
|
"nonebot-plugin-send-anything-anywhere<0.7.0,>=0.6.0",
|
||||||
|
"nonebot2<3.0.0,>=2.2.0",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "nonebot_plugin_cesaa-0.4.0-py3-none-any.whl", hash = "sha256:4ae34a7d5f023f614f3d3a7207e35f706ae964a203aa582b59f3e0b530a69360"},
|
||||||
|
{file = "nonebot_plugin_cesaa-0.4.0.tar.gz", hash = "sha256:572a5232262a8d3660a00a32f82041f791587e588046d14b0780fc7d908f1263"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nonebot-plugin-chatrecorder"
|
name = "nonebot-plugin-chatrecorder"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
@ -588,6 +736,24 @@ files = [
|
|||||||
{file = "nonebot_plugin_orm-0.7.3.tar.gz", hash = "sha256:cbb573598d0ecef2d0e75b5bdebd05297c68a2b368029a8763660f2a45381a2c"},
|
{file = "nonebot_plugin_orm-0.7.3.tar.gz", hash = "sha256:cbb573598d0ecef2d0e75b5bdebd05297c68a2b368029a8763660f2a45381a2c"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nonebot-plugin-send-anything-anywhere"
|
||||||
|
version = "0.6.1"
|
||||||
|
requires_python = "<4.0,>=3.8"
|
||||||
|
summary = "An adaptor for nonebot2 adaptors"
|
||||||
|
groups = ["default"]
|
||||||
|
dependencies = [
|
||||||
|
"anyio<5.0.0,>=3.3.0",
|
||||||
|
"filetype<2.0.0,>=1.2.0",
|
||||||
|
"nonebot2<3.0.0,>=2.0.0",
|
||||||
|
"pydantic!=2.5.0,!=2.5.1,<3.0.0,>=1.10.0",
|
||||||
|
"strenum<0.5.0,>=0.4.8",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "nonebot_plugin_send_anything_anywhere-0.6.1-py3-none-any.whl", hash = "sha256:d1ac0df520f950b61ff27d3abda39c4bb2023797f3b7df2a23517ad53f3a7f29"},
|
||||||
|
{file = "nonebot_plugin_send_anything_anywhere-0.6.1.tar.gz", hash = "sha256:89a695c5e356a423b8641f79082353b50ee431585988de2c2ae77f8ea00ac3e9"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nonebot-plugin-session"
|
name = "nonebot-plugin-session"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@ -619,6 +785,38 @@ files = [
|
|||||||
{file = "nonebot_plugin_session_orm-0.2.0.tar.gz", hash = "sha256:420e210898a3f348cebbb4ea0816bab66f3299c7b0c01e929a01967d60cc438c"},
|
{file = "nonebot_plugin_session_orm-0.2.0.tar.gz", hash = "sha256:420e210898a3f348cebbb4ea0816bab66f3299c7b0c01e929a01967d60cc438c"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nonebot-plugin-userinfo"
|
||||||
|
version = "0.2.4"
|
||||||
|
requires_python = "<4.0,>=3.8"
|
||||||
|
summary = "Nonebot2 用户信息获取插件"
|
||||||
|
groups = ["default"]
|
||||||
|
dependencies = [
|
||||||
|
"cachetools<6.0.0,>=5.0.0",
|
||||||
|
"emoji<3.0.0,>=2.0.0",
|
||||||
|
"httpx<1.0.0,>=0.20.0",
|
||||||
|
"nonebot2<3.0.0,>=2.0.0",
|
||||||
|
"strenum<0.5.0,>=0.4.8",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "nonebot_plugin_userinfo-0.2.4-py3-none-any.whl", hash = "sha256:f08dac58759b859f8bf1d1c17e96cdcee92b10613631a430405364a40181f9e4"},
|
||||||
|
{file = "nonebot_plugin_userinfo-0.2.4.tar.gz", hash = "sha256:1d49ff00ce38c856be4388fc2a954656f07cc529ce38ef9593e3a0ea40f26b6a"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nonebot-plugin-waiter"
|
||||||
|
version = "0.6.2"
|
||||||
|
requires_python = ">=3.9"
|
||||||
|
summary = "An alternative for got-and-reject in Nonebot"
|
||||||
|
groups = ["default"]
|
||||||
|
dependencies = [
|
||||||
|
"nonebot2>=2.3.0",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "nonebot_plugin_waiter-0.6.2-py3-none-any.whl", hash = "sha256:599251f02d074ab7142e2144f68d63f41104bddcd359051f63979a8163538eac"},
|
||||||
|
{file = "nonebot_plugin_waiter-0.6.2.tar.gz", hash = "sha256:02017a1613d1273be3535b28a4d8e823f2dbaba26fab524bc8207f50a25ec8e4"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nonebot2"
|
name = "nonebot2"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
@ -833,6 +1031,16 @@ files = [
|
|||||||
{file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"},
|
{file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytz"
|
||||||
|
version = "2024.1"
|
||||||
|
summary = "World timezone definitions, modern and historical"
|
||||||
|
groups = ["default"]
|
||||||
|
files = [
|
||||||
|
{file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"},
|
||||||
|
{file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyyaml"
|
name = "pyyaml"
|
||||||
version = "6.0.1"
|
version = "6.0.1"
|
||||||
@ -898,6 +1106,32 @@ files = [
|
|||||||
{file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"},
|
{file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ruff"
|
||||||
|
version = "0.4.9"
|
||||||
|
requires_python = ">=3.7"
|
||||||
|
summary = "An extremely fast Python linter and code formatter, written in Rust."
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "ruff-0.4.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b262ed08d036ebe162123170b35703aaf9daffecb698cd367a8d585157732991"},
|
||||||
|
{file = "ruff-0.4.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:98ec2775fd2d856dc405635e5ee4ff177920f2141b8e2d9eb5bd6efd50e80317"},
|
||||||
|
{file = "ruff-0.4.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4555056049d46d8a381f746680db1c46e67ac3b00d714606304077682832998e"},
|
||||||
|
{file = "ruff-0.4.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e91175fbe48f8a2174c9aad70438fe9cb0a5732c4159b2a10a3565fea2d94cde"},
|
||||||
|
{file = "ruff-0.4.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e8e7b95673f22e0efd3571fb5b0cf71a5eaaa3cc8a776584f3b2cc878e46bff"},
|
||||||
|
{file = "ruff-0.4.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2d45ddc6d82e1190ea737341326ecbc9a61447ba331b0a8962869fcada758505"},
|
||||||
|
{file = "ruff-0.4.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:78de3fdb95c4af084087628132336772b1c5044f6e710739d440fc0bccf4d321"},
|
||||||
|
{file = "ruff-0.4.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:06b60f91bfa5514bb689b500a25ba48e897d18fea14dce14b48a0c40d1635893"},
|
||||||
|
{file = "ruff-0.4.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88bffe9c6a454bf8529f9ab9091c99490578a593cc9f9822b7fc065ee0712a06"},
|
||||||
|
{file = "ruff-0.4.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:673bddb893f21ab47a8334c8e0ea7fd6598ecc8e698da75bcd12a7b9d0a3206e"},
|
||||||
|
{file = "ruff-0.4.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8c1aff58c31948cc66d0b22951aa19edb5af0a3af40c936340cd32a8b1ab7438"},
|
||||||
|
{file = "ruff-0.4.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:784d3ec9bd6493c3b720a0b76f741e6c2d7d44f6b2be87f5eef1ae8cc1d54c84"},
|
||||||
|
{file = "ruff-0.4.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:732dd550bfa5d85af8c3c6cbc47ba5b67c6aed8a89e2f011b908fc88f87649db"},
|
||||||
|
{file = "ruff-0.4.9-py3-none-win32.whl", hash = "sha256:8064590fd1a50dcf4909c268b0e7c2498253273309ad3d97e4a752bb9df4f521"},
|
||||||
|
{file = "ruff-0.4.9-py3-none-win_amd64.whl", hash = "sha256:e0a22c4157e53d006530c902107c7f550b9233e9706313ab57b892d7197d8e52"},
|
||||||
|
{file = "ruff-0.4.9-py3-none-win_arm64.whl", hash = "sha256:5d5460f789ccf4efd43f265a58538a2c24dbce15dbf560676e430375f20a8198"},
|
||||||
|
{file = "ruff-0.4.9.tar.gz", hash = "sha256:f1cb0828ac9533ba0135d148d214e284711ede33640465e706772645483427e3"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shellingham"
|
name = "shellingham"
|
||||||
version = "1.5.4"
|
version = "1.5.4"
|
||||||
@ -909,6 +1143,17 @@ files = [
|
|||||||
{file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"},
|
{file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
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"]
|
||||||
|
files = [
|
||||||
|
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||||
|
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sniffio"
|
name = "sniffio"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
@ -983,6 +1228,47 @@ files = [
|
|||||||
{file = "StrEnum-0.4.15.tar.gz", hash = "sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff"},
|
{file = "StrEnum-0.4.15.tar.gz", hash = "sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tarina"
|
||||||
|
version = "0.5.2"
|
||||||
|
requires_python = ">=3.8"
|
||||||
|
summary = "A collection of common utils for Arclet"
|
||||||
|
groups = ["default"]
|
||||||
|
dependencies = [
|
||||||
|
"typing-extensions>=4.4.0",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "tarina-0.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0ceb642f8b08649afb84b7b5419ac20a20e4b5cb3ccf70adadfbf677219d5c34"},
|
||||||
|
{file = "tarina-0.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90ab4fc0b64ddca3544a4f80f5747b725576e7e5b9723d375691e0acdcfc7317"},
|
||||||
|
{file = "tarina-0.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5c08bbfeae78f5f97971c4f3a6af18dd0c56d20379dd1302632180dbbc27b6ad"},
|
||||||
|
{file = "tarina-0.5.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d84de2660b05ce6a5195e3b9cb451aa69c530e0c5e6d2672b702f57062f8e7c"},
|
||||||
|
{file = "tarina-0.5.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3de93f3ad255e35b5228c926316d06f58a77752be5ad5bd3f52ad4781baa2c11"},
|
||||||
|
{file = "tarina-0.5.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:204d3229d1fa20d235f05054622b23b3d2b43010e882e401f844a950a65edfe7"},
|
||||||
|
{file = "tarina-0.5.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:11fb54d0d6f1692606bacac197f7fdb151dd7b2cf6365efceced1c63dd308ad8"},
|
||||||
|
{file = "tarina-0.5.2-cp310-cp310-win32.whl", hash = "sha256:0142e3ad8c1b85d4b6aeaee36f2102cf891db05efeccc7f445fbba86c84defd5"},
|
||||||
|
{file = "tarina-0.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:16d712303b1c5431812bcc85a6ad6801dafd2a9cb125207f01316dca4bf19dfb"},
|
||||||
|
{file = "tarina-0.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6452c02fc1d3503336b70aaeeffc978c46e1ac69ad32124a85b135690be84aa1"},
|
||||||
|
{file = "tarina-0.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:25c0c7551ce603cfd31fbb3ded86b2d357f59db2735279e60486a45d06bfa3e0"},
|
||||||
|
{file = "tarina-0.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3909e0175bab0ee88ef908bdc1df91fdcd39181833d25cb820876436126c7a2a"},
|
||||||
|
{file = "tarina-0.5.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1faceea384a150c958471a1c86676b96e7543b60f0e66196777f0c0ebb6207a"},
|
||||||
|
{file = "tarina-0.5.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce9fafc4da64e692e11eb75da65906387b86123acd190f0be5176d91f0c523a2"},
|
||||||
|
{file = "tarina-0.5.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:deb0848058843104727b8bb210d3b004d8aa4dcbc48e31abd65881eaa02a3a22"},
|
||||||
|
{file = "tarina-0.5.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1e07c227ae43482bc738532400840ae718c259e585903094fa758fec258ccd6e"},
|
||||||
|
{file = "tarina-0.5.2-cp311-cp311-win32.whl", hash = "sha256:bd775ac25ffce24f820e071786ceebab61fc7c2cc3102f43fabd664e2ce808dd"},
|
||||||
|
{file = "tarina-0.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:0ff7b0774233ea031a6192bcfca8cea3f01fb9d206447719e0764609ccbac243"},
|
||||||
|
{file = "tarina-0.5.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2955d68597e319e7ba1f009d333f75ea13e7eb11050044e33ac6b3970eb4ce20"},
|
||||||
|
{file = "tarina-0.5.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:40adb676c0649fa666ee2522d546183fb27b3448b3b222ceeb57c0d164b6902a"},
|
||||||
|
{file = "tarina-0.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9e959d1e5e2203beab515bdf540d21f2c744c7e661515f2ad130f2a2f0612ace"},
|
||||||
|
{file = "tarina-0.5.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84c4ffca7f56c464f209fb3bd828cb4f23de54625239a5fd45a6fb3d003e8f1c"},
|
||||||
|
{file = "tarina-0.5.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:900a41de49dc0af1f05906248c1331818fe685003149e9acbcc815b47efeffc8"},
|
||||||
|
{file = "tarina-0.5.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8ba80ee60ff18dd23431024b8708021522608e08908f882ed9521fffc3df1b4d"},
|
||||||
|
{file = "tarina-0.5.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:959c38a97cf64d10764525f8aa1212f464213212a49a10363dff1989ad18b3cb"},
|
||||||
|
{file = "tarina-0.5.2-cp312-cp312-win32.whl", hash = "sha256:4aa94f80d8442ff246289702994c12476dcbdeca3d0d2b7924af4c3e6929eb7f"},
|
||||||
|
{file = "tarina-0.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:56f898f938e33b1b06133d39e7f3e9016e94c56358870c27c9f6cf0d56e66797"},
|
||||||
|
{file = "tarina-0.5.2-py3-none-any.whl", hash = "sha256:a1a83f355b3725efcf5a1b24c8808508af1dd154528aae03263a9e04a5a3c2a3"},
|
||||||
|
{file = "tarina-0.5.2.tar.gz", hash = "sha256:7d5d93d73422e97b2409e6a43bf4d11296fe2dac90a5b4dcbc19e56bc1b55298"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tomli"
|
name = "tomli"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
@ -1023,6 +1309,32 @@ files = [
|
|||||||
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tzdata"
|
||||||
|
version = "2024.1"
|
||||||
|
requires_python = ">=2"
|
||||||
|
summary = "Provider of IANA time zone data"
|
||||||
|
groups = ["default"]
|
||||||
|
marker = "platform_system == \"Windows\""
|
||||||
|
files = [
|
||||||
|
{file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"},
|
||||||
|
{file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tzlocal"
|
||||||
|
version = "5.2"
|
||||||
|
requires_python = ">=3.8"
|
||||||
|
summary = "tzinfo object for the local timezone"
|
||||||
|
groups = ["default"]
|
||||||
|
dependencies = [
|
||||||
|
"tzdata; platform_system == \"Windows\"",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"},
|
||||||
|
{file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ujson"
|
name = "ujson"
|
||||||
version = "5.10.0"
|
version = "5.10.0"
|
||||||
|
@ -10,11 +10,26 @@ dependencies = [
|
|||||||
"nonebot-plugin-chatrecorder>=0.6.0",
|
"nonebot-plugin-chatrecorder>=0.6.0",
|
||||||
"pygal>=3.0.4",
|
"pygal>=3.0.4",
|
||||||
"requests>=2.32.3",
|
"requests>=2.32.3",
|
||||||
|
"nonebot-plugin-apscheduler>=0.4.0",
|
||||||
|
"nonebot-plugin-alconna>=0.46.6",
|
||||||
|
"nonebot-plugin-cesaa>=0.4.0",
|
||||||
|
"nonebot-plugin-userinfo>=0.2.4",
|
||||||
]
|
]
|
||||||
requires-python = ">=3.10,<4.0"
|
requires-python = ">=3.10,<4.0"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = {text = "MIT"}
|
license = {text = "MIT"}
|
||||||
|
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
dev = [
|
||||||
|
"ruff>=0.4.9",
|
||||||
|
]
|
||||||
|
|
||||||
[tool.pdm]
|
[tool.pdm]
|
||||||
distribution = false
|
distribution = false
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
line-length = 80
|
||||||
|
[tool.ruff.format]
|
||||||
|
quote-style = "single"
|
||||||
|
indent-style = "tab"
|
||||||
|
Loading…
Reference in New Issue
Block a user