update 0.0.6.0

This commit is contained in:
HibiKier
2021-11-04 16:11:50 +08:00
parent 21c1950898
commit 19d650c35d
217 changed files with 8213 additions and 5697 deletions
+49 -12
View File
@@ -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
View File
@@ -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
+32
View File
@@ -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()
+27 -10
View File
@@ -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
+65
View File
@@ -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
#
#
#
+21 -8
View File
@@ -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]
+62 -86
View File
@@ -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
+17 -20
View File
@@ -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()
+19 -20
View File
@@ -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()
+134
View File
@@ -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()
+4 -10
View File
@@ -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"]
+154
View File
@@ -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,
}
+246
View File
@@ -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
+109
View File
@@ -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
+18 -2
View File
@@ -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]))
+30 -2
View File
@@ -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
View File
@@ -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