2021-12-16 11:16:28 +08:00
|
|
|
|
from utils.image_utils import BuildImage
|
2021-11-23 21:44:59 +08:00
|
|
|
|
from configs.path_config import IMAGE_PATH
|
|
|
|
|
|
from utils.manager import (
|
|
|
|
|
|
plugins2settings_manager,
|
|
|
|
|
|
admin_manager,
|
|
|
|
|
|
plugins_manager,
|
|
|
|
|
|
group_manager,
|
|
|
|
|
|
)
|
|
|
|
|
|
from typing import Optional
|
|
|
|
|
|
from services.log import logger
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
from utils.utils import get_matchers
|
|
|
|
|
|
import random
|
|
|
|
|
|
import asyncio
|
|
|
|
|
|
import nonebot
|
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
random_bk_path = Path(IMAGE_PATH) / "background" / "help" / "simple_help"
|
|
|
|
|
|
|
|
|
|
|
|
background = Path(IMAGE_PATH) / "background" / "0.png"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def create_help_img(
|
|
|
|
|
|
group_id: Optional[int], help_image: Path, simple_help_image: Path
|
|
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
生成帮助图片
|
|
|
|
|
|
:param group_id: 群号
|
|
|
|
|
|
:param help_image: 图片路径
|
|
|
|
|
|
:param simple_help_image: 简易帮助图片路径
|
|
|
|
|
|
"""
|
|
|
|
|
|
return await asyncio.get_event_loop().run_in_executor(
|
|
|
|
|
|
None, _create_help_img, group_id, help_image, simple_help_image
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _create_help_img(
|
|
|
|
|
|
group_id: Optional[int], help_image: Path, simple_help_image: Path
|
|
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
生成帮助图片
|
|
|
|
|
|
:param group_id: 群号
|
|
|
|
|
|
:param help_image: 图片路径
|
|
|
|
|
|
:param simple_help_image: 简易帮助图片路径
|
|
|
|
|
|
"""
|
|
|
|
|
|
_matchers = get_matchers()
|
|
|
|
|
|
width = 0
|
|
|
|
|
|
matchers_data = {}
|
|
|
|
|
|
_des_tmp = {}
|
|
|
|
|
|
_plugin_name_tmp = []
|
|
|
|
|
|
_tmp = []
|
2021-12-16 11:16:28 +08:00
|
|
|
|
tmp_img = BuildImage(0, 0, plain_text="1", font_size=24)
|
2021-11-23 21:44:59 +08:00
|
|
|
|
font_height = tmp_img.h
|
|
|
|
|
|
# 插件分类
|
|
|
|
|
|
for matcher in _matchers:
|
|
|
|
|
|
plugin_name = None
|
|
|
|
|
|
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
|
|
|
|
|
_module = _plugin.module
|
|
|
|
|
|
try:
|
|
|
|
|
|
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
|
|
|
|
|
try:
|
|
|
|
|
|
plugin_des = _module.__getattribute__("__plugin_des__")
|
|
|
|
|
|
except AttributeError:
|
|
|
|
|
|
plugin_des = "_"
|
|
|
|
|
|
if (
|
|
|
|
|
|
"[hidden]" in plugin_name.lower()
|
|
|
|
|
|
or "[admin]" in plugin_name.lower()
|
|
|
|
|
|
or "[superuser]" in plugin_name.lower()
|
|
|
|
|
|
or plugin_name in _plugin_name_tmp
|
|
|
|
|
|
or plugin_name == "帮助"
|
|
|
|
|
|
):
|
|
|
|
|
|
continue
|
|
|
|
|
|
plugin_type = ("normal",)
|
|
|
|
|
|
text_type = 0
|
|
|
|
|
|
if plugins2settings_manager.get(
|
|
|
|
|
|
matcher.module
|
|
|
|
|
|
) and plugins2settings_manager[matcher.module].get("plugin_type"):
|
|
|
|
|
|
plugin_type = tuple(
|
|
|
|
|
|
plugins2settings_manager.get_plugin_data(matcher.module)[
|
|
|
|
|
|
"plugin_type"
|
|
|
|
|
|
]
|
|
|
|
|
|
)
|
|
|
|
|
|
else:
|
|
|
|
|
|
try:
|
|
|
|
|
|
plugin_type = _module.__getattribute__("__plugin_type__")
|
|
|
|
|
|
except AttributeError:
|
|
|
|
|
|
pass
|
|
|
|
|
|
if len(plugin_type) > 1:
|
|
|
|
|
|
try:
|
|
|
|
|
|
text_type = int(plugin_type[1])
|
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
|
logger.warning(f"生成列向帮助排列失败 {plugin_name}: {type(e)}: {e}")
|
|
|
|
|
|
plugin_type = plugin_type[0]
|
|
|
|
|
|
else:
|
|
|
|
|
|
plugin_type = plugin_type[0]
|
|
|
|
|
|
try:
|
|
|
|
|
|
plugin_cmd = _module.__getattribute__("__plugin_cmd__")
|
|
|
|
|
|
plugin_cmd = [x for x in plugin_cmd if "[_superuser]" not in x]
|
|
|
|
|
|
except AttributeError:
|
|
|
|
|
|
plugin_cmd = []
|
|
|
|
|
|
if plugin_type not in matchers_data.keys():
|
|
|
|
|
|
matchers_data[plugin_type] = {}
|
|
|
|
|
|
if plugin_des in _des_tmp.keys():
|
|
|
|
|
|
try:
|
|
|
|
|
|
matchers_data[plugin_type][_des_tmp[plugin_des]]["cmd"] = (
|
|
|
|
|
|
matchers_data[plugin_type][_des_tmp[plugin_des]]["cmd"]
|
|
|
|
|
|
+ plugin_cmd
|
|
|
|
|
|
)
|
|
|
|
|
|
except KeyError as e:
|
|
|
|
|
|
logger.warning(f"{type(e)}: {e}")
|
|
|
|
|
|
else:
|
|
|
|
|
|
matchers_data[plugin_type][plugin_name] = {
|
2022-01-16 14:52:50 +08:00
|
|
|
|
"modules": matcher.module,
|
2021-11-23 21:44:59 +08:00
|
|
|
|
"des": plugin_des,
|
|
|
|
|
|
"cmd": plugin_cmd,
|
|
|
|
|
|
"text_type": text_type,
|
|
|
|
|
|
}
|
|
|
|
|
|
try:
|
|
|
|
|
|
if text_type == 0:
|
|
|
|
|
|
x = tmp_img.getsize(
|
|
|
|
|
|
f'{plugin_name}: {matchers_data[plugin_type][plugin_name]["des"]} ->'
|
|
|
|
|
|
+ " / ".join(matchers_data[plugin_type][plugin_name]["cmd"])
|
|
|
|
|
|
)[0]
|
|
|
|
|
|
width = width if width > x else x
|
|
|
|
|
|
except KeyError:
|
|
|
|
|
|
pass
|
|
|
|
|
|
if plugin_des not in _des_tmp:
|
|
|
|
|
|
_des_tmp[plugin_des] = plugin_name
|
|
|
|
|
|
except AttributeError as e:
|
|
|
|
|
|
if plugin_name not in _plugin_name_tmp:
|
|
|
|
|
|
logger.warning(f"获取功能 {matcher.module}: {plugin_name} 设置失败...e:{e}")
|
|
|
|
|
|
if plugin_name not in _plugin_name_tmp:
|
|
|
|
|
|
_plugin_name_tmp.append(plugin_name)
|
|
|
|
|
|
help_img_list = []
|
|
|
|
|
|
simple_help_img_list = []
|
|
|
|
|
|
types = list(matchers_data.keys())
|
|
|
|
|
|
types.sort()
|
|
|
|
|
|
ix = 0
|
|
|
|
|
|
# 详细帮助
|
|
|
|
|
|
for type_ in types:
|
|
|
|
|
|
keys = list(matchers_data[type_].keys())
|
|
|
|
|
|
keys.sort()
|
|
|
|
|
|
help_str = f"{type_ if type_ != 'normal' else '功能'}:\n\n"
|
|
|
|
|
|
simple_help_str = f"{type_ if type_ != 'normal' else '功能'}:\n\n"
|
|
|
|
|
|
for i, k in enumerate(keys):
|
|
|
|
|
|
# 禁用flag
|
|
|
|
|
|
flag = True
|
|
|
|
|
|
if plugins_manager.get_plugin_status(
|
2022-01-16 14:52:50 +08:00
|
|
|
|
matchers_data[type_][k]["modules"], "all"
|
2021-11-23 21:44:59 +08:00
|
|
|
|
):
|
|
|
|
|
|
flag = False
|
|
|
|
|
|
if group_id:
|
|
|
|
|
|
flag = flag and plugins_manager.get_plugin_status(
|
2022-01-16 14:52:50 +08:00
|
|
|
|
matchers_data[type_][k]["modules"], "group"
|
2021-11-23 21:44:59 +08:00
|
|
|
|
)
|
|
|
|
|
|
simple_help_str += (
|
|
|
|
|
|
f"{i+1}.{k}<|_|~|>"
|
2022-01-16 14:52:50 +08:00
|
|
|
|
f"{group_manager.get_plugin_status(matchers_data[type_][k]['modules'], group_id) if group_id else '_'}|"
|
2021-11-23 21:44:59 +08:00
|
|
|
|
f"{flag}\n"
|
|
|
|
|
|
)
|
|
|
|
|
|
if matchers_data[type_][k]["text_type"] == 1:
|
|
|
|
|
|
_x = tmp_img.getsize(
|
|
|
|
|
|
f"{i+1}".rjust(5)
|
|
|
|
|
|
+ f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
|
|
|
|
|
|
)[0]
|
|
|
|
|
|
_str = (
|
|
|
|
|
|
f"{i+1}".rjust(5)
|
|
|
|
|
|
+ f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
|
|
|
|
|
|
)
|
|
|
|
|
|
_str += matchers_data[type_][k]["cmd"][0] + "\n"
|
|
|
|
|
|
for c in matchers_data[type_][k]["cmd"][1:]:
|
|
|
|
|
|
_str += "".rjust(int(_x * 0.125) + 1) + f"{c}\n"
|
|
|
|
|
|
help_str += _str
|
|
|
|
|
|
else:
|
|
|
|
|
|
help_str += (
|
|
|
|
|
|
f"{i+1}".rjust(5)
|
|
|
|
|
|
+ f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
|
|
|
|
|
|
+ " / ".join(matchers_data[type_][k]["cmd"])
|
|
|
|
|
|
+ "\n"
|
|
|
|
|
|
)
|
|
|
|
|
|
height = len(help_str.split("\n")) * (font_height + 5)
|
|
|
|
|
|
simple_height = len(simple_help_str.split("\n")) * (font_height + 5)
|
2021-12-16 11:16:28 +08:00
|
|
|
|
A = BuildImage(
|
2021-11-23 21:44:59 +08:00
|
|
|
|
width + 150, height, font_size=24, color="white" if not ix % 2 else "black"
|
|
|
|
|
|
)
|
|
|
|
|
|
A.text((10, 10), help_str, (255, 255, 255) if ix % 2 else (0, 0, 0))
|
|
|
|
|
|
# 生成各个分类的插件简易帮助图片
|
|
|
|
|
|
simple_width = 0
|
|
|
|
|
|
for x in [
|
|
|
|
|
|
tmp_img.getsize(x.split("<|_|~|>")[0])[0]
|
|
|
|
|
|
for x in simple_help_str.split("\n")
|
|
|
|
|
|
]:
|
|
|
|
|
|
simple_width = simple_width if simple_width > x else x
|
2021-12-16 11:16:28 +08:00
|
|
|
|
bk = BuildImage(simple_width + 20, simple_height, font_size=24, color="#6495ED")
|
|
|
|
|
|
B = BuildImage(
|
2021-11-23 21:44:59 +08:00
|
|
|
|
simple_width + 20,
|
|
|
|
|
|
simple_height,
|
|
|
|
|
|
font_size=24,
|
|
|
|
|
|
color="white" if not ix % 2 else "black",
|
|
|
|
|
|
)
|
|
|
|
|
|
# 切分,判断插件开关状态
|
|
|
|
|
|
_s_height = 10
|
|
|
|
|
|
for _s in simple_help_str.split("\n"):
|
|
|
|
|
|
text_color = (255, 255, 255) if ix % 2 else (0, 0, 0)
|
|
|
|
|
|
_line_flag = False
|
|
|
|
|
|
if "<|_|~|>" in _s:
|
|
|
|
|
|
_x = _s.split("<|_|~|>")
|
|
|
|
|
|
_flag_sp = _x[-1].split("|")
|
|
|
|
|
|
if group_id:
|
|
|
|
|
|
if _flag_sp[0].lower() != "true":
|
|
|
|
|
|
text_color = (252, 75, 13)
|
|
|
|
|
|
if _flag_sp[1].lower() == "true":
|
|
|
|
|
|
_line_flag = True
|
|
|
|
|
|
_s = _x[0]
|
|
|
|
|
|
B.text((10, _s_height), _s, text_color)
|
|
|
|
|
|
if _line_flag:
|
|
|
|
|
|
B.line(
|
|
|
|
|
|
(
|
|
|
|
|
|
7,
|
|
|
|
|
|
_s_height + int(B.getsize(_s)[1] / 2) + 2,
|
|
|
|
|
|
B.getsize(_s)[0] + 11,
|
|
|
|
|
|
_s_height + int(B.getsize(_s)[1] / 2) + 2,
|
|
|
|
|
|
),
|
|
|
|
|
|
(236, 66, 7),
|
|
|
|
|
|
3,
|
|
|
|
|
|
)
|
|
|
|
|
|
_s_height += B.getsize("1")[1] + 5
|
|
|
|
|
|
# B.text((10, 10), simple_help_str, (255, 255, 255) if ix % 2 else (0, 0, 0))
|
|
|
|
|
|
bk.paste(B, center_type="center")
|
|
|
|
|
|
bk.transparent(2)
|
|
|
|
|
|
ix += 1
|
|
|
|
|
|
help_img_list.append(A)
|
|
|
|
|
|
simple_help_img_list.append(bk)
|
|
|
|
|
|
height = 0
|
|
|
|
|
|
for img in help_img_list:
|
|
|
|
|
|
height += img.h
|
|
|
|
|
|
if not group_id:
|
2021-12-16 11:16:28 +08:00
|
|
|
|
A = BuildImage(width + 150, height + 50, font_size=24)
|
2021-11-23 21:44:59 +08:00
|
|
|
|
A.text(
|
|
|
|
|
|
(10, 10), '* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" "功能名: 功能简介 -> 指令\n\n'
|
|
|
|
|
|
)
|
|
|
|
|
|
current_height = 50
|
|
|
|
|
|
for img in help_img_list:
|
|
|
|
|
|
A.paste(img, (0, current_height))
|
|
|
|
|
|
current_height += img.h
|
|
|
|
|
|
A.save(help_image)
|
|
|
|
|
|
# 详细帮助生成完毕
|
|
|
|
|
|
# 简易帮助图片合成
|
|
|
|
|
|
height = 0
|
|
|
|
|
|
width = 0
|
|
|
|
|
|
for img in simple_help_img_list:
|
|
|
|
|
|
if img.h > height:
|
|
|
|
|
|
height = img.h
|
|
|
|
|
|
width += img.w + 10
|
2021-12-16 11:16:28 +08:00
|
|
|
|
B = BuildImage(width + 100, height + 250, font_size=24)
|
2021-11-23 21:44:59 +08:00
|
|
|
|
width, _ = get_max_width_or_paste(simple_help_img_list, B)
|
|
|
|
|
|
bk = None
|
|
|
|
|
|
random_bk = os.listdir(random_bk_path)
|
|
|
|
|
|
if random_bk:
|
|
|
|
|
|
bk = random.choice(random_bk)
|
|
|
|
|
|
x = max(width + 50, height + 250)
|
2021-12-16 11:16:28 +08:00
|
|
|
|
B = BuildImage(
|
2021-11-23 21:44:59 +08:00
|
|
|
|
x,
|
|
|
|
|
|
x,
|
|
|
|
|
|
font_size=24,
|
|
|
|
|
|
color="#FFEFD5",
|
|
|
|
|
|
background=random_bk_path / bk,
|
|
|
|
|
|
)
|
|
|
|
|
|
B.filter("GaussianBlur", 10)
|
|
|
|
|
|
_, B = get_max_width_or_paste(simple_help_img_list, B, True)
|
|
|
|
|
|
w = 10
|
|
|
|
|
|
h = 10
|
|
|
|
|
|
for msg in ["目前支持的功能列表:", "可以通过 ‘帮助[功能名称]’ 来获取对应功能的使用方法", "或者使用 ‘详细帮助’ 来获取所有功能方法"]:
|
2021-12-16 11:16:28 +08:00
|
|
|
|
text = BuildImage(
|
2021-11-23 21:44:59 +08:00
|
|
|
|
0,
|
|
|
|
|
|
0,
|
|
|
|
|
|
plain_text=msg,
|
|
|
|
|
|
font_size=24,
|
|
|
|
|
|
font="yuanshen.ttf",
|
|
|
|
|
|
)
|
|
|
|
|
|
B.paste(text, (w, h), True)
|
|
|
|
|
|
h += 50
|
|
|
|
|
|
if msg == "目前支持的功能列表:":
|
|
|
|
|
|
w += 50
|
|
|
|
|
|
B.paste(
|
2021-12-16 11:16:28 +08:00
|
|
|
|
BuildImage(
|
2021-11-23 21:44:59 +08:00
|
|
|
|
0,
|
|
|
|
|
|
0,
|
|
|
|
|
|
plain_text="注: 红字代表功能被群管理员禁用,红线代表功能正在维护",
|
|
|
|
|
|
font_size=24,
|
|
|
|
|
|
font="yuanshen.ttf",
|
|
|
|
|
|
font_color=(231, 74, 57)
|
|
|
|
|
|
),
|
|
|
|
|
|
(300, 10),
|
|
|
|
|
|
True,
|
|
|
|
|
|
)
|
|
|
|
|
|
B.save(simple_help_image)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_max_width_or_paste(
|
2021-12-16 11:16:28 +08:00
|
|
|
|
simple_help_img_list: list, B: BuildImage = None, is_paste: bool = False
|
|
|
|
|
|
) -> "int, BuildImage":
|
2021-11-23 21:44:59 +08:00
|
|
|
|
"""
|
|
|
|
|
|
获取最大宽度,或直接贴图
|
|
|
|
|
|
:param simple_help_img_list: 简单帮助图片列表
|
|
|
|
|
|
:param B: 背景图
|
|
|
|
|
|
:param is_paste: 是否直接贴图
|
|
|
|
|
|
"""
|
|
|
|
|
|
current_width = 50
|
|
|
|
|
|
current_height = 180
|
|
|
|
|
|
max_width = simple_help_img_list[0].w
|
|
|
|
|
|
for i in range(len(simple_help_img_list)):
|
|
|
|
|
|
try:
|
|
|
|
|
|
if is_paste and B:
|
|
|
|
|
|
B.paste(simple_help_img_list[i], (current_width, current_height), True)
|
|
|
|
|
|
current_height += simple_help_img_list[i].h + 40
|
|
|
|
|
|
if current_height + simple_help_img_list[i + 1].h > B.h - 10:
|
|
|
|
|
|
current_height = 180
|
|
|
|
|
|
current_width += max_width + 30
|
|
|
|
|
|
max_width = 0
|
|
|
|
|
|
elif simple_help_img_list[i].w > max_width:
|
|
|
|
|
|
max_width = simple_help_img_list[i].w
|
|
|
|
|
|
except IndexError:
|
|
|
|
|
|
pass
|
|
|
|
|
|
if current_width > simple_help_img_list[0].w + 50:
|
|
|
|
|
|
current_width += simple_help_img_list[-1].w
|
|
|
|
|
|
return current_width, B
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]:
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取功能的帮助信息
|
|
|
|
|
|
:param msg: 功能cmd
|
|
|
|
|
|
:param is_super: 是否为超级用户
|
|
|
|
|
|
"""
|
|
|
|
|
|
module = plugins2settings_manager.get_plugin_module(msg)
|
|
|
|
|
|
if not module:
|
|
|
|
|
|
module = admin_manager.get_plugin_module(msg)
|
|
|
|
|
|
if module:
|
|
|
|
|
|
try:
|
|
|
|
|
|
plugin = nonebot.plugin.get_plugin(module)
|
|
|
|
|
|
if plugin:
|
|
|
|
|
|
if is_super:
|
|
|
|
|
|
result = plugin.module.__getattribute__(
|
|
|
|
|
|
"__plugin_superuser_usage__"
|
|
|
|
|
|
)
|
|
|
|
|
|
else:
|
|
|
|
|
|
result = plugin.module.__getattribute__("__plugin_usage__")
|
|
|
|
|
|
if result:
|
|
|
|
|
|
width = 0
|
|
|
|
|
|
for x in result.split("\n"):
|
|
|
|
|
|
_width = len(x) * 24
|
|
|
|
|
|
width = width if width > _width else _width
|
|
|
|
|
|
height = len(result.split("\n")) * 45
|
2021-12-16 11:16:28 +08:00
|
|
|
|
A = BuildImage(width, height, font_size=24)
|
|
|
|
|
|
bk = BuildImage(
|
2021-11-23 21:44:59 +08:00
|
|
|
|
width,
|
|
|
|
|
|
height,
|
|
|
|
|
|
background=Path(IMAGE_PATH) / "background" / "1.png",
|
|
|
|
|
|
)
|
|
|
|
|
|
A.paste(bk, alpha=True)
|
|
|
|
|
|
A.text((int(width * 0.048), int(height * 0.21)), result)
|
|
|
|
|
|
return A.pic2bs4()
|
|
|
|
|
|
except AttributeError:
|
|
|
|
|
|
pass
|
|
|
|
|
|
return None
|