From 90738219f156205c4f25c5a1d2305b963120e837 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Wed, 13 Nov 2024 08:41:06 +0800 Subject: [PATCH] =?UTF-8?q?IYUU=E6=B6=88=E6=81=AF=E6=8E=A8=E9=80=81=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20=E9=99=90=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 17 ++++- plugins/iyuumsg/__init__.py | 127 ++++++++++++++++++++++++------------ 2 files changed, 100 insertions(+), 44 deletions(-) diff --git a/package.json b/package.json index 048729b..1fd28e0 100644 --- a/package.json +++ b/package.json @@ -891,7 +891,7 @@ "v1.0": "同步MoviePilot站点Cookie到CookieCloud" } }, - "BangumiColl": { + "BangumiColl": { "name": "Bangumi收藏订阅", "description": "Bangumi用户收藏添加到订阅", "labels": "订阅", @@ -905,5 +905,18 @@ "v1.5.1": "修复季度信息未传递的问题. 新增站点列表同步删除", "v1.5": "修复总集数会同步TMDB变动的问题,增加开关选项" } - } + }, + "IyuuMsg": { + "name": "IYUU消息推送", + "description": "支持使用IYUU发送消息通知。", + "labels": "消息通知,IYUU", + "version": "1.3", + "icon": "Iyuu_A.png", + "author": "jxxghp", + "level": 1, + "v2": true, + "history": { + "v1.3": "消息限流发送,以缓解IYUU服务器压力" + } + } } diff --git a/plugins/iyuumsg/__init__.py b/plugins/iyuumsg/__init__.py index f492ccb..542bf4c 100644 --- a/plugins/iyuumsg/__init__.py +++ b/plugins/iyuumsg/__init__.py @@ -1,11 +1,14 @@ +import threading +from queue import Queue +from time import time, sleep +from typing import Any, List, Dict, Tuple from urllib.parse import urlencode -from app.plugins import _PluginBase 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 -from typing import Any, List, Dict, Tuple -from app.log import logger class IyuuMsg(_PluginBase): @@ -16,7 +19,7 @@ class IyuuMsg(_PluginBase): # 插件图标 plugin_icon = "Iyuu_A.png" # 插件版本 - plugin_version = "1.2" + plugin_version = "1.3" # 插件作者 plugin_author = "jxxghp" # 作者主页 @@ -33,12 +36,30 @@ class IyuuMsg(_PluginBase): _token = None _msgtypes = [] + # 消息处理线程 + processing_thread = None + # 上次发送时间 + last_send_time = 0 + # 消息队列 + message_queue = Queue() + # 消息发送间隔(秒) + send_interval = 5 + # 退出事件 + __event = threading.Event() + def init_plugin(self, config: dict = None): + self.__event.clear() if config: self._enabled = config.get("enabled") self._token = config.get("token") self._msgtypes = config.get("msgtypes") or [] + if self._enabled and self._token: + # 启动处理队列的后台线程 + self.processing_thread = threading.Thread(target=self.process_queue) + self.processing_thread.daemon = True + self.processing_thread.start() + def get_state(self) -> bool: return self._enabled and (True if self._token else False) @@ -143,55 +164,77 @@ class IyuuMsg(_PluginBase): @eventmanager.register(EventType.NoticeMessage) def send(self, event: Event): """ - 消息发送事件 + 消息发送事件,将消息加入队列 """ - if not self.get_state(): - return - - if not event.event_data: + if not self.get_state() or not event.event_data: return msg_body = event.event_data - # 渠道 - channel = msg_body.get("channel") - if channel: - return - # 类型 - msg_type: NotificationType = msg_body.get("type") - # 标题 - title = msg_body.get("title") - # 文本 - text = msg_body.get("text") - - if not title and not text: + # 验证消息的有效性 + if not msg_body.get("title") and not msg_body.get("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 + # 将消息加入队列 + self.message_queue.put(msg_body) + logger.info("消息已加入队列等待发送") - try: - sc_url = "https://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消息发送成功") + def process_queue(self): + """ + 处理队列中的消息,按间隔时间发送 + """ + while True: + if self.__event.is_set(): + logger.info("消息发送线程正在退出...") + break + # 获取队列中的下一条消息 + msg_body = self.message_queue.get() + + # 检查是否满足发送间隔时间 + current_time = time() + time_since_last_send = current_time - self.last_send_time + if time_since_last_send < self.send_interval: + sleep(self.send_interval - time_since_last_send) + + # 处理消息内容 + channel = msg_body.get("channel") + if channel: + continue + msg_type: NotificationType = msg_body.get("type") + title = msg_body.get("title") + text = msg_body.get("text") + + # 检查消息类型是否已启用 + if msg_type and self._msgtypes and msg_type.name not in self._msgtypes: + logger.info(f"消息类型 {msg_type.value} 未开启消息发送") + continue + + # 尝试发送消息 + try: + sc_url = "https://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消息发送成功") + # 更新上次发送时间 + self.last_send_time = time() + else: + logger.warn(f"IYUU消息发送失败,错误码:{errno},错误原因:{error}") + elif res is not None: + logger.warn(f"IYUU消息发送失败,错误码:{res.status_code},错误原因:{res.reason}") 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)}") + logger.warn("IYUU消息发送失败,未获取到返回信息") + except Exception as msg_e: + logger.error(f"IYUU消息发送失败,{str(msg_e)}") + + # 标记任务完成 + self.message_queue.task_done() def stop_service(self): """ 退出插件 """ - pass + self.__event.set()