From 4b609caf61028a8c8b6633476b67d19236cc3637 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 5 Nov 2023 08:42:51 +0800 Subject: [PATCH] =?UTF-8?q?add=20=E6=B6=88=E6=81=AF=E6=8E=A8=E9=80=81?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=20*=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- icons/bark.webp | Bin 0 -> 1912 bytes icons/pushdeer.png | Bin 0 -> 7737 bytes plugins/barkmsg/__init__.py | 240 +++++++++++++++++++++++++++ plugins/iyuumsg/__init__.py | 195 ++++++++++++++++++++++ plugins/pushdeermsg/__init__.py | 210 +++++++++++++++++++++++ plugins/pushdeermsg/requirements.txt | 1 + 6 files changed, 646 insertions(+) create mode 100644 icons/bark.webp create mode 100644 icons/pushdeer.png create mode 100644 plugins/barkmsg/__init__.py create mode 100644 plugins/iyuumsg/__init__.py create mode 100644 plugins/pushdeermsg/__init__.py create mode 100644 plugins/pushdeermsg/requirements.txt diff --git a/icons/bark.webp b/icons/bark.webp new file mode 100644 index 0000000000000000000000000000000000000000..0d6bb2f41b8aac470fb214d6c380600e7e88d13f GIT binary patch literal 1912 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 literal 0 HcmV?d00001 diff --git a/plugins/barkmsg/__init__.py b/plugins/barkmsg/__init__.py new file mode 100644 index 0000000..03f8eca --- /dev/null +++ b/plugins/barkmsg/__init__.py @@ -0,0 +1,240 @@ +from typing import Any, List, Dict, Tuple +from urllib.parse import quote_plus + +from app.core.event import eventmanager, Event +from app.log import logger +from app.plugins import _PluginBase +from app.schemas.types import EventType, NotificationType +from app.utils.http import RequestUtils + + +class BarkMsg(_PluginBase): + # 插件名称 + plugin_name = "Bark消息通知" + # 插件描述 + plugin_desc = "支持使用Bark发送消息通知。" + # 插件图标 + plugin_icon = "bark.webp" + # 主题色 + plugin_color = "#FF3B30" + # 插件版本 + plugin_version = "1.0" + # 插件作者 + plugin_author = "jxxghp" + # 作者主页 + author_url = "https://github.com/jxxghp" + # 插件配置项ID前缀 + plugin_config_prefix = "barkmsg_" + # 加载顺序 + plugin_order = 27 + # 可使用的用户级别 + auth_level = 1 + + # 私有属性 + _enabled = False + _server = None + _apikey = None + _params = None + _msgtypes = [] + + def init_plugin(self, config: dict = None): + if config: + self._enabled = config.get("enabled") + self._msgtypes = config.get("msgtypes") or [] + self._server = config.get("server") + self._apikey = config.get("apikey") + self._params = config.get("params") + + def get_state(self) -> bool: + return self._enabled and self._server and self._apikey + + @staticmethod + def get_command() -> List[Dict[str, Any]]: + pass + + def get_api(self) -> List[Dict[str, Any]]: + pass + + def get_form(self) -> Tuple[List[dict], Dict[str, Any]]: + """ + 拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构 + """ + # 编历 NotificationType 枚举,生成消息类型选项 + MsgTypeOptions = [] + for item in NotificationType: + MsgTypeOptions.append({ + "title": item.value, + "value": item.name + }) + return [ + { + 'component': 'VForm', + 'content': [ + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'enabled', + 'label': '启用插件', + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'server', + 'label': '服务器', + 'placeholder': 'http://xxx', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'apikey', + 'label': '密钥', + 'placeholder': '', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'params', + 'label': '附加参数', + 'placeholder': '', + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'multiple': True, + 'chips': True, + 'model': 'msgtypes', + 'label': '消息类型', + 'items': MsgTypeOptions + } + } + ] + } + ] + }, + ] + } + ], { + "enabled": False, + 'msgtypes': [], + 'server': '', + 'apikey': '', + 'params': '' + } + + def get_page(self) -> List[dict]: + pass + + @eventmanager.register(EventType.NoticeMessage) + def send(self, event: Event): + """ + 消息发送事件 + """ + if not self.get_state(): + return + + if not event.event_data: + return + + msg_body = event.event_data + # 类型 + msg_type: NotificationType = msg_body.get("type") + # 标题 + title = msg_body.get("title") + # 文本 + text = msg_body.get("text") + + if not title and not text: + logger.warn("标题和内容不能同时为空") + return + + if (msg_type and self._msgtypes + and msg_type.name not in self._msgtypes): + logger.info(f"消息类型 {msg_type.value} 未开启消息发送") + return + + try: + if not self._server or not self._apikey: + return False, "参数未配置" + sc_url = "%s/%s/%s/%s" % (self._server, self._apikey, quote_plus(title), quote_plus(text)) + if self._params: + sc_url = "%s?%s" % (sc_url, self._params) + res = RequestUtils().post_res(sc_url) + if res and res.status_code == 200: + ret_json = res.json() + code = ret_json['code'] + message = ret_json['message'] + if code == 200: + logger.info("Bark消息发送成功") + else: + logger.warn(f"Bark消息发送失败:{message}") + elif res is not None: + logger.warn(f"Bark消息发送失败,错误码:{res.status_code},错误原因:{res.reason}") + else: + logger.warn(f"Bark消息发送失败:未获取到返回信息") + except Exception as msg_e: + logger.error(f"Bark消息发送失败:{str(msg_e)}") + + def stop_service(self): + """ + 退出插件 + """ + pass diff --git a/plugins/iyuumsg/__init__.py b/plugins/iyuumsg/__init__.py new file mode 100644 index 0000000..1b3f3c0 --- /dev/null +++ b/plugins/iyuumsg/__init__.py @@ -0,0 +1,195 @@ +from urllib.parse import urlencode + +from app.plugins import _PluginBase +from app.core.event import eventmanager, Event +from app.schemas.types import EventType, NotificationType +from app.utils.http import RequestUtils +from typing import Any, List, Dict, Tuple +from app.log import logger + + +class IyuuMsg(_PluginBase): + # 插件名称 + plugin_name = "IYUU消息通知" + # 插件描述 + plugin_desc = "支持使用IYUU发送消息通知。" + # 插件图标 + plugin_icon = "iyuu.png" + # 主题色 + plugin_color = "#C9221B" + # 插件版本 + plugin_version = "1.0" + # 插件作者 + plugin_author = "jxxghp" + # 作者主页 + author_url = "https://github.com/jxxghp" + # 插件配置项ID前缀 + plugin_config_prefix = "iyuumsg_" + # 加载顺序 + plugin_order = 25 + # 可使用的用户级别 + auth_level = 1 + + # 私有属性 + _enabled = False + _token = None + _msgtypes = [] + + def init_plugin(self, config: dict = None): + if config: + self._enabled = config.get("enabled") + self._token = config.get("token") + self._msgtypes = config.get("msgtypes") or [] + + def get_state(self) -> bool: + return self._enabled and self._token + + @staticmethod + def get_command() -> List[Dict[str, Any]]: + pass + + def get_api(self) -> List[Dict[str, Any]]: + pass + + def get_form(self) -> Tuple[List[dict], Dict[str, Any]]: + """ + 拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构 + """ + # 编历 NotificationType 枚举,生成消息类型选项 + MsgTypeOptions = [] + for item in NotificationType: + MsgTypeOptions.append({ + "title": item.value, + "value": item.name + }) + return [ + { + 'component': 'VForm', + 'content': [ + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'enabled', + 'label': '启用插件', + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'token', + 'label': 'IYUU令牌', + 'placeholder': 'IYUUxxx', + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'multiple': True, + 'chips': True, + 'model': 'msgtypes', + 'label': '消息类型', + 'items': MsgTypeOptions + } + } + ] + } + ] + }, + ] + } + ], { + "enabled": False, + 'token': '', + 'msgtypes': [] + } + + def get_page(self) -> List[dict]: + pass + + @eventmanager.register(EventType.NoticeMessage) + def send(self, event: Event): + """ + 消息发送事件 + """ + if not self.get_state(): + return + + if not event.event_data: + return + + msg_body = event.event_data + # 类型 + msg_type: NotificationType = msg_body.get("type") + # 标题 + title = msg_body.get("title") + # 文本 + text = msg_body.get("text") + + if not title and not text: + logger.warn("标题和内容不能同时为空") + return + + if (msg_type and self._msgtypes + and msg_type.name not in self._msgtypes): + logger.info(f"消息类型 {msg_type.value} 未开启消息发送") + return + + try: + sc_url = "http://iyuu.cn/%s.send?%s" % (self._token, urlencode({"text": title, "desp": text})) + res = RequestUtils().get_res(sc_url) + if res and res.status_code == 200: + ret_json = res.json() + errno = ret_json.get('errcode') + error = ret_json.get('errmsg') + if errno == 0: + logger.info("IYUU消息发送成功") + else: + logger.warn(f"IYUU消息发送失败,错误码:{errno},错误原因:{error}") + elif res is not None: + logger.warn(f"IYUU消息发送失败,错误码:{res.status_code},错误原因:{res.reason}") + else: + logger.warn("IYUU消息发送失败,未获取到返回信息") + except Exception as msg_e: + logger.error(f"IYUU消息发送失败,{str(msg_e)}") + + def stop_service(self): + """ + 退出插件 + """ + pass diff --git a/plugins/pushdeermsg/__init__.py b/plugins/pushdeermsg/__init__.py new file mode 100644 index 0000000..4d6ad3b --- /dev/null +++ b/plugins/pushdeermsg/__init__.py @@ -0,0 +1,210 @@ +from typing import Any, List, Dict, Tuple + +from pypushdeer import PushDeer + +from app.core.event import eventmanager, Event +from app.log import logger +from app.plugins import _PluginBase +from app.schemas.types import EventType, NotificationType + + +class PushDeerMsg(_PluginBase): + # 插件名称 + plugin_name = "PushDeer消息通知" + # 插件描述 + plugin_desc = "支持使用PushDeer发送消息通知。" + # 插件图标 + plugin_icon = "pushdeer.png" + # 主题色 + plugin_color = "#FFFFFF" + # 插件版本 + plugin_version = "1.0" + # 插件作者 + plugin_author = "jxxghp" + # 作者主页 + author_url = "https://github.com/jxxghp" + # 插件配置项ID前缀 + plugin_config_prefix = "pushdeermsg_" + # 加载顺序 + plugin_order = 26 + # 可使用的用户级别 + auth_level = 1 + + # 私有属性 + _enabled = False + _server = None + _apikey = None + _msgtypes = [] + + def init_plugin(self, config: dict = None): + if config: + self._enabled = config.get("enabled") + self._msgtypes = config.get("msgtypes") or [] + self._server = config.get("server") + self._apikey = config.get("apikey") + + def get_state(self) -> bool: + return self._enabled and self._server and self._apikey + + @staticmethod + def get_command() -> List[Dict[str, Any]]: + pass + + def get_api(self) -> List[Dict[str, Any]]: + pass + + def get_form(self) -> Tuple[List[dict], Dict[str, Any]]: + """ + 拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构 + """ + # 编历 NotificationType 枚举,生成消息类型选项 + MsgTypeOptions = [] + for item in NotificationType: + MsgTypeOptions.append({ + "title": item.value, + "value": item.name + }) + return [ + { + 'component': 'VForm', + 'content': [ + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'enabled', + 'label': '启用插件', + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'server', + 'label': '服务器', + 'placeholder': 'http://xxx', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'apikey', + 'label': '密钥', + 'placeholder': 'PDUUxxx', + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'multiple': True, + 'chips': True, + 'model': 'msgtypes', + 'label': '消息类型', + 'items': MsgTypeOptions + } + } + ] + } + ] + }, + ] + } + ], { + "enabled": False, + 'msgtypes': [], + 'server': '', + 'apikey': '' + } + + def get_page(self) -> List[dict]: + pass + + @eventmanager.register(EventType.NoticeMessage) + def send(self, event: Event): + """ + 消息发送事件 + """ + if not self.get_state(): + return + + if not event.event_data: + return + + msg_body = event.event_data + # 类型 + msg_type: NotificationType = msg_body.get("type") + # 标题 + title = msg_body.get("title") + # 文本 + text = msg_body.get("text") + + if not title and not text: + logger.warn("标题和内容不能同时为空") + return + + if (msg_type and self._msgtypes + and msg_type.name not in self._msgtypes): + logger.info(f"消息类型 {msg_type.value} 未开启消息发送") + return + + try: + if not self._server or not self._apikey: + return False, "参数未配置" + pushdeer = PushDeer(server=self._server, pushkey=self._apikey) + res = pushdeer.send_markdown(title, desp=text) + if res: + logger.info(f"PushDeer消息发送成功") + else: + logger.warn(f"PushDeer消息发送失败!") + except Exception as msg_e: + logger.error(f"PushDeer消息发送失败,错误信息:{str(msg_e)}") + + def stop_service(self): + """ + 退出插件 + """ + pass diff --git a/plugins/pushdeermsg/requirements.txt b/plugins/pushdeermsg/requirements.txt new file mode 100644 index 0000000..d58568c --- /dev/null +++ b/plugins/pushdeermsg/requirements.txt @@ -0,0 +1 @@ +pypushdeer~=0.0.3 \ No newline at end of file