from utils.image_utils import BuildImage 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 = IMAGE_PATH / "background" / "help" / "simple_help" background = 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(True) width = 0 matchers_data = {} _des_tmp = {} _plugin_name_tmp = [] _tmp = [] tmp_img = BuildImage(0, 0, plain_text="1", font_size=24) font_height = tmp_img.h # 插件分类 for matcher in _matchers: plugin_name = None _plugin = matcher.plugin if not _plugin: logger.warning(f"获取 功能:{matcher.plugin_name} 失败...") continue metadata = _plugin.metadata _module = _plugin.module try: plugin_name = metadata.name if metadata else _module.__getattribute__("__zx_plugin_name__") try: plugin_des = metadata.description if metadata else _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.plugin_name ) and plugins2settings_manager[matcher.plugin_name].get("plugin_type"): plugin_type = tuple( plugins2settings_manager.get_plugin_data(matcher.plugin_name)[ "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] = { "modules": matcher.plugin_name, "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.plugin_name}: {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( matchers_data[type_][k]["modules"], "all" ): flag = False if group_id: flag = flag and plugins_manager.get_plugin_status( matchers_data[type_][k]["modules"], "group" ) simple_help_str += ( f"{i+1}.{k}<|_|~|>" f"{group_manager.get_plugin_status(matchers_data[type_][k]['modules'], group_id) if group_id else '_'}|" 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) A = BuildImage( 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 bk = BuildImage(simple_width + 20, simple_height, font_size=24, color="#6495ED") B = BuildImage( 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: A = BuildImage(width + 150, height + 50, font_size=24) 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 B = BuildImage(width + 100, height + 250, font_size=24) 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) B = BuildImage( 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 ["目前支持的功能列表:", "可以通过 ‘帮助[功能名称]’ 来获取对应功能的使用方法", "或者使用 ‘详细帮助’ 来获取所有功能方法"]: text = BuildImage( 0, 0, plain_text=msg, font_size=24, font="HYWenHei-85W.ttf", ) B.paste(text, (w, h), True) h += 50 if msg == "目前支持的功能列表:": w += 50 B.paste( BuildImage( 0, 0, plain_text="注: 红字代表功能被群管理员禁用,红线代表功能正在维护", font_size=24, font="HYWenHei-85W.ttf", font_color=(231, 74, 57) ), (300, 10), True, ) B.save(simple_help_image) def get_max_width_or_paste( simple_help_img_list: list, B: BuildImage = None, is_paste: bool = False ) -> "int, BuildImage": """ 获取最大宽度,或直接贴图 :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) metadata = plugin.metadata if plugin: if is_super: result = plugin.module.__getattribute__( "__plugin_superuser_usage__" ) else: result = metadata.usage if metadata else 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 A = BuildImage(width, height, font_size=24) bk = BuildImage( width, height, background=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