mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-02 02:00:01 +08:00
update 0.0.6.0
This commit is contained in:
+49
-12
@@ -1,31 +1,68 @@
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from typing import List
|
||||
from utils.image_utils import CreateMat
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from typing import List, Union
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
|
||||
async def init_rank(all_user_id: List[int], all_user_data: List[int], group_id: int) -> str:
|
||||
async def init_rank(
|
||||
title: str, all_user_id: List[int], all_user_data: List[int], group_id: int, total_count: int = 10
|
||||
) -> CreateMat:
|
||||
"""
|
||||
说明:
|
||||
初始化通用的数据排行榜
|
||||
参数:
|
||||
:param title: 排行榜标题
|
||||
:param all_user_id: 所有用户的qq号
|
||||
:param all_user_data: 所有用户需要排行的对应数据
|
||||
:param group_id: 群号,用于从数据库中获取该用户在此群的昵称
|
||||
:param total_count: 获取人数总数
|
||||
"""
|
||||
rst = ''
|
||||
for i in range(len(all_user_id) if len(all_user_id) < 10 else 10):
|
||||
_uname_lst = []
|
||||
_num_lst = []
|
||||
for i in range(len(all_user_id) if len(all_user_id) < total_count else total_count):
|
||||
_max = max(all_user_data)
|
||||
max_user_id = all_user_id[all_user_data.index(_max)]
|
||||
all_user_id.remove(max_user_id)
|
||||
all_user_data.remove(_max)
|
||||
try:
|
||||
user_name = (await GroupInfoUser.get_member_info(max_user_id, group_id)).user_name
|
||||
user_name = (
|
||||
await GroupInfoUser.get_member_info(max_user_id, group_id)
|
||||
).user_name
|
||||
except AttributeError:
|
||||
user_name = f'{max_user_id}'
|
||||
rst += f'{user_name}: {_max}\n'
|
||||
return rst[:-1]
|
||||
|
||||
|
||||
|
||||
|
||||
user_name = f"{max_user_id}"
|
||||
_uname_lst.append(user_name)
|
||||
_num_lst.append(_max)
|
||||
_uname_lst.reverse()
|
||||
_num_lst.reverse()
|
||||
return await asyncio.get_event_loop().run_in_executor(
|
||||
None, _init_rank_graph, title, _uname_lst, _num_lst
|
||||
)
|
||||
|
||||
|
||||
def _init_rank_graph(
|
||||
title: str, _uname_lst: List[str], _num_lst: List[Union[int, float]]
|
||||
) -> CreateMat:
|
||||
"""
|
||||
生成排行榜统计图
|
||||
:param title: 排行榜标题
|
||||
:param _uname_lst: 用户名列表
|
||||
:param _num_lst: 数值列表
|
||||
"""
|
||||
image = CreateMat(
|
||||
y=_num_lst,
|
||||
y_name="* 可以在命令后添加数字来指定排行人数 至多 50 *",
|
||||
mat_type="barh",
|
||||
title=title,
|
||||
x_index=_uname_lst,
|
||||
display_num=True,
|
||||
x_rotate=30,
|
||||
background=[
|
||||
f"{IMAGE_PATH}/background/create_mat/{x}"
|
||||
for x in os.listdir(f"{IMAGE_PATH}/background/create_mat")
|
||||
],
|
||||
bar_color=["*"],
|
||||
)
|
||||
image.gen_graph()
|
||||
return image
|
||||
|
||||
+59
-30
@@ -416,6 +416,7 @@ class CreateImg:
|
||||
color = self.markImg.getpixel((i, k))
|
||||
color = color[:-1] + (int(100 * alpha_ratio),)
|
||||
self.markImg.putpixel((i, k), color)
|
||||
self.draw = ImageDraw.Draw(self.markImg)
|
||||
|
||||
def pic2bs4(self) -> str:
|
||||
"""
|
||||
@@ -501,26 +502,38 @@ class CreateImg:
|
||||
:param radii: 半径
|
||||
"""
|
||||
# 画圆(用于分离4个角)
|
||||
circle = Image.new('L', (radii * 2, radii * 2), 0)
|
||||
circle = Image.new("L", (radii * 2, radii * 2), 0)
|
||||
draw = ImageDraw.Draw(circle)
|
||||
draw.ellipse((0, 0, radii * 2, radii * 2), fill=255)
|
||||
self.markImg = self.markImg.convert("RGBA")
|
||||
w, h = self.markImg.size
|
||||
alpha = Image.new('L', self.markImg.size, 255)
|
||||
alpha = Image.new("L", self.markImg.size, 255)
|
||||
alpha.paste(circle.crop((0, 0, radii, radii)), (0, 0))
|
||||
alpha.paste(circle.crop((radii, 0, radii * 2, radii)), (w - radii, 0))
|
||||
alpha.paste(circle.crop((radii, radii, radii * 2, radii * 2)), (w - radii, h - radii))
|
||||
alpha.paste(
|
||||
circle.crop((radii, radii, radii * 2, radii * 2)), (w - radii, h - radii)
|
||||
)
|
||||
alpha.paste(circle.crop((0, radii, radii, radii * 2)), (0, h - radii))
|
||||
self.markImg.putalpha(alpha)
|
||||
|
||||
def rotate(self, angle: int):
|
||||
def rotate(self, angle: int, expand: bool = False):
|
||||
"""
|
||||
说明:
|
||||
旋转图片
|
||||
参数:
|
||||
:param angle: 角度
|
||||
:param expand: 放大图片适应角度
|
||||
"""
|
||||
self.markImg = self.markImg.rotate(angle)
|
||||
self.markImg = self.markImg.rotate(angle, expand=expand)
|
||||
|
||||
def transpose(self, angle: int):
|
||||
"""
|
||||
说明:
|
||||
旋转图片(包括边框)
|
||||
参数:
|
||||
:param angle: 角度
|
||||
"""
|
||||
self.markImg.transpose(angle)
|
||||
|
||||
def filter(self, filter_: str, aud: int = None):
|
||||
"""
|
||||
@@ -529,21 +542,22 @@ class CreateImg:
|
||||
:param aud: 利率
|
||||
"""
|
||||
_x = None
|
||||
if filter_ == 'GaussianBlur': # 高斯模糊
|
||||
if filter_ == "GaussianBlur": # 高斯模糊
|
||||
_x = ImageFilter.GaussianBlur
|
||||
elif filter_ == 'EDGE_ENHANCE': # 锐化效果
|
||||
elif filter_ == "EDGE_ENHANCE": # 锐化效果
|
||||
_x = ImageFilter.EDGE_ENHANCE
|
||||
elif filter_ == 'BLUR': # 模糊效果
|
||||
elif filter_ == "BLUR": # 模糊效果
|
||||
_x = ImageFilter.BLUR
|
||||
elif filter_ == 'CONTOUR': # 铅笔滤镜
|
||||
elif filter_ == "CONTOUR": # 铅笔滤镜
|
||||
_x = ImageFilter.CONTOUR
|
||||
elif filter_ == 'FIND_EDGES': # 边缘检测
|
||||
elif filter_ == "FIND_EDGES": # 边缘检测
|
||||
_x = ImageFilter.FIND_EDGES
|
||||
if _x:
|
||||
if aud:
|
||||
self.markImg = self.markImg.filter(_x(aud))
|
||||
else:
|
||||
self.markImg = self.markImg.filter(_x)
|
||||
self.draw = ImageDraw.Draw(self.markImg)
|
||||
|
||||
#
|
||||
def getchannel(self, type_):
|
||||
@@ -565,9 +579,11 @@ class CreateMat:
|
||||
y_name: Optional[str] = None,
|
||||
x_index: List[Union[str, int, float]] = None,
|
||||
y_index: List[Union[str, int, float]] = None,
|
||||
x_rotate: int = 0,
|
||||
title: Optional[str] = None,
|
||||
size: Tuple[int, int] = (1000, 1000),
|
||||
font_size: int = 20,
|
||||
font: str = "msyh.ttf",
|
||||
font_size: Optional[int] = None,
|
||||
display_num: bool = False,
|
||||
is_grid: bool = False,
|
||||
background: Optional[List[str]] = None,
|
||||
@@ -584,8 +600,10 @@ class CreateMat:
|
||||
:param y_name: 纵坐标名称
|
||||
:param x_index: 横坐标值
|
||||
:param y_index: 纵坐标值
|
||||
:param x_rotate: 横坐标旋转角度
|
||||
:param title: 标题
|
||||
:param size: 图像大小,建议默认
|
||||
:param font: 字体
|
||||
:param font_size: 字体大小,建议默认
|
||||
:param display_num: 是否显示数值
|
||||
:param is_grid: 是否添加栅格
|
||||
@@ -603,8 +621,9 @@ class CreateMat:
|
||||
self.y_name = y_name
|
||||
self.x_index = x_index
|
||||
self.y_index = y_index
|
||||
self.x_rotate = x_rotate
|
||||
self.title = title
|
||||
self.font_size = font_size
|
||||
self.font = font
|
||||
self.display_num = display_num
|
||||
self.is_grid = is_grid
|
||||
self.background = background
|
||||
@@ -616,6 +635,10 @@ class CreateMat:
|
||||
self.line_length = 760
|
||||
self._deviation = 0.905
|
||||
self._color = {}
|
||||
if not font_size:
|
||||
self.font_size = int(25 * (1 - len(x_index) / 100))
|
||||
else:
|
||||
self.font_size = font_size
|
||||
if self.bar_color == ["*"]:
|
||||
self.bar_color = [
|
||||
"#FF0000",
|
||||
@@ -629,14 +652,11 @@ class CreateMat:
|
||||
if not x_index:
|
||||
raise ValueError("缺少 x_index [横坐标值]...")
|
||||
self._x_interval = int((self.line_length - 70) / len(x_index))
|
||||
self._bar_width = int(
|
||||
(self.line_length - (len(x_index) * (10 if len(x_index) >= 18 else 25)))
|
||||
/ len(x_index)
|
||||
)
|
||||
self._bar_width = int(30 * (1 - (len(x_index) + 10) / 100))
|
||||
# 没有 y_index 时自动生成
|
||||
if not y_index:
|
||||
_y_index = []
|
||||
_max_value = max(y)
|
||||
_max_value = int(max(y))
|
||||
_max_value = ceil(
|
||||
_max_value / eval("1" + "0" * (len(str(_max_value)) - 1))
|
||||
) * eval("1" + "0" * (len(str(_max_value)) - 1))
|
||||
@@ -793,9 +813,9 @@ class CreateMat:
|
||||
self.markImg.text(
|
||||
(
|
||||
current_w - w,
|
||||
current_h - int(y[i] * self._p * self._deviation) - 25,
|
||||
current_h - int(y[i] * self._p * self._deviation) - 25 - 5,
|
||||
),
|
||||
str(y[i]),
|
||||
f"{y[i]:.2f}" if isinstance(y[i], float) else f"{y[i]}",
|
||||
)
|
||||
self.markImg.paste(
|
||||
_black_point,
|
||||
@@ -840,15 +860,17 @@ class CreateMat:
|
||||
current_w = self.padding_w + _interval
|
||||
current_h = self.padding_h + self.line_length
|
||||
for i in range(len(y)):
|
||||
# 画出显示数字
|
||||
if display_num:
|
||||
# 横柱状图
|
||||
if is_barh:
|
||||
font_h = self.markImg.getsize(str(y[i]))[1]
|
||||
self.markImg.text(
|
||||
(
|
||||
self.padding_w + int(y[i] * self._p * self._deviation) + 2,
|
||||
current_h - int(font_h / 2),
|
||||
self.padding_w + int(y[i] * self._p * self._deviation) + 2 + 5,
|
||||
current_h - int(font_h / 2) - 1,
|
||||
),
|
||||
str(y[i]),
|
||||
f"{y[i]:.2f}" if isinstance(y[i], float) else f"{y[i]}",
|
||||
)
|
||||
else:
|
||||
w = int(self.markImg.getsize(str(y[i]))[0] / 2)
|
||||
@@ -857,7 +879,7 @@ class CreateMat:
|
||||
current_w - w,
|
||||
current_h - int(y[i] * self._p * self._deviation) - 25,
|
||||
),
|
||||
str(y[i]),
|
||||
f"{y[i]:.2f}" if isinstance(y[i], float) else f"{y[i]}",
|
||||
)
|
||||
if i != len(y):
|
||||
bar_color = random.choice(self.bar_color)
|
||||
@@ -915,7 +937,7 @@ class CreateMat:
|
||||
padding_h = self.padding_h
|
||||
line_length = self.line_length
|
||||
background = random.choice(self.background) if self.background else None
|
||||
A = CreateImg(self.w, self.h, font_size=font_size, background=background)
|
||||
A = CreateImg(self.w, self.h, font_size=font_size, font=self.font, background=background)
|
||||
if background:
|
||||
_tmp = CreateImg(self.w, self.h)
|
||||
_tmp.transparent(2)
|
||||
@@ -928,6 +950,7 @@ class CreateMat:
|
||||
color=(255, 255, 255, 0),
|
||||
font_size=35,
|
||||
font_color=self._color.get("title"),
|
||||
font=self.font
|
||||
)
|
||||
A.paste(title, (0, 25), True, "by_width")
|
||||
A.line(
|
||||
@@ -957,8 +980,9 @@ class CreateMat:
|
||||
y_index = tmp
|
||||
_interval = self._y_interval
|
||||
current_w = padding_w + _interval
|
||||
_text_font = CreateImg(0, 0, font_size=self.font_size)
|
||||
_text_font = CreateImg(0, 0, font_size=self.font_size, font=self.font)
|
||||
_grid = self.line_length if is_grid else 10
|
||||
x_rotate_height = 0
|
||||
for _x in x_index:
|
||||
_p = CreateImg(1, _grid, color="#a9a9a9")
|
||||
A.paste(_p, (current_w, padding_h + line_length - _grid))
|
||||
@@ -969,15 +993,18 @@ class CreateMat:
|
||||
plain_text=f"{_x}",
|
||||
font_size=self.font_size,
|
||||
color=(255, 255, 255, 0),
|
||||
font=self.font
|
||||
)
|
||||
text.rotate(self.x_rotate, True)
|
||||
A.paste(text, (current_w - w, padding_h + line_length + 10), alpha=True)
|
||||
current_w += _interval
|
||||
x_rotate_height = text.h
|
||||
_interval = self._x_interval if self.mat_type == "barh" else self._y_interval
|
||||
current_h = padding_h + line_length - _interval
|
||||
_text_font = CreateImg(0, 0, font_size=self.font_size)
|
||||
_text_font = CreateImg(0, 0, font_size=self.font_size, font=self.font)
|
||||
for _y in y_index:
|
||||
_p = CreateImg(_grid, 1, color="#a9a9a9")
|
||||
A.paste(_p, (padding_w, current_h))
|
||||
A.paste(_p, (padding_w + 2, current_h))
|
||||
w, h = _text_font.getsize(f"{_y}")
|
||||
h = int(h / 2)
|
||||
text = CreateImg(
|
||||
@@ -986,6 +1013,7 @@ class CreateMat:
|
||||
plain_text=f"{_y}",
|
||||
font_size=self.font_size,
|
||||
color=(255, 255, 255, 0),
|
||||
font=self.font
|
||||
)
|
||||
idx = 0
|
||||
while text.size[0] > self.padding_w - 10 and idx < 3:
|
||||
@@ -993,8 +1021,9 @@ class CreateMat:
|
||||
0,
|
||||
0,
|
||||
plain_text=f"{_y}",
|
||||
font_size=int(self.font_size * 0.9),
|
||||
font_size=int(self.font_size * 0.75),
|
||||
color=(255, 255, 255, 0),
|
||||
font=self.font
|
||||
)
|
||||
w, _ = text.getsize(f"{_y}")
|
||||
idx += 1
|
||||
@@ -1004,10 +1033,10 @@ class CreateMat:
|
||||
A.text((int(padding_w / 2), int(padding_w / 2)), x_name)
|
||||
if y_name:
|
||||
A.text(
|
||||
(int(padding_w + line_length + 50), int(padding_h + line_length + 50)),
|
||||
(int(padding_w + line_length + 50 - A.getsize(y_name)[0]),
|
||||
int(padding_h + line_length + 50 + x_rotate_height)),
|
||||
y_name,
|
||||
)
|
||||
# A.show()
|
||||
return A
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
from typing import Optional
|
||||
from .group_manager import GroupManager
|
||||
from pathlib import Path
|
||||
from .data_class import StaticData
|
||||
from .withdraw_message_manager import WithdrawMessageManager
|
||||
from .plugins2cd_manager import Plugins2cdManager
|
||||
from .plugins2block_manager import Plugins2blockManager
|
||||
from .plugins2count_manager import Plugins2countManager
|
||||
from .plugins2settings_manager import Plugins2settingsManager
|
||||
from .plugins_manager import PluginsManager
|
||||
from .resources_manager import ResourcesManager
|
||||
from .admin_manager import AdminManager
|
||||
from .none_plugin_count_manager import NonePluginCountManager
|
||||
from .requests_manager import RequestManager
|
||||
from configs.path_config import DATA_PATH
|
||||
from nonebot import Driver
|
||||
import nonebot
|
||||
@@ -19,6 +25,11 @@ group_manager: Optional[GroupManager] = GroupManager(
|
||||
# 撤回消息管理
|
||||
withdraw_message_manager: Optional[WithdrawMessageManager] = WithdrawMessageManager()
|
||||
|
||||
# 插件管理
|
||||
plugins_manager: Optional[PluginsManager] = PluginsManager(
|
||||
Path(DATA_PATH) / "manager" / "plugins_manager.json"
|
||||
)
|
||||
|
||||
# 插件基本设置管理
|
||||
plugins2settings_manager: Optional[Plugins2settingsManager] = Plugins2settingsManager(
|
||||
Path(DATA_PATH) / "configs" / "plugins2settings.yaml"
|
||||
@@ -34,6 +45,27 @@ plugins2block_manager: Optional[Plugins2blockManager] = Plugins2blockManager(
|
||||
Path(DATA_PATH) / "configs" / "plugins2block.yaml"
|
||||
)
|
||||
|
||||
# 插件命令 每次次数限制 管理
|
||||
plugins2count_manager: Optional[Plugins2countManager] = Plugins2countManager(
|
||||
Path(DATA_PATH) / "configs" / "plugins2count.yaml"
|
||||
)
|
||||
|
||||
# 资源管理
|
||||
resources_manager: Optional[ResourcesManager] = ResourcesManager(
|
||||
Path(DATA_PATH) / "manager" / "resources_manager.json"
|
||||
)
|
||||
|
||||
# 插件加载容忍管理
|
||||
none_plugin_count_manager: Optional[NonePluginCountManager] = NonePluginCountManager(
|
||||
Path(DATA_PATH) / "manager" / "none_plugin_count_manager.json"
|
||||
)
|
||||
|
||||
# 好友请求/群聊邀请 管理
|
||||
requests_manager: Optional[RequestManager] = RequestManager(
|
||||
Path(DATA_PATH) / "manager" / "requests_manager.json"
|
||||
)
|
||||
|
||||
|
||||
# 管理员命令管理器
|
||||
admin_manager = AdminManager()
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
from typing import Optional, Dict
|
||||
from .data_class import StaticData
|
||||
from utils.utils import FreqLimiter
|
||||
from services.log import logger
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
class AdminManager(StaticData):
|
||||
@@ -13,15 +10,27 @@ class AdminManager(StaticData):
|
||||
def __init__(self):
|
||||
super().__init__(None)
|
||||
|
||||
def add_admin_command(self, plugin: str, level: int):
|
||||
def add_admin_plugin_settings(self, plugin: str, cmd: List[str], level: int):
|
||||
"""
|
||||
添加一个管理员命令
|
||||
:param plugin: 模块
|
||||
:param cmd: 别名
|
||||
:param level: 等级
|
||||
"""
|
||||
self._data[plugin] = {
|
||||
"level": level,
|
||||
"cmd": cmd,
|
||||
}
|
||||
|
||||
def set_admin_level(self, plugin: str, level: int):
|
||||
"""
|
||||
设置管理员命令等级
|
||||
:param plugin: 模块名
|
||||
:param level: 权限等级
|
||||
"""
|
||||
self._data[plugin] = level
|
||||
self._data[plugin]["level"] = level
|
||||
|
||||
def remove_admin_command(self, plugin: str):
|
||||
def remove_admin_plugin_settings(self, plugin: str):
|
||||
"""
|
||||
删除一个管理员命令
|
||||
:param plugin: 模块名
|
||||
@@ -36,7 +45,7 @@ class AdminManager(StaticData):
|
||||
:param level: 权限等级
|
||||
"""
|
||||
if plugin in self._data.keys():
|
||||
return level >= self._data[plugin]
|
||||
return level >= self._data[plugin]["level"]
|
||||
return True
|
||||
|
||||
def get_plugin_level(self, plugin: str) -> int:
|
||||
@@ -45,7 +54,15 @@ class AdminManager(StaticData):
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
if plugin in self._data.keys():
|
||||
return self._data[plugin]
|
||||
return self._data[plugin]["level"]
|
||||
return 0
|
||||
|
||||
|
||||
def get_plugin_module(self, cmd: str) -> Optional[str]:
|
||||
"""
|
||||
根据 cmd 获取功能 module
|
||||
:param cmd: 命令
|
||||
"""
|
||||
for key in self._data.keys():
|
||||
if self._data[key].get("cmd") and cmd in self._data[key]["cmd"]:
|
||||
return key
|
||||
return None
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# from typing import Optional, Any
|
||||
# from .data_class import StaticData
|
||||
# from pathlib import Path
|
||||
# from ruamel.yaml import YAML
|
||||
#
|
||||
# yaml = YAML(typ="safe")
|
||||
#
|
||||
#
|
||||
# class ConfigsManager(StaticData):
|
||||
# """
|
||||
# 插件配置 与 资源 管理器
|
||||
# """
|
||||
#
|
||||
# def __init__(self, file: Path):
|
||||
# self.file = file
|
||||
# super().__init__(file)
|
||||
# self._resource_data = {}
|
||||
#
|
||||
# def add_plugin_config(
|
||||
# self,
|
||||
# module: str,
|
||||
# key: str,
|
||||
# value: str,
|
||||
# help_: Optional[str] = None,
|
||||
# default_value: Optional[str] = None,
|
||||
# ):
|
||||
# """
|
||||
# 为插件添加一个配置
|
||||
# :param module: 模块
|
||||
# :param key: 键
|
||||
# :param value: 值
|
||||
# :param help_: 配置注解
|
||||
# :param default_value: 默认值
|
||||
# """
|
||||
# if self._data.get(module) is None:
|
||||
# self._data[module] = {}
|
||||
# self._data[module][key] = {
|
||||
# "value": value,
|
||||
# "help": help_,
|
||||
# "default_value": default_value,
|
||||
# }
|
||||
#
|
||||
# def remove_plugin_config(self, module: str):
|
||||
# """
|
||||
# 为插件删除一个配置
|
||||
# :param module: 模块名
|
||||
# """
|
||||
# if module in self._data.keys():
|
||||
# del self._data[module]
|
||||
#
|
||||
# def get_config(self, module: str, key: str) -> Optional[Any]:
|
||||
# """
|
||||
# 获取指定配置值
|
||||
# :param module: 模块名
|
||||
# :param key: 配置名称
|
||||
# """
|
||||
# if module in self._data.keys():
|
||||
# if self._data[module].get(key):
|
||||
# if self._data[module][key]["value"] is None:
|
||||
# return self._data[module][key]["default_value"]
|
||||
# return self._data[module][key]["value"]
|
||||
# return None
|
||||
#
|
||||
#
|
||||
#
|
||||
@@ -12,15 +12,25 @@ class StaticData:
|
||||
"""
|
||||
|
||||
def __init__(self, file: Optional[Path]):
|
||||
self._data = {}
|
||||
self._data: dict = {}
|
||||
if file:
|
||||
file.parent.mkdir(exist_ok=True, parents=True)
|
||||
self.file = file
|
||||
if file.exists():
|
||||
self._data: dict = json.load(open(file, "r", encoding="utf8"))
|
||||
with open(file, "r", encoding="utf8") as f:
|
||||
if file.name.endswith("json"):
|
||||
self._data: dict = json.load(f)
|
||||
elif file.name.endswith("yaml"):
|
||||
self._data = yaml.load(f)
|
||||
|
||||
def set(self, key, value):
|
||||
self._data[key] = value
|
||||
self.save()
|
||||
|
||||
def set_module_data(self, module, key, value):
|
||||
if module in self._data.keys():
|
||||
self._data[module][key] = value
|
||||
self.save()
|
||||
|
||||
def get(self, key):
|
||||
return self._data.get(key)
|
||||
@@ -31,20 +41,24 @@ class StaticData:
|
||||
def delete(self, key):
|
||||
if self._data.get(key) is not None:
|
||||
del self._data[key]
|
||||
self.save()
|
||||
|
||||
def get_data(self):
|
||||
def get_data(self) -> dict:
|
||||
return self._data
|
||||
|
||||
def save(self, path: Union[str, Path] = None):
|
||||
path = path if path else self.file
|
||||
with open(path, "w", encoding="utf8") as f:
|
||||
json.dump(self._data, f, ensure_ascii=False, indent=4)
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
if path:
|
||||
with open(path, "w", encoding="utf8") as f:
|
||||
json.dump(self._data, f, ensure_ascii=False, indent=4)
|
||||
|
||||
def reload(self):
|
||||
if self.file.exists():
|
||||
if self.file.name.endswith('json'):
|
||||
if self.file.name.endswith("json"):
|
||||
self._data: dict = json.load(open(self.file, "r", encoding="utf8"))
|
||||
elif self.file.name.endswith('yaml'):
|
||||
elif self.file.name.endswith("yaml"):
|
||||
self._data: dict = yaml.load(open(self.file, "r", encoding="utf8"))
|
||||
|
||||
def is_exists(self):
|
||||
@@ -61,4 +75,3 @@ class StaticData:
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._data[key]
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from configs.config import DEFAULT_GROUP_LEVEL
|
||||
from typing import Optional, List, Union, Dict
|
||||
from pathlib import Path
|
||||
from .data_class import StaticData
|
||||
@@ -15,33 +14,30 @@ class GroupManager(StaticData):
|
||||
super().__init__(file)
|
||||
if not self._data:
|
||||
self._data = {
|
||||
"super": {"close_plugins": {}, "white_group_list": []},
|
||||
"super": {"white_group_list": []},
|
||||
"group_manager": {},
|
||||
}
|
||||
self._task = {}
|
||||
|
||||
def block_plugin(
|
||||
self, plugin_cmd: str, group_id: Optional[int] = None, block_type: str = "all"
|
||||
):
|
||||
def block_plugin(self, module: str, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
锁定插件
|
||||
参数:
|
||||
:param plugin_cmd: 功能模块名
|
||||
:param module: 功能模块名
|
||||
:param group_id: 群组,None时为超级用户禁用
|
||||
:param block_type: 限制类型
|
||||
"""
|
||||
self._set_plugin_status(plugin_cmd, "block", group_id, block_type)
|
||||
self._set_plugin_status(module, "block", group_id)
|
||||
|
||||
def unblock_plugin(self, plugin_cmd: str, group_id: Optional[int] = None):
|
||||
def unblock_plugin(self, module: str, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
解锁插件
|
||||
参数:
|
||||
:param plugin_cmd: 功能模块名
|
||||
:param module: 功能模块名
|
||||
:param group_id: 群组
|
||||
"""
|
||||
self._set_plugin_status(plugin_cmd, "unblock", group_id)
|
||||
self._set_plugin_status(module, "unblock", group_id)
|
||||
|
||||
def set_group_level(self, group_id: int, level: int):
|
||||
"""
|
||||
@@ -57,49 +53,21 @@ class GroupManager(StaticData):
|
||||
self._data["group_manager"][group_id]["level"] = level
|
||||
self.save()
|
||||
|
||||
def get_plugin_status(
|
||||
self, plugin_cmd: str, group_id: Optional[int] = None, block_type: str = "all"
|
||||
) -> bool:
|
||||
def get_plugin_status(self, module: str, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
获取插件状态
|
||||
参数:
|
||||
:param plugin_cmd: 功能模块名
|
||||
:param module: 功能模块名
|
||||
:param group_id: 群组
|
||||
:param block_type: 限制类型
|
||||
"""
|
||||
group_id = str(group_id) if group_id else group_id
|
||||
if group_id:
|
||||
if not self._data["group_manager"].get(group_id):
|
||||
self._init_group(group_id)
|
||||
return True
|
||||
if plugin_cmd in self._data["group_manager"][group_id]["close_plugins"]:
|
||||
return False
|
||||
if not self._data["group_manager"].get(group_id):
|
||||
self._init_group(group_id)
|
||||
return True
|
||||
else:
|
||||
if plugin_cmd in self._data["super"]["close_plugins"]:
|
||||
if (
|
||||
self._data["super"]["close_plugins"][plugin_cmd] == "all"
|
||||
and block_type == "all"
|
||||
):
|
||||
return False
|
||||
else:
|
||||
return (
|
||||
not self._data["super"]["close_plugins"][plugin_cmd]
|
||||
== block_type
|
||||
)
|
||||
return True
|
||||
|
||||
def get_plugin_block_type(self, plugin_cmd: str) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取功能限制类型
|
||||
参数:
|
||||
:param plugin_cmd: 模块名称
|
||||
"""
|
||||
if plugin_cmd in self._data["super"]["close_plugins"]:
|
||||
return self._data["super"]["close_plugins"][plugin_cmd]
|
||||
return ""
|
||||
if module in self._data["group_manager"][group_id]["close_plugins"]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_group_level(self, group_id: int) -> int:
|
||||
"""
|
||||
@@ -149,6 +117,17 @@ class GroupManager(StaticData):
|
||||
"""
|
||||
return self._data["super"]["white_group_list"]
|
||||
|
||||
def delete_group(self, group_id: int):
|
||||
"""
|
||||
删除群配置
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if group_id in self._data["group_manager"]:
|
||||
del self._data["group_manager"][str(group_id)]
|
||||
if group_id in self._data["super"]["white_group_list"]:
|
||||
self._data["super"]["white_group_list"].remove(group_id)
|
||||
self.save()
|
||||
|
||||
async def open_group_task(self, group_id: int, task: str):
|
||||
"""
|
||||
开启群被动技能
|
||||
@@ -181,6 +160,9 @@ class GroupManager(StaticData):
|
||||
return self._data["group_manager"][group_id]["group_task_status"][task]
|
||||
|
||||
def get_task_data(self) -> Dict[str, str]:
|
||||
"""
|
||||
获取所有被动任务
|
||||
"""
|
||||
return self._task
|
||||
|
||||
async def group_task_status(self, group_id: int) -> str:
|
||||
@@ -188,7 +170,7 @@ class GroupManager(StaticData):
|
||||
查看群被全部动技能状态
|
||||
:param group_id: 群号
|
||||
"""
|
||||
x = '[群被动技能]:\n'
|
||||
x = "[群被动技能]:\n"
|
||||
group_id = str(group_id)
|
||||
if not self._data["group_manager"][group_id].get("group_task_status"):
|
||||
await self.init_group_task(group_id)
|
||||
@@ -222,8 +204,8 @@ class GroupManager(StaticData):
|
||||
if not self._task:
|
||||
for matcher in get_matchers():
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
_module = _plugin.module
|
||||
try:
|
||||
_module = _plugin.module
|
||||
plugin_task = _module.__getattribute__("__plugin_task__")
|
||||
for key in plugin_task.keys():
|
||||
self._task[key] = plugin_task[key]
|
||||
@@ -240,18 +222,20 @@ class GroupManager(StaticData):
|
||||
if not self._data["group_manager"].get(group_id):
|
||||
self._init_group(group_id)
|
||||
if not self._data["group_manager"][group_id].get("group_task_status"):
|
||||
self._data["group_manager"][group_id]['group_task_status'] = {}
|
||||
self._data["group_manager"][group_id]["group_task_status"] = {}
|
||||
for task in self._task:
|
||||
if (
|
||||
self._data["group_manager"][group_id][
|
||||
"group_task_status"
|
||||
].get(task)
|
||||
self._data["group_manager"][group_id]["group_task_status"].get(
|
||||
task
|
||||
)
|
||||
is None
|
||||
):
|
||||
self._data["group_manager"][group_id]["group_task_status"][
|
||||
task
|
||||
] = True
|
||||
for task in self._data["group_manager"][group_id]["group_task_status"]:
|
||||
for task in list(
|
||||
self._data["group_manager"][group_id]["group_task_status"]
|
||||
):
|
||||
if task not in self._task:
|
||||
del self._data["group_manager"][group_id]["group_task_status"][
|
||||
task
|
||||
@@ -260,48 +244,27 @@ class GroupManager(StaticData):
|
||||
|
||||
def _set_plugin_status(
|
||||
self,
|
||||
plugin_cmd: str,
|
||||
module: str,
|
||||
status: str,
|
||||
group_id: Optional[str],
|
||||
block_type: str = "all",
|
||||
group_id: int,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
设置功能开关状态
|
||||
参数:
|
||||
:param plugin_cmd: 功能模块名
|
||||
:param module: 功能模块名
|
||||
:param status: 功能状态
|
||||
:param group_id: 群组
|
||||
:param block_type: 限制类型
|
||||
"""
|
||||
group_id = str(group_id) if group_id else group_id
|
||||
if plugin_cmd:
|
||||
if group_id:
|
||||
if not self._data["group_manager"].get(group_id):
|
||||
self._init_group(group_id)
|
||||
if status == "block":
|
||||
if (
|
||||
plugin_cmd
|
||||
not in self._data["group_manager"][group_id]["close_plugins"]
|
||||
):
|
||||
self._data["group_manager"][group_id]["close_plugins"].append(
|
||||
plugin_cmd
|
||||
)
|
||||
else:
|
||||
if plugin_cmd in self._data["group_manager"][group_id]["close_plugins"]:
|
||||
self._data["group_manager"][group_id]["close_plugins"].remove(
|
||||
plugin_cmd
|
||||
)
|
||||
else:
|
||||
if status == "block":
|
||||
if (
|
||||
plugin_cmd not in self._data["super"]["close_plugins"]
|
||||
or block_type != self._data["super"]["close_plugins"][plugin_cmd]
|
||||
):
|
||||
self._data["super"]["close_plugins"][plugin_cmd] = block_type
|
||||
else:
|
||||
if plugin_cmd in self._data["super"]["close_plugins"]:
|
||||
del self._data["super"]["close_plugins"][plugin_cmd]
|
||||
if not self._data["group_manager"].get(group_id):
|
||||
self._init_group(group_id)
|
||||
if status == "block":
|
||||
if module not in self._data["group_manager"][group_id]["close_plugins"]:
|
||||
self._data["group_manager"][group_id]["close_plugins"].append(module)
|
||||
else:
|
||||
if module in self._data["group_manager"][group_id]["close_plugins"]:
|
||||
self._data["group_manager"][group_id]["close_plugins"].remove(module)
|
||||
self.save()
|
||||
|
||||
def _init_group(self, group_id: str):
|
||||
@@ -311,9 +274,22 @@ class GroupManager(StaticData):
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
default_group_level = 5 # Config.get_config("group_manager")
|
||||
if not default_group_level:
|
||||
default_group_level = 5
|
||||
if not self._data["group_manager"].get(group_id):
|
||||
self._data["group_manager"][group_id] = {
|
||||
"level": DEFAULT_GROUP_LEVEL,
|
||||
"level": default_group_level,
|
||||
"close_plugins": [],
|
||||
"group_task_status": {},
|
||||
}
|
||||
|
||||
def get_super_old_data(self) -> Optional[dict]:
|
||||
"""
|
||||
获取旧数据,平时使用请不要调用
|
||||
"""
|
||||
if self._data["super"].get("close_plugins"):
|
||||
_x = self._data["super"].get("close_plugins")
|
||||
del self._data["super"]["close_plugins"]
|
||||
return _x
|
||||
return None
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
from .data_class import StaticData
|
||||
from typing import Optional
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class NonePluginCountManager(StaticData):
|
||||
|
||||
"""
|
||||
插件加载容忍管理器,当连续 max_count 次插件加载,视为删除插件,清楚数据
|
||||
"""
|
||||
|
||||
def __init__(self, file: Optional[Path], max_count: int = 5):
|
||||
"""
|
||||
:param file: 存储路径
|
||||
:param max_count: 容忍最大次数
|
||||
"""
|
||||
super().__init__(file)
|
||||
self._max_count = max_count
|
||||
|
||||
def add_count(self, module: str, count: int = 1):
|
||||
"""
|
||||
添加次数
|
||||
:param module: 模块
|
||||
:param count: 次数,无特殊情况均为 1
|
||||
"""
|
||||
if module not in self._data.keys():
|
||||
self._data[module] = count
|
||||
else:
|
||||
self._data[module] += count
|
||||
|
||||
def reset(self, module: str):
|
||||
"""
|
||||
重置次数
|
||||
:param module: 模块
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
self._data[module] = 0
|
||||
|
||||
def check(self, module: str):
|
||||
"""
|
||||
检查容忍次数是否到达最大值
|
||||
:param module: 模块
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
return self._data.keys() > self._max_count
|
||||
return False
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -12,10 +12,18 @@ class Plugins2blockManager(StaticData):
|
||||
"""
|
||||
插件命令阻塞 管理器
|
||||
"""
|
||||
|
||||
def __init__(self, file: Path):
|
||||
self.file = file
|
||||
super().__init__(None)
|
||||
self._block_limiter: Dict[str, UserBlockLimiter] = {}
|
||||
if file.exists():
|
||||
with open(file, "r", encoding="utf8") as f:
|
||||
self._data = yaml.load(f)
|
||||
if "PluginBlockLimit" in self._data.keys():
|
||||
self._data = (
|
||||
self._data["PluginBlockLimit"] if self._data["PluginBlockLimit"] else {}
|
||||
)
|
||||
|
||||
def add_block_limit(
|
||||
self,
|
||||
@@ -36,13 +44,13 @@ class Plugins2blockManager(StaticData):
|
||||
:param data_dict: 封装好的字典数据
|
||||
"""
|
||||
if data_dict:
|
||||
status = data_dict.get('status')
|
||||
check_type = data_dict.get('check_type')
|
||||
limit_type = data_dict.get('limit_type')
|
||||
rst = data_dict.get('rst')
|
||||
status = data_dict.get("status")
|
||||
check_type = data_dict.get("check_type")
|
||||
limit_type = data_dict.get("limit_type")
|
||||
rst = data_dict.get("rst")
|
||||
status = status if status is not None else True
|
||||
check_type = check_type if check_type else 'all'
|
||||
limit_type = limit_type if limit_type else 'user'
|
||||
check_type = check_type if check_type else "all"
|
||||
limit_type = limit_type if limit_type else "user"
|
||||
if check_type not in ["all", "group", "private"]:
|
||||
raise ValueError(
|
||||
f"{plugin} 添加block限制错误,‘check_type‘ 必须为 'private'/'group'/'all'"
|
||||
@@ -56,14 +64,6 @@ class Plugins2blockManager(StaticData):
|
||||
"rst": rst,
|
||||
}
|
||||
|
||||
def remove_block_limit(self, plugin: str):
|
||||
"""
|
||||
删除一个插件 block 限制
|
||||
:param plugin: 插件模块名称
|
||||
"""
|
||||
if self._data.get(plugin):
|
||||
del self._data[plugin]
|
||||
|
||||
def get_plugin_block_data(self, plugin: str) -> Optional[dict]:
|
||||
"""
|
||||
获取插件block数据
|
||||
@@ -78,10 +78,7 @@ class Plugins2blockManager(StaticData):
|
||||
检测插件是否有 block
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
return (
|
||||
plugin in self._data.keys()
|
||||
and self._data[plugin]["status"]
|
||||
)
|
||||
return plugin in self._data.keys() and self._data[plugin]["status"]
|
||||
|
||||
def check(self, id_: int, plugin: str) -> bool:
|
||||
"""
|
||||
@@ -119,7 +116,7 @@ class Plugins2blockManager(StaticData):
|
||||
for plugin in self._data:
|
||||
if self.check_plugin_block_status(plugin):
|
||||
self._block_limiter[plugin] = UserBlockLimiter()
|
||||
logger.info(f'已成功加载 {len(self._block_limiter)} 个Block限制.')
|
||||
logger.info(f"已成功加载 {len(self._block_limiter)} 个Block限制.")
|
||||
|
||||
def reload(self):
|
||||
"""
|
||||
@@ -128,5 +125,5 @@ class Plugins2blockManager(StaticData):
|
||||
if self.file.exists():
|
||||
with open(self.file, "r", encoding="utf8") as f:
|
||||
self._data: dict = yaml.load(f)
|
||||
self._data = self._data['PluginBlockLimit']
|
||||
self._data = self._data["PluginBlockLimit"]
|
||||
self.reload_block_limit()
|
||||
|
||||
@@ -17,6 +17,13 @@ class Plugins2cdManager(StaticData):
|
||||
self.file = file
|
||||
super().__init__(None)
|
||||
self._freq_limiter: Dict[str, FreqLimiter] = {}
|
||||
if file.exists():
|
||||
with open(file, "r", encoding="utf8") as f:
|
||||
self._data = yaml.load(f)
|
||||
if "PluginCdLimit" in self._data.keys():
|
||||
self._data = (
|
||||
self._data["PluginCdLimit"] if self._data["PluginCdLimit"] else {}
|
||||
)
|
||||
|
||||
def add_cd_limit(
|
||||
self,
|
||||
@@ -40,15 +47,15 @@ class Plugins2cdManager(StaticData):
|
||||
:param data_dict: 封装好的字典数据
|
||||
"""
|
||||
if data_dict:
|
||||
cd = data_dict.get('cd')
|
||||
status = data_dict.get('status')
|
||||
check_type = data_dict.get('check_type')
|
||||
limit_type = data_dict.get('limit_type')
|
||||
rst = data_dict.get('rst')
|
||||
cd = data_dict.get("cd")
|
||||
status = data_dict.get("status")
|
||||
check_type = data_dict.get("check_type")
|
||||
limit_type = data_dict.get("limit_type")
|
||||
rst = data_dict.get("rst")
|
||||
cd = cd if cd is not None else 5
|
||||
status = status if status is not None else True
|
||||
check_type = check_type if check_type else 'all'
|
||||
limit_type = limit_type if limit_type else 'user'
|
||||
check_type = check_type if check_type else "all"
|
||||
limit_type = limit_type if limit_type else "user"
|
||||
if check_type not in ["all", "group", "private"]:
|
||||
raise ValueError(
|
||||
f"{plugin} 添加cd限制错误,‘check_type‘ 必须为 'private'/'group'/'all'"
|
||||
@@ -63,14 +70,6 @@ class Plugins2cdManager(StaticData):
|
||||
"rst": rst,
|
||||
}
|
||||
|
||||
def remove_cd_limit(self, plugin: str):
|
||||
"""
|
||||
删除一个插件 cd 限制
|
||||
:param plugin: 插件模块名称
|
||||
"""
|
||||
if self._data.get(plugin):
|
||||
del self._data[plugin]
|
||||
|
||||
def get_plugin_cd_data(self, plugin: str) -> Optional[dict]:
|
||||
"""
|
||||
获取插件cd数据
|
||||
@@ -128,8 +127,10 @@ class Plugins2cdManager(StaticData):
|
||||
"""
|
||||
for plugin in self._data:
|
||||
if self.check_plugin_cd_status(plugin):
|
||||
self._freq_limiter[plugin] = FreqLimiter(self.get_plugin_cd_data(plugin)['cd'])
|
||||
logger.info(f'已成功加载 {len(self._freq_limiter)} 个Cd限制.')
|
||||
self._freq_limiter[plugin] = FreqLimiter(
|
||||
self.get_plugin_cd_data(plugin)["cd"]
|
||||
)
|
||||
logger.info(f"已成功加载 {len(self._freq_limiter)} 个Cd限制.")
|
||||
|
||||
def reload(self):
|
||||
"""
|
||||
@@ -138,7 +139,5 @@ class Plugins2cdManager(StaticData):
|
||||
if self.file.exists():
|
||||
with open(self.file, "r", encoding="utf8") as f:
|
||||
self._data: dict = yaml.load(f)
|
||||
self._data = self._data['PluginCdLimit']
|
||||
self._data = self._data["PluginCdLimit"]
|
||||
self.reload_cd_limit()
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
from typing import Optional, Dict
|
||||
from .data_class import StaticData
|
||||
from utils.utils import DailyNumberLimiter
|
||||
from services.log import logger
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import YAML
|
||||
|
||||
yaml = YAML(typ="safe")
|
||||
|
||||
|
||||
class Plugins2countManager(StaticData):
|
||||
"""
|
||||
插件命令 次数 管理器
|
||||
"""
|
||||
|
||||
def __init__(self, file: Path):
|
||||
self.file = file
|
||||
super().__init__(None)
|
||||
self._daily_limiter: Dict[str, DailyNumberLimiter] = {}
|
||||
if file.exists():
|
||||
with open(file, "r", encoding="utf8") as f:
|
||||
self._data = yaml.load(f)
|
||||
if "PluginCountLimit" in self._data.keys():
|
||||
self._data = (
|
||||
self._data["PluginCountLimit"] if self._data["PluginCountLimit"] else {}
|
||||
)
|
||||
|
||||
def add_count_limit(
|
||||
self,
|
||||
plugin: str,
|
||||
*,
|
||||
max_count: int = 5,
|
||||
status: Optional[bool] = True,
|
||||
limit_type: Optional[str] = "user",
|
||||
rst: Optional[str] = None,
|
||||
data_dict: Optional[dict] = None,
|
||||
):
|
||||
"""
|
||||
添加插件调用 次数 限制
|
||||
:param plugin: 插件模块名称
|
||||
:param max_count: 最大次数限制
|
||||
:param status: 默认开关状态
|
||||
:param limit_type: 限制类型 监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
|
||||
:param rst: 回复的话,为空则不回复
|
||||
:param data_dict: 封装好的字典数据
|
||||
"""
|
||||
if data_dict:
|
||||
max_count = data_dict.get("max_count")
|
||||
status = data_dict.get("status")
|
||||
limit_type = data_dict.get("limit_type")
|
||||
rst = data_dict.get("rst")
|
||||
status = status if status is not None else True
|
||||
limit_type = limit_type if limit_type else "user"
|
||||
max_count = max_count if max_count is not None else 5
|
||||
if limit_type not in ["user", "group"]:
|
||||
raise ValueError(f"{plugin} 添加count限制错误,‘limit_type‘ 必须为 'user'/'group'")
|
||||
self._data[plugin] = {
|
||||
"max_count": max_count,
|
||||
"status": status,
|
||||
"limit_type": limit_type,
|
||||
"rst": rst,
|
||||
}
|
||||
|
||||
def get_plugin_count_data(self, plugin: str) -> Optional[dict]:
|
||||
"""
|
||||
获取插件次数数据
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
if self.check_plugin_count_status(plugin):
|
||||
return self._data[plugin]
|
||||
return None
|
||||
|
||||
def get_plugin_data(self, plugin: str) -> Optional[dict]:
|
||||
"""
|
||||
获取单个模块限制数据
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
if self._data.get(plugin) is not None:
|
||||
return self._data.get(plugin)
|
||||
return None
|
||||
|
||||
def check_plugin_count_status(self, plugin: str) -> bool:
|
||||
"""
|
||||
检测插件是否有 次数 限制
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
return (
|
||||
plugin in self._data.keys()
|
||||
and self._data[plugin]["status"]
|
||||
and self._data[plugin]["max_count"] > 0
|
||||
)
|
||||
|
||||
def check(self, plugin: str, id_: int) -> bool:
|
||||
"""
|
||||
检查 count
|
||||
:param plugin: 模块名
|
||||
:param id_: 限制 id
|
||||
"""
|
||||
if self._daily_limiter.get(plugin):
|
||||
return self._daily_limiter[plugin].check(id_)
|
||||
return True
|
||||
|
||||
def increase(self, plugin: str, id_: int, num: int = 1):
|
||||
"""
|
||||
增加次数
|
||||
:param plugin: 模块名
|
||||
:param id_: cd 限制类型
|
||||
:param num: 增加次数
|
||||
:return:
|
||||
"""
|
||||
if self._daily_limiter.get(plugin):
|
||||
self._daily_limiter[plugin].increase(id_, num)
|
||||
|
||||
def reload_count_limit(self):
|
||||
"""
|
||||
加载 cd 限制器
|
||||
:return:
|
||||
"""
|
||||
for plugin in self._data:
|
||||
if self.check_plugin_count_status(plugin):
|
||||
self._daily_limiter[plugin] = DailyNumberLimiter(
|
||||
self.get_plugin_count_data(plugin)["max_count"]
|
||||
)
|
||||
logger.info(f"已成功加载 {len(self._daily_limiter)} 个Count限制.")
|
||||
|
||||
def reload(self):
|
||||
"""
|
||||
重载本地数据
|
||||
"""
|
||||
if self.file.exists():
|
||||
with open(self.file, "r", encoding="utf8") as f:
|
||||
self._data: dict = yaml.load(f)
|
||||
self._data = self._data["PluginCountLimit"]
|
||||
self.reload_count_limit()
|
||||
@@ -55,17 +55,11 @@ class Plugins2settingsManager(StaticData):
|
||||
if limit_superuser is not None
|
||||
else False,
|
||||
"cmd": cmd,
|
||||
"plugin_type": list(plugin_type if plugin_type is not None else ("normal",))
|
||||
"plugin_type": list(
|
||||
plugin_type if plugin_type is not None else ("normal",)
|
||||
),
|
||||
}
|
||||
|
||||
def remove_plugin_settings(self, plugin: str):
|
||||
"""
|
||||
删除一个插件设置
|
||||
:param plugin: 插件模块名称
|
||||
"""
|
||||
if self._data.get(plugin):
|
||||
del self._data[plugin]
|
||||
|
||||
def get_plugin_data(self, module: str) -> dict:
|
||||
"""
|
||||
通过模块名获取数据
|
||||
@@ -99,4 +93,4 @@ class Plugins2settingsManager(StaticData):
|
||||
if self.file.exists():
|
||||
with open(self.file, "r", encoding="utf8") as f:
|
||||
self._data: dict = yaml.load(f)
|
||||
self._data = self._data['PluginSettings']
|
||||
self._data = self._data["PluginSettings"]
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
from typing import Optional
|
||||
from pathlib import Path
|
||||
from .data_class import StaticData
|
||||
from . import group_manager
|
||||
|
||||
|
||||
class PluginsManager(StaticData):
|
||||
"""
|
||||
插件 管理器
|
||||
"""
|
||||
|
||||
def __init__(self, file: Path):
|
||||
super().__init__(file)
|
||||
if not self._data:
|
||||
self._data = {}
|
||||
|
||||
def add_plugin_data(
|
||||
self,
|
||||
module: str,
|
||||
plugin_name: str,
|
||||
*,
|
||||
status: Optional[bool] = True,
|
||||
error: Optional[bool] = False,
|
||||
block_type: Optional[str] = None,
|
||||
author: Optional[str] = None,
|
||||
version: Optional[int] = None,
|
||||
):
|
||||
"""
|
||||
添加插件数据
|
||||
:param module: 模块名称
|
||||
:param plugin_name: 插件名称
|
||||
:param status: 插件开关状态
|
||||
:param error: 加载状态
|
||||
:param block_type: 限制类型
|
||||
:param author: 作者
|
||||
:param version: 版本
|
||||
"""
|
||||
self._data[module] = {
|
||||
"plugin_name": plugin_name,
|
||||
"status": status,
|
||||
"error": error,
|
||||
"block_type": block_type,
|
||||
"author": author,
|
||||
"version": version,
|
||||
}
|
||||
|
||||
def block_plugin(
|
||||
self, module: str, group_id: Optional[int] = None, block_type: str = "all"
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
锁定插件
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param group_id: 群组,None时为超级用户禁用
|
||||
:param block_type: 限制类型
|
||||
"""
|
||||
self._set_plugin_status(module, "block", group_id, block_type)
|
||||
|
||||
def unblock_plugin(self, module: str, group_id: Optional[int] = None):
|
||||
"""
|
||||
说明:
|
||||
解锁插件
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param group_id: 群组
|
||||
"""
|
||||
self._set_plugin_status(module, "unblock", group_id)
|
||||
|
||||
def get_plugin_status(
|
||||
self, module: str, block_type: str = "all"
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
获取插件状态
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param block_type: 限制类型
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
if self._data[module]["block_type"] == "all" and block_type == "all":
|
||||
return False
|
||||
else:
|
||||
return not self._data[module]["block_type"] == block_type
|
||||
return True
|
||||
|
||||
def get_plugin_block_type(self, module: str) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取功能限制类型
|
||||
参数:
|
||||
:param module: 模块名称
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
return self._data[module]["block_type"]
|
||||
return ""
|
||||
|
||||
def get_plugin_error_status(self, module: str) -> bool:
|
||||
"""
|
||||
插件是否成功加载
|
||||
:param module: 模块名称
|
||||
"""
|
||||
if module not in self._data.keys():
|
||||
self.init_plugin(module)
|
||||
return self._data[module]["error"]
|
||||
|
||||
def _set_plugin_status(
|
||||
self,
|
||||
module: str,
|
||||
status: str,
|
||||
group_id: Optional[str],
|
||||
block_type: str = "all",
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
设置功能开关状态
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param status: 功能状态
|
||||
:param group_id: 群组
|
||||
:param block_type: 限制类型
|
||||
"""
|
||||
group_id = str(group_id) if group_id else group_id
|
||||
if module:
|
||||
if group_id:
|
||||
if status == "block":
|
||||
group_manager.block_plugin(f"{module}:super", int(group_id))
|
||||
else:
|
||||
group_manager.unblock_plugin(f"{module}:super", int(group_id))
|
||||
else:
|
||||
if module not in self._data.keys():
|
||||
self.init_plugin(module)
|
||||
if status == "block":
|
||||
self._data[module]["status"] = False
|
||||
self._data[module]["block_type"] = block_type
|
||||
else:
|
||||
if module in self._data.keys():
|
||||
self._data[module]["status"] = True
|
||||
self.save()
|
||||
|
||||
def init_plugin(self, module: str):
|
||||
"""
|
||||
初始化插件数据
|
||||
:param module: 模块名称
|
||||
"""
|
||||
if module not in self._data.keys():
|
||||
self._data[module] = {
|
||||
"plugin_name": module,
|
||||
"status": True,
|
||||
"error": False,
|
||||
"block_type": None,
|
||||
"author": None,
|
||||
"version": None,
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
from utils.manager.data_class import StaticData
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from services.log import logger
|
||||
from typing import Optional
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.utils import get_user_avatar
|
||||
from pathlib import Path
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
class RequestManager(StaticData):
|
||||
|
||||
"""
|
||||
好友请求/邀请请求 管理
|
||||
"""
|
||||
|
||||
def __init__(self, file: Optional[Path]):
|
||||
super().__init__(file)
|
||||
if not self._data:
|
||||
self._data = {"private": {}, "group": {}}
|
||||
|
||||
def add_request(
|
||||
self,
|
||||
id_: int,
|
||||
type_: str,
|
||||
flag: str,
|
||||
*,
|
||||
nickname: Optional[str] = None,
|
||||
level: Optional[int] = None,
|
||||
sex: Optional[str] = None,
|
||||
age: Optional[str] = None,
|
||||
from_: Optional[str] = "",
|
||||
comment: Optional[str] = None,
|
||||
invite_group: Optional[int] = None,
|
||||
group_name: Optional[str] = None,
|
||||
):
|
||||
"""
|
||||
添加一个请求
|
||||
:param id_: id,用户id或群id
|
||||
:param type_: 类型,private 或 group
|
||||
:param flag: event.flag
|
||||
:param nickname: 用户昵称
|
||||
:param level: 等级
|
||||
:param sex: 性别
|
||||
:param age: 年龄
|
||||
:param from_: 请求来自
|
||||
:param comment: 附加消息
|
||||
:param invite_group: 邀请群聊
|
||||
:param group_name: 群聊名称
|
||||
"""
|
||||
self._data[type_][str(len(self._data[type_].keys()))] = {
|
||||
"id": id_,
|
||||
"flag": flag,
|
||||
"nickname": nickname,
|
||||
"level": level,
|
||||
"sex": sex,
|
||||
"age": age,
|
||||
"from": from_,
|
||||
"comment": comment,
|
||||
"invite_group": invite_group,
|
||||
"group_name": group_name,
|
||||
}
|
||||
self.save()
|
||||
|
||||
def remove_request(self, type_: str, id_: int):
|
||||
"""
|
||||
删除一个请求数据
|
||||
:param type_: 类型
|
||||
:param id_: id,user_id 或 group_id
|
||||
"""
|
||||
for x in self._data[type_].keys():
|
||||
if self._data[type_][x].get("id") == id_:
|
||||
del self._data[type_][x]
|
||||
break
|
||||
self.save()
|
||||
|
||||
async def approve(self, bot: Bot, id_: int, type_: str) -> Optional[int]:
|
||||
"""
|
||||
同意请求
|
||||
:param bot: Bot
|
||||
:param id_: id
|
||||
:param type_: 类型,private 或 group
|
||||
"""
|
||||
return await self._set_add_request(bot, id_, type_, True)
|
||||
|
||||
async def refused(self, bot: Bot, id_: int, type_: str) -> Optional[int]:
|
||||
"""
|
||||
拒绝请求
|
||||
:param bot: Bot
|
||||
:param id_: id
|
||||
:param type_: 类型,private 或 group
|
||||
"""
|
||||
return await self._set_add_request(bot, id_, type_, False)
|
||||
|
||||
def clear(self):
|
||||
"""
|
||||
清空所有请求信息,无视请求
|
||||
"""
|
||||
self._data = {"private": {}, "group": {}}
|
||||
self.save()
|
||||
|
||||
def set_group_name(self, group_name: str, group_id: int):
|
||||
"""
|
||||
设置群聊名称
|
||||
:param group_name: 名称
|
||||
:param group_id: id
|
||||
"""
|
||||
for id_ in self._data["group"].keys():
|
||||
if self._data["group"][id_]["invite_group"] == group_id:
|
||||
self._data["group"][id_]["group_name"] = group_name
|
||||
break
|
||||
self.save()
|
||||
|
||||
async def show(self, type_: str) -> Optional[str]:
|
||||
"""
|
||||
请求可视化
|
||||
"""
|
||||
data = self._data[type_]
|
||||
if not data:
|
||||
return None
|
||||
img_list = []
|
||||
id_list = list(data.keys())
|
||||
id_list.reverse()
|
||||
for id_ in id_list:
|
||||
age = data[id_]["age"]
|
||||
nickname = data[id_]["nickname"]
|
||||
comment = data[id_]["comment"] if type_ == "private" else ""
|
||||
from_ = data[id_]["from"]
|
||||
sex = data[id_]["sex"]
|
||||
ava = CreateImg(
|
||||
80, 80, background=BytesIO(await get_user_avatar(data[id_]["id"]))
|
||||
)
|
||||
ava.circle()
|
||||
age_bk = CreateImg(
|
||||
len(str(age)) * 10 - 5,
|
||||
15,
|
||||
color="#04CAF7" if sex == "male" else "#F983C1",
|
||||
)
|
||||
age_bk.text((3, 1), f"{age}", fill=(255, 255, 255))
|
||||
x = CreateImg(
|
||||
90, 32, font_size=15, color="#EEEFF4", font="HYWenHei-85W.ttf"
|
||||
)
|
||||
x.text((0, 0), "同意/拒绝", center_type="center")
|
||||
x.circle_corner(10)
|
||||
A = CreateImg(500, 100, font_size=24, font="msyh.ttf")
|
||||
A.paste(ava, (15, 0), alpha=True, center_type="by_height")
|
||||
A.text((120, 15), nickname)
|
||||
A.paste(age_bk, (120, 50), True)
|
||||
A.paste(
|
||||
CreateImg(
|
||||
200,
|
||||
0,
|
||||
font_size=12,
|
||||
plain_text=f"对方留言:{comment}",
|
||||
font_color=(140, 140, 143),
|
||||
),
|
||||
(120 + age_bk.w + 10, 49),
|
||||
True,
|
||||
)
|
||||
if type_ == "private":
|
||||
A.paste(
|
||||
CreateImg(
|
||||
200,
|
||||
0,
|
||||
font_size=12,
|
||||
plain_text=f"来源:{from_}",
|
||||
font_color=(140, 140, 143),
|
||||
),
|
||||
(120, 70),
|
||||
True,
|
||||
)
|
||||
else:
|
||||
A.paste(
|
||||
CreateImg(
|
||||
200,
|
||||
0,
|
||||
font_size=12,
|
||||
plain_text=f"邀请你加入:{data[id_]['group_name']}({data[id_]['invite_group']})",
|
||||
font_color=(140, 140, 143),
|
||||
),
|
||||
(120, 70),
|
||||
True,
|
||||
)
|
||||
A.paste(x, (380, 35), True)
|
||||
A.paste(
|
||||
CreateImg(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"id:{id_}",
|
||||
font_size=13,
|
||||
font_color=(140, 140, 143),
|
||||
),
|
||||
(400, 10),
|
||||
True,
|
||||
)
|
||||
img_list.append(A)
|
||||
A = CreateImg(500, len(img_list) * 100, 500, 100)
|
||||
for img in img_list:
|
||||
A.paste(img)
|
||||
bk = CreateImg(A.w, A.h + 50, color="#F8F9FB", font_size=20)
|
||||
bk.paste(A, (0, 50))
|
||||
bk.text(
|
||||
(15, 13), "好友请求" if type_ == "private" else "群聊请求", fill=(140, 140, 143)
|
||||
)
|
||||
return bk.pic2bs4()
|
||||
|
||||
async def _set_add_request(
|
||||
self, bot: Bot, id_: int, type_: str, approve: bool
|
||||
) -> Optional[int]:
|
||||
"""
|
||||
处理请求
|
||||
:param bot: Bot
|
||||
:param id_: id
|
||||
:param type_: 类型,private 或 group
|
||||
:param approve: 是否同意
|
||||
"""
|
||||
id_ = str(id_)
|
||||
if id_ in self._data[type_]:
|
||||
try:
|
||||
if type_ == "private":
|
||||
await bot.set_friend_add_request(
|
||||
flag=self._data[type_][id_]["flag"], approve=approve
|
||||
)
|
||||
rid = self._data[type_][id_]["id"]
|
||||
else:
|
||||
await bot.set_group_add_request(
|
||||
flag=self._data[type_][id_]["flag"],
|
||||
sub_type="invite",
|
||||
approve=approve,
|
||||
)
|
||||
rid = self._data[type_][id_]["invite_group"]
|
||||
except ActionFailed:
|
||||
logger.info(
|
||||
f"同意{self._data[type_][id_]['nickname']}({self._data[type_][id_]['id']})"
|
||||
f"的{'好友' if type_ == 'private' else '入群'}请求失败了..."
|
||||
)
|
||||
return None
|
||||
logger.info(
|
||||
f"同意{self._data[type_][id_]['nickname']}({self._data[type_][id_]['id']})"
|
||||
f"的{'好友' if type_ == 'private' else '入群'}请求..."
|
||||
)
|
||||
del self._data[type_][id_]
|
||||
self.save()
|
||||
return rid
|
||||
return None
|
||||
@@ -0,0 +1,109 @@
|
||||
from typing import Union, List, Optional
|
||||
from .data_class import StaticData
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import YAML
|
||||
from services.log import logger
|
||||
import shutil
|
||||
|
||||
yaml = YAML(typ="safe")
|
||||
|
||||
|
||||
class ResourcesManager(StaticData):
|
||||
"""
|
||||
插件配置 与 资源 管理器
|
||||
"""
|
||||
|
||||
def __init__(self, file: Path):
|
||||
self.file = file
|
||||
super().__init__(file)
|
||||
self._temp_dir = []
|
||||
self._abspath = Path()
|
||||
|
||||
def add_resource(
|
||||
self, module: str, source_file: Union[str, Path], move_file: Union[str, Path]
|
||||
):
|
||||
"""
|
||||
添加一个资源移动路劲
|
||||
:param module: 模块名
|
||||
:param source_file: 源文件路径
|
||||
:param move_file: 移动路径
|
||||
"""
|
||||
if isinstance(source_file, Path):
|
||||
source_file = str(source_file.absolute())
|
||||
if isinstance(move_file, Path):
|
||||
move_file = move_file.absolute()
|
||||
if module not in self._data.keys():
|
||||
self._data[module] = {source_file: move_file}
|
||||
else:
|
||||
self._data[module][source_file] = move_file
|
||||
|
||||
def remove_resource(self, module: str, source_file: Optional[Union[str, Path]] = None):
|
||||
"""
|
||||
删除一个资源路径
|
||||
:param module: 模块
|
||||
:param source_file: 源文件路径
|
||||
"""
|
||||
if not source_file:
|
||||
if module in self._data.keys():
|
||||
for x in self._data[module].keys():
|
||||
move_file = Path(self._data[module][x])
|
||||
if move_file.exists():
|
||||
shutil.rmtree(move_file.absolute(), ignore_errors=True)
|
||||
logger.info(f"已清除插件 {module} 资源路径:{self._data[module][x]}")
|
||||
del self._data[module][x]
|
||||
else:
|
||||
if isinstance(source_file, Path):
|
||||
source_file = str(source_file.absolute())
|
||||
if source_file:
|
||||
if module in self._data.keys() and source_file in self._data[module].keys():
|
||||
move_file = Path(self._data[module][source_file])
|
||||
if move_file.exists():
|
||||
shutil.rmtree(move_file.absolute(), ignore_errors=True)
|
||||
del self._data[module][source_file]
|
||||
self.save()
|
||||
|
||||
def start_move(self):
|
||||
"""
|
||||
开始移动路径
|
||||
"""
|
||||
for module in self._data.keys():
|
||||
for source_path in self._data[module].keys():
|
||||
move_path = Path(self._data[module][source_path])
|
||||
source_path = Path(source_path)
|
||||
file_name = source_path.name
|
||||
move_path = move_path / file_name
|
||||
move_path.mkdir(exist_ok=True, parents=True)
|
||||
try:
|
||||
if source_path.exists():
|
||||
if move_path.exists():
|
||||
shutil.rmtree(str(move_path.absolute()), ignore_errors=True)
|
||||
shutil.move(str(source_path.absolute()), str(move_path.absolute()))
|
||||
logger.info(
|
||||
f"移动资源文件路径 {source_path.absolute()} >>> {move_path.absolute()}"
|
||||
)
|
||||
elif not move_path.exists():
|
||||
logger.warning(
|
||||
f"移动资源路径文件{source_path.absolute()} >>>"
|
||||
f" {move_path.absolute()} 失败,源文件不存在.."
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"移动资源路径文件{source_path.absolute()} >>>"
|
||||
f" {move_path.absolute()}失败,{type(e)}:{e}"
|
||||
)
|
||||
self.save()
|
||||
|
||||
def add_temp_dir(self, path: Union[str, Path]):
|
||||
"""
|
||||
添加临时清理文件夹
|
||||
:param path: 路径
|
||||
"""
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
self._temp_dir.append(path)
|
||||
|
||||
def get_temp_data_dir(self) -> List[Path]:
|
||||
"""
|
||||
获取临时文件文件夹
|
||||
"""
|
||||
return self._temp_dir
|
||||
@@ -1,8 +1,8 @@
|
||||
from typing import Tuple, Union, Dict
|
||||
from nonebot.adapters.cqhttp import MessageEvent, PrivateMessageEvent, GroupMessageEvent
|
||||
|
||||
|
||||
class WithdrawMessageManager:
|
||||
|
||||
def __init__(self):
|
||||
self.data = []
|
||||
|
||||
@@ -14,7 +14,7 @@ class WithdrawMessageManager:
|
||||
:param message_data: 撤回消息id和时间
|
||||
"""
|
||||
if isinstance(message_data[0], dict):
|
||||
message_data = (message_data[0]['message_id'], message_data[1])
|
||||
message_data = (message_data[0]["message_id"], message_data[1])
|
||||
self.data.append(message_data)
|
||||
|
||||
def remove(self, message_data: Tuple[int, int]):
|
||||
@@ -26,3 +26,19 @@ class WithdrawMessageManager:
|
||||
"""
|
||||
self.data.remove(message_data)
|
||||
|
||||
def withdraw_message(
|
||||
self, event: MessageEvent, id_: Union[int, Dict[str, int]], conditions: Tuple[int, int]
|
||||
):
|
||||
"""
|
||||
便捷判断消息撤回
|
||||
:param event: event
|
||||
:param id_: 消息id 或 send 返回的字典
|
||||
:param conditions: 判断条件
|
||||
"""
|
||||
if conditions[0]:
|
||||
if (
|
||||
(conditions[1] == 0 and isinstance(event, PrivateMessageEvent))
|
||||
or (conditions[1] == 1 and isinstance(event, GroupMessageEvent))
|
||||
or conditions[1] == 2
|
||||
):
|
||||
self.append((id_, conditions[0]))
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
from configs.path_config import IMAGE_PATH, VOICE_PATH
|
||||
from nonebot.adapters.cqhttp.message import MessageSegment
|
||||
from configs.config import NICKNAME
|
||||
from services.log import logger
|
||||
from typing import Union
|
||||
from typing import Union, List
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
|
||||
def image(
|
||||
img_name: Union[str, Path] = None, path: str = None, abspath: str = None, b64: str = None
|
||||
img_name: Union[str, Path] = None,
|
||||
path: str = None,
|
||||
abspath: str = None,
|
||||
b64: str = None,
|
||||
) -> Union[MessageSegment, str]:
|
||||
"""
|
||||
说明:
|
||||
@@ -153,3 +157,27 @@ def poke(qq: int) -> MessageSegment:
|
||||
:param qq: qq号
|
||||
"""
|
||||
return MessageSegment("poke", {"qq": qq})
|
||||
|
||||
|
||||
def custom_forward_msg(
|
||||
msg_list: List[str], uin: Union[int, str], name: str = f"这里是{NICKNAME}"
|
||||
) -> List[dict]:
|
||||
"""
|
||||
生成自定义合并消息
|
||||
:param msg_list: 消息列表
|
||||
:param uin: 发送者 QQ
|
||||
:param name: 自定义名称
|
||||
"""
|
||||
uin = int(uin)
|
||||
mes_list = []
|
||||
for _message in msg_list:
|
||||
data = {
|
||||
"type": "node",
|
||||
"data": {
|
||||
"name": name,
|
||||
"uin": f"{uin}",
|
||||
"content": _message,
|
||||
},
|
||||
}
|
||||
mes_list.append(data)
|
||||
return mes_list
|
||||
|
||||
+28
-35
@@ -1,15 +1,14 @@
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime
|
||||
from collections import defaultdict
|
||||
from nonebot import require
|
||||
from configs.path_config import TEXT_PATH
|
||||
from configs.config import SYSTEM_PROXY
|
||||
from typing import List, Union, Optional, Type
|
||||
from typing import List, Union, Optional, Type, Any
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from nonebot.matcher import matchers, Matcher
|
||||
import httpx
|
||||
import nonebot
|
||||
import pytz
|
||||
import pypinyin
|
||||
import aiohttp
|
||||
import time
|
||||
|
||||
try:
|
||||
@@ -30,10 +29,10 @@ class CountLimiter:
|
||||
self.count = defaultdict(int)
|
||||
self.max_count = max_count
|
||||
|
||||
def add(self, key: Union[str, int, float]):
|
||||
def add(self, key: Any):
|
||||
self.count[key] += 1
|
||||
|
||||
def check(self, key: Union[str, int, float]) -> bool:
|
||||
def check(self, key: Any) -> bool:
|
||||
if self.count[key] >= self.max_count:
|
||||
self.count[key] = 0
|
||||
return True
|
||||
@@ -49,14 +48,14 @@ class UserBlockLimiter:
|
||||
self.flag_data = defaultdict(bool)
|
||||
self.time = time.time()
|
||||
|
||||
def set_true(self, key: Union[str, int, float]):
|
||||
def set_true(self, key: Any):
|
||||
self.time = time.time()
|
||||
self.flag_data[key] = True
|
||||
|
||||
def set_false(self, key: Union[str, int, float]):
|
||||
def set_false(self, key: Any):
|
||||
self.flag_data[key] = False
|
||||
|
||||
def check(self, key: Union[str, int, float]) -> bool:
|
||||
def check(self, key: Any) -> bool:
|
||||
if time.time() - self.time > 30:
|
||||
self.set_false(key)
|
||||
return False
|
||||
@@ -72,15 +71,15 @@ class FreqLimiter:
|
||||
self.next_time = defaultdict(float)
|
||||
self.default_cd = default_cd_seconds
|
||||
|
||||
def check(self, key: Union[str, int, float]) -> bool:
|
||||
def check(self, key: Any) -> bool:
|
||||
return time.time() >= self.next_time[key]
|
||||
|
||||
def start_cd(self, key: Union[str, int, float], cd_time: int = 0):
|
||||
def start_cd(self, key: Any, cd_time: int = 0):
|
||||
self.next_time[key] = time.time() + (
|
||||
cd_time if cd_time > 0 else self.default_cd
|
||||
)
|
||||
|
||||
def left_time(self, key: Union[str, int, float]) -> float:
|
||||
def left_time(self, key: Any) -> float:
|
||||
return self.next_time[key] - time.time()
|
||||
|
||||
|
||||
@@ -131,8 +130,7 @@ class DailyNumberLimiter:
|
||||
self.max = max_num
|
||||
|
||||
def check(self, key) -> bool:
|
||||
now = datetime.now(self.tz)
|
||||
day = (now - timedelta(hours=5)).day
|
||||
day = datetime.now(self.tz).day
|
||||
if day != self.today:
|
||||
self.today = day
|
||||
self.count.clear()
|
||||
@@ -282,18 +280,6 @@ def get_message_json(data: str) -> List[dict]:
|
||||
return []
|
||||
|
||||
|
||||
# 获取文本加密后的cookie
|
||||
def get_cookie_text(cookie_name: str) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取 txt/cookie 目录下指定 cookie 的内容
|
||||
参数:
|
||||
:param cookie_name: cookie文件名称
|
||||
"""
|
||||
with open(TEXT_PATH + "cookie/" + cookie_name + ".txt", "r") as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
def get_local_proxy():
|
||||
"""
|
||||
说明:
|
||||
@@ -302,7 +288,7 @@ def get_local_proxy():
|
||||
return SYSTEM_PROXY if SYSTEM_PROXY else None
|
||||
|
||||
|
||||
def is_Chinese(word: str) -> bool:
|
||||
def is_chinese(word: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
判断字符串是否为纯中文
|
||||
@@ -315,7 +301,7 @@ def is_Chinese(word: str) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
async def user_avatar(qq: int) -> bytes:
|
||||
async def get_user_avatar(qq: int) -> bytes:
|
||||
"""
|
||||
说明:
|
||||
快捷获取用户头像
|
||||
@@ -323,12 +309,15 @@ async def user_avatar(qq: int) -> bytes:
|
||||
:param qq: qq号
|
||||
"""
|
||||
url = f"http://q1.qlogo.cn/g?b=qq&nk={qq}&s=160"
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, proxy=get_local_proxy(), timeout=5) as response:
|
||||
return await response.read()
|
||||
async with httpx.AsyncClient() as client:
|
||||
for _ in range(3):
|
||||
try:
|
||||
return (await client.get(url)).content
|
||||
except TimeoutError:
|
||||
pass
|
||||
|
||||
|
||||
async def group_avatar(group_id: int) -> bytes:
|
||||
async def get_group_avatar(group_id: int) -> bytes:
|
||||
"""
|
||||
说明:
|
||||
快捷获取用群头像
|
||||
@@ -336,9 +325,12 @@ async def group_avatar(group_id: int) -> bytes:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
url = f"http://p.qlogo.cn/gh/{group_id}/{group_id}/640/"
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, proxy=get_local_proxy(), timeout=5) as response:
|
||||
return await response.read()
|
||||
async with httpx.AsyncClient() as client:
|
||||
for _ in range(3):
|
||||
try:
|
||||
return (await client.get(url)).content
|
||||
except TimeoutError:
|
||||
pass
|
||||
|
||||
|
||||
def cn2py(word: str) -> str:
|
||||
@@ -368,3 +360,4 @@ def change_picture_links(url: str, mode: str):
|
||||
img_type = img_sp[1]
|
||||
url = url.replace("original", "master") + f"_master1200.{img_type}"
|
||||
return url
|
||||
|
||||
|
||||
Reference in New Issue
Block a user