diff --git a/ICON.png b/ICON.png new file mode 100644 index 0000000..121eca4 Binary files /dev/null and b/ICON.png differ diff --git a/gsuid_core/gss.py b/gsuid_core/gss.py index 020f98b..621db95 100644 --- a/gsuid_core/gss.py +++ b/gsuid_core/gss.py @@ -1,16 +1,13 @@ -import asyncio import inspect from gsuid_core.aps import scheduler from gsuid_core.logger import logger from gsuid_core.server import GsServer -from gsuid_core.help.draw_help import get_help_img gss = GsServer() if not gss.is_load: gss.is_load = True gss.load_plugins() - asyncio.run(get_help_img()) repeat_jobs = {} for i in scheduler.get_jobs(): diff --git a/gsuid_core/help/draw_help.py b/gsuid_core/help/draw_help.py deleted file mode 100644 index bc4c000..0000000 --- a/gsuid_core/help/draw_help.py +++ /dev/null @@ -1,232 +0,0 @@ -from pathlib import Path -from typing import Dict, List, Tuple, Union, Optional - -from PIL import Image, ImageDraw - -from gsuid_core.sv import SV, Plugins - -# from gsuid_core.utils.image.image_tools import get_color_bg -from gsuid_core.utils.fonts.fonts import core_font -from gsuid_core.utils.plugins_config.gs_config import pic_gen_config - -pic_quality: int = pic_gen_config.get_config('PicQuality').data -TEXT_PATH = Path(__file__).parent / 'texture2d' -CORE_HELP_IMG = Path(__file__).parent / 'core_help.jpg' - -plugin_title = 92 -sv_title = 67 - -tag_color = { - 'prefix': (137, 228, 124), - 'suffix': (124, 180, 228), - 'file': (190, 228, 217), - 'keyword': (217, 228, 254), - 'fullmatch': (228, 124, 124), - 'regex': (225, 228, 124), - 'command': (228, 124, 124), - 'message': (176, 150, 198), - 'other': (228, 190, 191), -} - -tag_text: Dict[str, str] = { - 'prefix': '前缀', - 'suffix': '后缀', - 'file': '文件', - 'keyword': '包含', - 'fullmatch': '完全', - 'regex': '正则', - 'command': '命令', - 'message': '消息', - 'other': '其他', -} - -tags: Dict[str, Optional[Image.Image]] = { - 'prefix': None, - 'suffix': None, - 'file': None, - 'keyword': None, - 'fullmatch': None, - 'regex': None, - 'command': None, - 'other': None, - 'message': None, -} - - -def get_tag(tag_type: str) -> Image.Image: - cache = tags[tag_type] - if cache is not None: - return cache - text = tag_text[tag_type] - tag = Image.new('RGBA', (60, 40)) - tag_draw = ImageDraw.Draw(tag) - tag_draw.rounded_rectangle((7, 5, 53, 35), 10, tag_color[tag_type]) - tag_draw.text((30, 20), text, (62, 62, 62), core_font(22), 'mm') - tags[tag_type] = tag - return tag - - -def get_command_bg(command: str, tag_type: str): - img = Image.new('RGBA', (220, 40)) - img_draw = ImageDraw.Draw(img) - img_draw.rounded_rectangle((6, 5, 160, 35), 10, (230, 202, 167)) - img_draw.text((83, 20), command, (62, 62, 62), core_font(20), 'mm') - tag = get_tag(tag_type) - img.paste(tag, (160, 0), tag) - return img - - -def _c(data: Union[int, str, bool]) -> Tuple[int, int, int]: - gray_color = (184, 184, 184) - - if isinstance(data, bool): - color = tag_color['prefix'] if data else gray_color - elif isinstance(data, str): - color = ( - tag_color['prefix'] - if data == 'ALL' - else tag_color['command'] if data == 'GROUP' else tag_color['file'] - ) - else: - colors = list(tag_color.values()) - if data <= len(colors) and data >= 0: - color = colors[data] - else: - color = tag_color['other'] - return color - - -def _t(data: Union[int, str, bool]) -> str: - if isinstance(data, bool): - text = '开启' if data else '关闭' - elif isinstance(data, str): - text = ( - '不限' if data == 'ALL' else '群聊' if data == 'GROUP' else '私聊' - ) - else: - texts = [ - '主人', - '超管', - '群主', - '管理', - '频管', - '子管', - '正常', - '低', - '黑', - ] - if data <= len(texts) and data >= 0: - text = [ - '主人', - '超管', - '群主', - '管理', - '频管', - '子管', - '正常', - '低', - '黑', - ][data] - else: - text = '最低' - return text - - -def get_plugin_bg(plugin: Plugins, sv_list: List[SV]): - plugin_name = plugin.name - img_list: List[Image.Image] = [] - - for sv in sv_list: - sv_img = Image.new( - 'RGBA', - ( - 900, - sv_title + ((len(sv.TL) + 3) // 4) * 40, - ), - ) - sv_img_draw = ImageDraw.Draw(sv_img) - - index = 0 - for type in sv.TL: - for trigger_name in sv.TL[type]: - tg_img = get_command_bg( - trigger_name, sv.TL[type][trigger_name].type - ) - sv_img.paste( - tg_img, - (6 + 220 * (index % 4), 67 + 40 * (index // 4)), - tg_img, - ) - index += 1 - index = 0 - - sv_img_draw.rounded_rectangle((15, 19, 25, 50), 10, (62, 62, 62)) - sv_img_draw.text((45, 31), sv.name, (62, 62, 62), core_font(36), 'lm') - - sv_img_draw.rounded_rectangle((710, 15, 760, 50), 10, _c(sv.enabled)) - sv_img_draw.rounded_rectangle((770, 15, 820, 50), 10, _c(sv.pm)) - sv_img_draw.rounded_rectangle((830, 15, 880, 50), 10, _c(sv.area)) - - sv_img_draw.text( - (735, 32), _t(sv.enabled), (62, 62, 62), core_font(22), 'mm' - ) - sv_img_draw.text( - (795, 32), _t(sv.pm), (62, 62, 62), core_font(22), 'mm' - ) - sv_img_draw.text( - (855, 32), _t(sv.area), (62, 62, 62), core_font(22), 'mm' - ) - img_list.append(sv_img) - - img = Image.new( - 'RGBA', - ( - 900, - plugin_title + sum([i.size[1] for i in img_list]), - ), - ) - img_draw = ImageDraw.Draw(img) - img_draw.rounded_rectangle((10, 26, 890, 76), 10, (230, 202, 167)) - img_draw.text((450, 51), plugin_name, (62, 62, 62), core_font(42), 'mm') - - temp = 0 - for _img in img_list: - img.paste(_img, (0, 92 + temp), _img) - temp += _img.size[1] - - return img - - -async def get_help_img() -> Image.Image: - from gsuid_core.sv import SL - - content = SL.detail_lst - img_list: List[Image.Image] = [] - for plugin in content: - plugin_img = get_plugin_bg(plugin, content[plugin]) - img_list.append(plugin_img) - - x = 900 - y = 200 + sum([i.size[1] for i in img_list]) - # img = await get_color_bg(x, y) - img = Image.new('RGBA', (x, y), (255, 255, 255)) - title = Image.open(TEXT_PATH / 'title.png') - - # white = Image.new('RGBA', img.size, (255, 255, 255, 120)) - # img.paste(white, (0, 0), white) - img.paste(title, (0, 50), title) - - temp = 0 - for _img in img_list: - img.paste(_img, (0, 340 + temp), _img) - temp += _img.size[1] - - img = img.convert('RGB') - img.save( - CORE_HELP_IMG, - format='JPEG', - quality=pic_quality, - subsampling=0, - ) - - return img diff --git a/gsuid_core/help/draw_new_plugin_help.py b/gsuid_core/help/draw_new_plugin_help.py new file mode 100644 index 0000000..b39ce6b --- /dev/null +++ b/gsuid_core/help/draw_new_plugin_help.py @@ -0,0 +1,223 @@ +import random +from pathlib import Path +from copy import deepcopy +from typing import Dict, Literal, Optional + +from PIL import Image, ImageDraw + +from gsuid_core.help.model import PluginHelp +from gsuid_core.data_store import get_res_path +from gsuid_core.utils.fonts.fonts import core_font +from gsuid_core.utils.image.convert import convert_img +from gsuid_core.utils.plugins_config.gs_config import pic_gen_config +from gsuid_core.utils.image.image_tools import ( + crop_center_img, + draw_color_badge, +) + +cache: Dict[str, int] = {} +ICON_PATH = Path(__file__).parent / 'new_icon' +TEXT_PATH = Path(__file__).parent / 'texture2d' +pic_quality: int = pic_gen_config.get_config('PicQuality').data + + +def find_icon(name: str, icon_path: Path = ICON_PATH): + for icon in icon_path.glob('*.png'): + if icon.stem == name: + _r = icon + break + else: + for icon in icon_path.glob('*.png'): + if icon.stem in name: + _r = icon + break + else: + if (icon_path / '通用.png').exists(): + _r = icon_path / '通用.png' + else: + _r = random.choice(list(icon_path.iterdir())) + return Image.open(_r) + + +async def get_new_help( + plugin_name: str, + plugin_info: Dict[str, str], + plugin_icon: Image.Image, + plugin_help: Dict[str, PluginHelp], + plugin_prefix: str = '', + help_mode: Literal['dark', 'light'] = 'dark', + banner_bg: Optional[Image.Image] = None, + banner_sub_text: str = '💖且听风吟。', + help_bg: Optional[Image.Image] = None, + cag_bg: Optional[Image.Image] = None, + item_bg: Optional[Image.Image] = None, + icon_path: Path = ICON_PATH, + footer: Optional[Image.Image] = None, + enable_cache: bool = True, +): + help_path = get_res_path('help') / f'{plugin_name}.jpg' + + if ( + help_path.exists() + and plugin_name in cache + and cache[plugin_name] + and enable_cache + ): + return await convert_img(Image.open(help_path)) + + if banner_bg is None: + banner_bg = Image.open(TEXT_PATH / 'banner_bg.jpg') + if help_bg is None: + help_bg = Image.open(TEXT_PATH / 'help_bg.jpg') + if cag_bg is None: + cag_bg = Image.open(TEXT_PATH / 'cag_bg.png') + if footer is None: + footer = Image.open(TEXT_PATH / f'footer_{help_mode}.png') + if item_bg is None: + item_bg = Image.open(TEXT_PATH / f'item_{help_mode}.png') + + if help_mode == 'dark': + main_color = (255, 255, 255) + sub_color = (206, 206, 206) + else: + main_color = (0, 0, 0) + sub_color = (102, 102, 102) + + banner_bg = banner_bg.convert('RGBA') + help_bg = help_bg.convert('RGBA') + cag_bg = cag_bg.convert('RGBA') + item_bg = item_bg.convert('RGBA') + footer = footer.convert('RGBA') + + plugin_icon = plugin_icon.resize((128, 128)) + + # 准备计算整体帮助图大小 + w, h = 1545, 300 + footer.height + + cag_num = len(plugin_help) + h += cag_num * 100 + for cag in plugin_help: + cag_data = plugin_help[cag]['data'] + sv_num = len(cag_data) + h += (((sv_num - 1) // 3) + 1) * 175 + + # 基准图 + img = crop_center_img(help_bg, w, h) + + # 绘制banner + banner_bg.paste(plugin_icon, (89, 88), plugin_icon) + banner_draw = ImageDraw.Draw(banner_bg) + + _banner_name = plugin_name + '帮助' + banner_draw.text( + (262, 128), + _banner_name, + main_color, + font=core_font(50), + anchor='lm', + ) + banner_draw.text( + (262, 183), + banner_sub_text, + sub_color, + font=core_font(30), + anchor='lm', + ) + x1, y1, x2, y2 = core_font(50).getbbox(_banner_name) + plugin_name_len = int(x2 - x1) + + for key, value in plugin_info.items(): + if value == 'any' or not value: + value = (252, 69, 69) + badge = draw_color_badge( + key, + value, + core_font(30), + (255, 255, 255), + ) + banner_bg.paste( + badge, + (262 + plugin_name_len + 10, 128 - badge.height // 2), + badge, + ) + + plugin_name_len += badge.width + 10 + + img.paste(banner_bg, (0, 0), banner_bg) + + # 开始粘贴服务 + hs = 0 + for cag in plugin_help: + sv = plugin_help[cag] + cag_bar = deepcopy(cag_bg) + cag_desc = sv['desc'] + cag_data = sv['data'] + cag_draw = ImageDraw.Draw(cag_bar) + + cag_draw.text( + (136, 50), + cag, + main_color, + font=core_font(45), + anchor='lm', + ) + bbox = core_font(45).getbbox(cag) + cag_name_len = int(bbox[2] - bbox[0]) + + cag_draw.text( + (136 + cag_name_len + 15, 55), + cag_desc, + sub_color, + font=core_font(30), + anchor='lm', + ) + img.paste(cag_bar, (0, 280 + hs), cag_bar) + + for i, command in enumerate(cag_data): + command_name = command['name'] + # command_desc = command['desc'] + command_eg = command['eg'] + command_bg = deepcopy(item_bg) + + icon = find_icon(command_name, icon_path) + command_bg.paste(icon, (6, 12), icon) + + command_draw = ImageDraw.Draw(command_bg) + + command_draw.text( + (160, 67), + plugin_prefix + command_name, + main_color, + font=core_font(40), + anchor='lm', + ) + + command_draw.text( + (160, 116), + plugin_prefix + command_eg, + sub_color, + font=core_font(26), + anchor='lm', + ) + + x, y = 45 + (i % 3) * 490, 370 + (i // 3) * 175 + hs + img.paste(command_bg, (x, y), command_bg) + + hs += (((len(cag_data) - 1) // 3) + 1) * 175 + 100 + + img.paste( + footer, + ((w - footer.width) // 2, h - footer.height - 20), + footer, + ) + + img = img.convert('RGB') + img.save( + help_path, + 'JPEG', + quality=pic_quality, + subsampling=0, + ) + cache[plugin_name] = 1 + + return await convert_img(img) diff --git a/gsuid_core/help/texture2d/banner_bg.jpg b/gsuid_core/help/texture2d/banner_bg.jpg new file mode 100644 index 0000000..d75b5c8 Binary files /dev/null and b/gsuid_core/help/texture2d/banner_bg.jpg differ diff --git a/gsuid_core/help/texture2d/bg.jpg b/gsuid_core/help/texture2d/bg.jpg new file mode 100644 index 0000000..66c7be0 Binary files /dev/null and b/gsuid_core/help/texture2d/bg.jpg differ diff --git a/gsuid_core/help/texture2d/cag_bg.png b/gsuid_core/help/texture2d/cag_bg.png new file mode 100644 index 0000000..998f4a2 Binary files /dev/null and b/gsuid_core/help/texture2d/cag_bg.png differ diff --git a/gsuid_core/help/texture2d/footer_dark.png b/gsuid_core/help/texture2d/footer_dark.png new file mode 100644 index 0000000..b6b267b Binary files /dev/null and b/gsuid_core/help/texture2d/footer_dark.png differ diff --git a/gsuid_core/help/texture2d/footer_light.png b/gsuid_core/help/texture2d/footer_light.png new file mode 100644 index 0000000..bab6863 Binary files /dev/null and b/gsuid_core/help/texture2d/footer_light.png differ diff --git a/gsuid_core/help/texture2d/item_dark.png b/gsuid_core/help/texture2d/item_dark.png new file mode 100644 index 0000000..3125a48 Binary files /dev/null and b/gsuid_core/help/texture2d/item_dark.png differ diff --git a/gsuid_core/help/texture2d/item_light.png b/gsuid_core/help/texture2d/item_light.png new file mode 100644 index 0000000..8993328 Binary files /dev/null and b/gsuid_core/help/texture2d/item_light.png differ diff --git a/gsuid_core/help/texture2d/title.png b/gsuid_core/help/texture2d/title.png deleted file mode 100644 index 7fc2adf..0000000 Binary files a/gsuid_core/help/texture2d/title.png and /dev/null differ diff --git a/gsuid_core/plugins/core_command/core_help/__init__.py b/gsuid_core/plugins/core_command/core_help/__init__.py index 0ded94b..ad5e66e 100644 --- a/gsuid_core/plugins/core_command/core_help/__init__.py +++ b/gsuid_core/plugins/core_command/core_help/__init__.py @@ -2,8 +2,6 @@ from gsuid_core.sv import SV from gsuid_core.bot import Bot from gsuid_core.models import Event from gsuid_core.logger import logger -from gsuid_core.utils.image.convert import convert_img -from gsuid_core.help.draw_help import CORE_HELP_IMG, get_help_img sv_core_help_img = SV('Core帮助') @@ -11,10 +9,4 @@ sv_core_help_img = SV('Core帮助') @sv_core_help_img.on_fullmatch(('core帮助', 'Core帮助')) async def send_core_htlp_msg(bot: Bot, ev: Event): logger.info('[早柚核心] 开始执行[帮助图]') - if CORE_HELP_IMG.exists(): - img = await convert_img(CORE_HELP_IMG) - else: - img = await get_help_img() - img = await convert_img(img) - logger.info('[早柚核心] 帮助图获取成功!') - await bot.send(img) + await bot.send('该功能已删除...') diff --git a/gsuid_core/utils/api/ambr/api.py b/gsuid_core/utils/api/ambr/api.py index c244b63..8291a2d 100644 --- a/gsuid_core/utils/api/ambr/api.py +++ b/gsuid_core/utils/api/ambr/api.py @@ -11,5 +11,5 @@ AMBR_GCG_DETAIL = AMBR_BASE_URL + '/v2/chs/gcg/{}?vh=37F4' AMBR_MONSTER_LIST = AMBR_BASE_URL + '/v2/chs/monster?vh=37F4' AMBR_ICON_URL = AMBR_BASE_URL + '/assets/UI' AMBR_MONSTER_ICON_URL = f'{AMBR_ICON_URL}/monster/' -AMBR_DAILY_URL = AMBR_BASE_URL + '/v2/chs/dailyDungeon?vh=37F4' -AMBR_UPGRADE_URL = AMBR_BASE_URL + '/v2/chs/upgrade?vh=40F3' +AMBR_DAILY_URL = AMBR_BASE_URL + '/api/v2/chs/dailyDungeon?vh=37F4' +AMBR_UPGRADE_URL = AMBR_BASE_URL + '/api/v2/chs/upgrade?vh=40F3' diff --git a/gsuid_core/utils/fonts/MiSans-Bold.ttf b/gsuid_core/utils/fonts/MiSans-Bold.ttf new file mode 100644 index 0000000..eda4bea Binary files /dev/null and b/gsuid_core/utils/fonts/MiSans-Bold.ttf differ diff --git a/gsuid_core/utils/fonts/fonts.py b/gsuid_core/utils/fonts/fonts.py index 298c49b..d8fa4a5 100644 --- a/gsuid_core/utils/fonts/fonts.py +++ b/gsuid_core/utils/fonts/fonts.py @@ -2,7 +2,7 @@ from pathlib import Path from PIL import ImageFont -FONT_ORIGIN_PATH = Path(__file__).parent / 'yuanshen_origin.ttf' +FONT_ORIGIN_PATH = Path(__file__).parent / 'MiSans-Bold.ttf' def core_font(size: int) -> ImageFont.FreeTypeFont: diff --git a/gsuid_core/utils/fonts/yuanshen_origin.ttf b/gsuid_core/utils/fonts/yuanshen_origin.ttf deleted file mode 100644 index cd3ecd4..0000000 Binary files a/gsuid_core/utils/fonts/yuanshen_origin.ttf and /dev/null differ diff --git a/gsuid_core/utils/image/image_tools.py b/gsuid_core/utils/image/image_tools.py index a28b7f6..07cbcad 100644 --- a/gsuid_core/utils/image/image_tools.py +++ b/gsuid_core/utils/image/image_tools.py @@ -6,6 +6,7 @@ from typing import Tuple, Union, Optional import httpx from httpx import get +from utils.fonts.fonts import core_font from PIL import Image, ImageDraw, ImageFont, ImageFilter from gsuid_core.models import Event @@ -20,6 +21,31 @@ def get_div(): return Image.open(TEXT_PATH / 'div.png') +def draw_color_badge( + text: str, + color: Union[Tuple[int, int, int], str] = (252, 69, 69), + font: ImageFont.FreeTypeFont = core_font(30), + font_color: Tuple[int, int, int] = (255, 255, 255), +): + x1, y1, x2, y2 = font.getbbox(text) + offset_x = int((x2 - x1) * 0.3) + offset_y = int((y2 - y1) * 0.5) + x3, y3, x4, y4 = x1 - offset_x, y1 - offset_y, x2 + offset_x, y2 + offset_y + w, h = int(x4 - x3), int(y4 - y3) + center_x, center_y = int(w // 2), int(h // 2) + img = Image.new('RGBA', (w, h), (0, 0, 0, 0)) + draw = ImageDraw.Draw(img) + draw.rounded_rectangle((0, 0, w, h), fill=color, radius=20) + draw.text( + (center_x, center_y), + text, + font=font, + fill=font_color, + anchor='mm', + ) + return img + + def get_status_icon(status: Union[int, bool]) -> Image.Image: if status: img = Image.open(TEXT_PATH / 'yes.png') @@ -89,9 +115,9 @@ async def shift_image_hue(img: Image.Image, angle: float = 30) -> Image.Image: for y in range(img.height): for x in range(img.width): - h, s, v = pixels[x, y] + h, s, v = pixels[x, y] # type: ignore h = (h + hue_shift) % 360 - pixels[x, y] = (h, s, v) + pixels[x, y] = (h, s, v) # type: ignore img = img.convert('RGBA') img.putalpha(alpha) @@ -394,7 +420,16 @@ class CustomizeImage: img = img.convert("RGBA") img = img.resize((1, 1), resample=0) dominant_color = img.getpixel((0, 0)) - return dominant_color + if isinstance(dominant_color, float): + _dominant_color = tuple( + [int(dominant_color * 255) for _ in range(3)] + ) # type: ignore + elif dominant_color is None or isinstance(dominant_color, int): + _dominant_color: Tuple[int, int, int] = (255, 255, 255) + else: + _dominant_color = dominant_color # type: ignore + + return _dominant_color @staticmethod def get_bg_color(