diff --git a/konabot/plugins/fx_process/fx_handle.py b/konabot/plugins/fx_process/fx_handle.py index ada3785..d9a40b9 100644 --- a/konabot/plugins/fx_process/fx_handle.py +++ b/konabot/plugins/fx_process/fx_handle.py @@ -562,8 +562,8 @@ class ImageFilterImplement: def apply_shadow(image: Image.Image, x_offset: int = 10, y_offset: int = 10, - blur = 10, - opacity = 0.5, + blur: float = 10, + opacity: float = 0.5, shadow_color = "black") -> Image.Image: if image.mode != 'RGBA': image = image.convert('RGBA') diff --git a/konabot/plugins/notice_ui/__init__.py b/konabot/plugins/notice_ui/__init__.py new file mode 100644 index 0000000..158a16b --- /dev/null +++ b/konabot/plugins/notice_ui/__init__.py @@ -0,0 +1,26 @@ +from loguru import logger +import nonebot +from nonebot.adapters import Event as BaseEvent +from nonebot.adapters.discord.event import MessageEvent as DiscordMessageEvent +from nonebot_plugin_alconna import ( + UniMessage, + UniMsg +) +from konabot.plugins.notice_ui.notice import NoticeUI +from nonebot_plugin_alconna import on_alconna, Alconna, Args + +evt = on_alconna(Alconna( + "notice", + Args["title", str], + Args["message", str] + ), + use_cmd_start=True, use_cmd_sep=False, skip_for_unmatch=True +) + +@evt.handle() +async def _(title: str, message: str, msg: UniMsg, event: BaseEvent): + logger.debug(f"Received notice command with title: {title}, message: {message}") + + out = await NoticeUI.render_notice(title, message) + + await evt.send(await UniMessage().image(raw=out).export()) \ No newline at end of file diff --git a/konabot/plugins/notice_ui/notice.py b/konabot/plugins/notice_ui/notice.py new file mode 100644 index 0000000..431249c --- /dev/null +++ b/konabot/plugins/notice_ui/notice.py @@ -0,0 +1,53 @@ +from io import BytesIO +from PIL import Image +from konabot.common.web_render import konaweb +from konabot.common.web_render.core import WebRenderer + +from playwright.async_api import Page + +class NoticeUI: + @staticmethod + async def render_notice(title: str, message: str) -> bytes: + """ + 渲染一个通知图片,包含标题和消息内容。 + """ + async def page_function(page: Page): + # 直到 setMaskMode 函数加载完成 + await page.wait_for_function("typeof setMaskMode === 'function'", timeout=1000) + await page.evaluate('setMaskMode(false)') + # 直到 setContent 函数加载完成 + await page.wait_for_function("typeof setContent === 'function'", timeout=1000) + # 设置标题和消息内容 + await page.evaluate(f'setContent("{title}", "{message}")') + + async def mask_function(page: Page): + # 直到 setContent 函数加载完成 + await page.wait_for_function("typeof setContent === 'function'", timeout=1000) + # 设置标题和消息内容 + await page.evaluate(f'setContent("{title}", "{message}")') + # 直到 setMaskMode 函数加载完成 + await page.wait_for_function("typeof setMaskMode === 'function'", timeout=1000) + await page.evaluate('setMaskMode(true)') + + image_bytes = await WebRenderer.render_with_persistent_page( + "notice_renderer", + konaweb('notice'), + target='#main', + other_function=page_function, + ) + + mask_bytes = await WebRenderer.render_with_persistent_page( + "notice_renderer", + konaweb('notice'), + target='#main', + other_function=mask_function) + + image = Image.open(BytesIO(image_bytes)).convert("RGBA") + mask = Image.open(BytesIO(mask_bytes)).convert("L") + # 应用遮罩 + image.putalpha(mask) + + output_buffer = BytesIO() + image.save(output_buffer, format="GIF", disposal=2, loop=0) + output_buffer.seek(0) + return output_buffer.getvalue() \ No newline at end of file diff --git a/konabot/plugins/simple_notify/__init__.py b/konabot/plugins/simple_notify/__init__.py index 91be3c7..1e197c5 100644 --- a/konabot/plugins/simple_notify/__init__.py +++ b/konabot/plugins/simple_notify/__init__.py @@ -6,6 +6,7 @@ from pathlib import Path from typing import Any import nanoid +from konabot.plugins.notice_ui.notice import NoticeUI import nonebot from loguru import logger from nonebot import get_plugin_config, on_message @@ -107,6 +108,10 @@ async def _(task: LongTask): await task.target.send_message( UniMessage().text(f"代办提醒:{message}") ) + notice_bytes = NoticeUI.render_notice("代办提醒", message) + await task.target.send_message( + await UniMessage().image(raw=notice_bytes).export() + ) async with DATA_FILE_LOCK: data = load_notify_config() if (chan := data.notify_channels.get(task.target.target_id)) is not None: