From ac8ba98f0ad5b95d1985471807802d7a81984822 Mon Sep 17 00:00:00 2001 From: thsrite Date: Fri, 7 Jun 2024 15:26:31 +0800 Subject: [PATCH 01/21] =?UTF-8?q?fix=20v2.5.1=E4=BF=AE=E5=A4=8Dtoken?= =?UTF-8?q?=E8=BF=87=E6=9C=9F=E9=87=8D=E5=8F=91=E6=9C=AA=E5=AD=98=E5=82=A8?= =?UTF-8?q?userid=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- package.json | 3 ++- plugins/wechatforward/__init__.py | 7 ++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7c889e0..008589a 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ MoviePilot三方插件市场:https://github.com/thsrite/MoviePilot-Plugins/ - [短剧刮削 v3.2](docs%2FShortPlayMonitor.md) - 云盘实时监控 v2.1 - 源文件恢复 v1.2 -- [微信消息转发 v2.5](docs%2FWeChatForward.md) +- [微信消息转发 v2.5.1](docs%2FWeChatForward.md) - 订阅下载统计 v1.5 - [自定义命令 v1.7](docs%2FCustomCommand.md) - docker自定义任务 v1.3 diff --git a/package.json b/package.json index fa08dd5..fb932f4 100644 --- a/package.json +++ b/package.json @@ -285,11 +285,12 @@ "name": "微信消息转发", "description": "根据正则转发通知到其他WeChat应用。", "labels": "消息通知", - "version": "2.5", + "version": "2.5.1", "icon": "Wechat_A.png", "author": "thsrite", "level": 1, "history": { + "v2.5.1": "修复token过期重发未存储userid问题", "v2.5": "增强额外消息发送", "v2.4": "修复配置修改后不重建缓存bug", "v2.3": "增加重建缓存,丰富转发历史", diff --git a/plugins/wechatforward/__init__.py b/plugins/wechatforward/__init__.py index 8ce0736..ebcd2fe 100644 --- a/plugins/wechatforward/__init__.py +++ b/plugins/wechatforward/__init__.py @@ -21,7 +21,7 @@ class WeChatForward(_PluginBase): # 插件图标 plugin_icon = "Wechat_A.png" # 插件版本 - plugin_version = "2.5" + plugin_version = "2.5.1" # 插件作者 plugin_author = "thsrite" # 作者主页 @@ -759,7 +759,7 @@ class WeChatForward(_PluginBase): f"额外消息 {self.__parse_tv_title(title)} 用户 {user_id} 已订阅,不再发送额外消息。") continue - logger.info(f"消息用户{user_id} 匹配到目标用户 {extra_userid}") + logger.info(f"消息用户 {user_id} 匹配到目标用户 {extra_userid}") self.__send_message(title=extra_msg, userid=user_id, @@ -972,7 +972,8 @@ class WeChatForward(_PluginBase): appid=appid, title=title, retry=retry, - text=text) + text=text, + userid=userid) return False elif res is not None: logger.error( From e13a190cee3e451550efbc0acdeda609044fbf7f Mon Sep 17 00:00:00 2001 From: thsrite Date: Fri, 7 Jun 2024 23:41:10 +0800 Subject: [PATCH 02/21] =?UTF-8?q?fix=20=E4=BA=91=E7=9B=98Strm=E7=94=9F?= =?UTF-8?q?=E6=88=90v4.1=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E5=AA=92=E4=BD=93=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- package.json | 3 +- plugins/cloudstrm/__init__.py | 42 ++++++++++++++++++++++---- plugins/cloudstrmincrement/__init__.py | 3 +- 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 008589a..1c723cd 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ MoviePilot三方插件市场:https://github.com/thsrite/MoviePilot-Plugins/ - 站点数据统计 v1.4 (无未读消息版本)(废弃) - 站点未读消息 v1.9 (依赖于[站点数据统计]插件) -- [云盘Strm生成 v4.0](docs%2FCloudStrm.md) +- [云盘Strm生成 v4.1](docs%2FCloudStrm.md) - [云盘Strm生成(增量版) v1.0](docs%2FCloudStrmIncrement.md) - [Strm文件模式转换 v1.0](docs%2FStrmConvert.md) - 清理订阅缓存 v1.0 diff --git a/package.json b/package.json index fb932f4..2d270ed 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,12 @@ "name": "云盘Strm生成", "description": "监控文件创建,生成Strm文件。", "labels": "云盘", - "version": "4.0", + "version": "4.1", "icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/create.png", "author": "thsrite", "level": 1, "history": { + "v4.1": "支持自定义媒体类型", "v4.0": "回归老版本", "v3.8": "支持增量路径、支持自定义媒体类型(注:本次更新需修改配置使用)", "v3.7": "api模式支持启用https", diff --git a/plugins/cloudstrm/__init__.py b/plugins/cloudstrm/__init__.py index c6b159a..db218fa 100644 --- a/plugins/cloudstrm/__init__.py +++ b/plugins/cloudstrm/__init__.py @@ -26,7 +26,7 @@ class CloudStrm(_PluginBase): # 插件图标 plugin_icon = "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/create.png" # 插件版本 - plugin_version = "4.0" + plugin_version = "4.1" # 插件作者 plugin_author = "thsrite" # 作者主页 @@ -56,6 +56,7 @@ class CloudStrm(_PluginBase): _cloudurlconf = {} _cloudpathconf = {} __cloud_files = [] + _rmt_mediaext = ".mp4, .mkv, .ts, .iso,.rmvb, .avi, .mov, .mpeg,.mpg, .wmv, .3gp, .asf, .m4v, .flv, .m2ts, .strm,.tp, .f4v" # 定时器 _scheduler: Optional[BackgroundScheduler] = None @@ -78,6 +79,8 @@ class CloudStrm(_PluginBase): self._https = config.get("https") self._copy_files = config.get("copy_files") self._monitor_confs = config.get("monitor_confs") + self._rmt_mediaext = config.get( + "rmt_mediaext") or ".mp4, .mkv, .ts, .iso,.rmvb, .avi, .mov, .mpeg,.mpg, .wmv, .3gp, .asf, .m4v, .flv, .m2ts, .strm,.tp, .f4v" # 停止现有任务 self.stop_service() @@ -233,7 +236,8 @@ class CloudStrm(_PluginBase): continue # 不复制非媒体文件时直接过滤掉非媒体文件 - if not self._copy_files and Path(file).suffix not in settings.RMT_MEDIAEXT: + if not self._copy_files and Path(file).suffix not in [ext.strip() for ext in + self._rmt_mediaext.split(",")]: continue if source_file not in self.__cloud_files: @@ -280,7 +284,8 @@ class CloudStrm(_PluginBase): continue # 不复制非媒体文件时直接过滤掉非媒体文件 - if not self._copy_files and Path(file).suffix not in settings.RMT_MEDIAEXT: + if not self._copy_files and Path(file).suffix not in [ext.strip() for ext in + self._rmt_mediaext.split(",")]: continue logger.info(f"扫描到新文件 {source_file},正在开始处理") @@ -343,7 +348,8 @@ class CloudStrm(_PluginBase): os.makedirs(Path(dest_file).parent) # 视频文件创建.strm文件 - if Path(dest_file).suffix in settings.RMT_MEDIAEXT: + if Path(dest_file).suffix in [ext.strip() for ext in + self._rmt_mediaext.split(",")]: # 创建.strm文件 self.__create_strm_file(scheme="https" if self._https else "http", dest_file=dest_file, @@ -433,7 +439,8 @@ class CloudStrm(_PluginBase): "copy_files": self._copy_files, "https": self._https, "cron": self._cron, - "monitor_confs": self._monitor_confs + "monitor_confs": self._monitor_confs, + "rmt_mediaext": self._rmt_mediaext }) def get_state(self) -> bool: @@ -638,6 +645,28 @@ class CloudStrm(_PluginBase): }, ] }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12 + }, + 'content': [ + { + 'component': 'VTextarea', + 'props': { + 'model': 'rmt_mediaext', + 'label': '视频格式', + 'rows': 2, + 'placeholder': ".mp4, .mkv, .ts, .iso,.rmvb, .avi, .mov, .mpeg,.mpg, .wmv, .3gp, .asf, .m4v, .flv, .m2ts, .strm,.tp, .f4v" + } + } + ] + } + ] + }, { 'component': 'VRow', 'content': [ @@ -737,7 +766,8 @@ class CloudStrm(_PluginBase): "rebuild": False, "copy_files": False, "https": False, - "monitor_confs": "" + "monitor_confs": "", + "rmt_mediaext": ".mp4, .mkv, .ts, .iso,.rmvb, .avi, .mov, .mpeg,.mpg, .wmv, .3gp, .asf, .m4v, .flv, .m2ts, .strm,.tp, .f4v" } def get_page(self) -> List[dict]: diff --git a/plugins/cloudstrmincrement/__init__.py b/plugins/cloudstrmincrement/__init__.py index 5f1049b..1dff14c 100644 --- a/plugins/cloudstrmincrement/__init__.py +++ b/plugins/cloudstrmincrement/__init__.py @@ -236,7 +236,8 @@ class CloudStrmIncrement(_PluginBase): break if str(parent_path.parent) != str(Path(increment_file).root): # 父目录非根目录,才删除父目录 - if not SystemUtils.exits_files(parent_path, settings.RMT_MEDIAEXT): + if not SystemUtils.exits_files(parent_path, + [ext.strip() for ext in self._rmt_mediaext.split(",")]): # 当前路径下没有媒体文件则删除 shutil.rmtree(parent_path) logger.warn(f"增量非保留目录 {parent_path} 已删除") From 477388d908585e562f9c40b5f56a5c4dd61514b1 Mon Sep 17 00:00:00 2001 From: thsrite Date: Sat, 8 Jun 2024 11:59:26 +0800 Subject: [PATCH 03/21] =?UTF-8?q?fix=20=E8=AE=A2=E9=98=85=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E9=A2=9D=E5=A4=96=E6=B6=88=E6=81=AF=E5=8D=95=E7=8B=AC?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/wechatforward/__init__.py | 130 +++++++++++++++++------------- 1 file changed, 76 insertions(+), 54 deletions(-) diff --git a/plugins/wechatforward/__init__.py b/plugins/wechatforward/__init__.py index ebcd2fe..76cf3d5 100644 --- a/plugins/wechatforward/__init__.py +++ b/plugins/wechatforward/__init__.py @@ -4,6 +4,7 @@ import time from datetime import datetime from app.core.config import settings +from app.db.models.subscribehistory import SubscribeHistory from app.db.subscribe_oper import SubscribeOper from app.plugins import _PluginBase from app.core.event import eventmanager @@ -715,63 +716,84 @@ class WeChatForward(_PluginBase): if str(extra_msg).find('{name}') != -1: extra_msg = extra_msg.replace('{name}', self.__parse_tv_title(title)) - # 搜索消息,获取消息text中的用户 - result = re.search(r"用户:(.*?)\n", text) - if not result: - # 订阅消息,获取消息text中的用户 - pattern = r"来自用户:(.*?)$" - result = re.search(pattern, text) + # 订阅完成消息单独处理 + if "已完成订阅" in str(title): + # 查订阅历史的用户 + subscribes = SubscribeHistory().list() + # 倒叙 + subscribes = sorted(subscribes, key=lambda x: x.id, reverse=True) + for subscribe in subscribes: + # 匹配订阅title + if f"{subscribe.name} ({subscribe.year}) 已完成订阅" == title \ + or f"{subscribe.name} ({subscribe.year}) S{str(subscribe.season).rjust(2, '0')} 已完成订阅" == title: + user_id = subscribe.username + logger.info(f"{title} 获取到订阅用户 {user_id}") + + self.__send_image_message(title=extra_msg, + userid=user_id, + access_token=access_token, + appid=wechat_appid, + image_url=subscribe.backdrop) + logger.info(f"{wechat_appid} 发送额外消息 {extra_msg} 成功") + break + else: + # 搜索消息,获取消息text中的用户 + result = re.search(r"用户:(.*?)\n", text) if not result: - logger.error("未获取到用户,跳过处理") - continue - - # 获取消息text中的用户 - user_id = result.group(1) - logger.info(f"获取到消息用户 {user_id}") - if user_id and any(user_id == user for user in extra_userid.split(",")): - if "开始下载" in str(title): - # 判断是否重复发送,10分钟内重复消息title、重复userid算重复消息 - extra_history_time = self._extra_msg_history.get( - f"{user_id}-{self.__parse_tv_title(title)}") or None - # 只处理下载消息 - if extra_history_time: - logger.info( - f"获取到额外消息上次发送时间 {datetime.strptime(extra_history_time, '%Y-%m-%d %H:%M:%S')}") - if (datetime.now() - datetime.strptime(extra_history_time, - '%Y-%m-%d %H:%M:%S')).total_seconds() < 600: - logger.warn( - f"额外消息 {self.__parse_tv_title(title)} 十分钟内重复发送,跳过。") - continue - # 判断当前用户是否订阅,是否订阅后续消息 - subscribes = SubscribeOper().list_by_username(username=str(user_id), - state="R", - mtype=MediaType.TV.value) - is_subscribe = False - for subscribe in subscribes: - # 匹配订阅title - if f"{subscribe.name} ({subscribe.year})" in title: - is_subscribe = True - break - - # 电视剧之前该用户订阅下载过,不再发送额外消息 - if is_subscribe: - logger.warn( - f"额外消息 {self.__parse_tv_title(title)} 用户 {user_id} 已订阅,不再发送额外消息。") + # 订阅消息,获取消息text中的用户 + pattern = r"来自用户:(.*?)$" + result = re.search(pattern, text) + if not result: + logger.error(f"{title} 未获取到用户,跳过处理") continue - logger.info(f"消息用户 {user_id} 匹配到目标用户 {extra_userid}") + # 获取消息text中的用户 + user_id = result.group(1) + logger.info(f"{title} 获取到消息用户 {user_id}") + if user_id and any(user_id == user for user in extra_userid.split(",")): + if "开始下载" in str(title): + # 判断是否重复发送,10分钟内重复消息title、重复userid算重复消息 + extra_history_time = self._extra_msg_history.get( + f"{user_id}-{self.__parse_tv_title(title)}") or None + # 只处理下载消息 + if extra_history_time: + logger.info( + f"{title} 获取到额外消息上次发送时间 {datetime.strptime(extra_history_time, '%Y-%m-%d %H:%M:%S')}") + if (datetime.now() - datetime.strptime(extra_history_time, + '%Y-%m-%d %H:%M:%S')).total_seconds() < 600: + logger.warn( + f"{title} 额外消息 {self.__parse_tv_title(title)} 十分钟内重复发送,跳过。") + continue + # 判断当前用户是否订阅,是否订阅后续消息 + subscribes = SubscribeOper().list_by_username(username=str(user_id), + state="R", + mtype=MediaType.TV.value) + is_subscribe = False + for subscribe in subscribes: + # 匹配订阅title + if f"{subscribe.name} ({subscribe.year})" in title: + is_subscribe = True + break - self.__send_message(title=extra_msg, - userid=user_id, - access_token=access_token, - appid=wechat_appid) - logger.info(f"{wechat_appid} 发送额外消息 {extra_msg} 成功") - # 保存已发送消息 - if "开始下载" in str(title): - self._extra_msg_history[ - f"{user_id}-{self.__parse_tv_title(title)}"] = time.strftime( - "%Y-%m-%d %H:%M:%S", time.localtime(time.time())) - is_save_history = True + # 电视剧之前该用户订阅下载过,不再发送额外消息 + if is_subscribe: + logger.warn( + f"{title} 额外消息 {self.__parse_tv_title(title)} 用户 {user_id} 已订阅,不再发送额外消息。") + continue + + logger.info(f"{title} 消息用户 {user_id} 匹配到目标用户 {extra_userid}") + + self.__send_message(title=extra_msg, + userid=user_id, + access_token=access_token, + appid=wechat_appid) + logger.info(f"{title} {wechat_appid} 发送额外消息 {extra_msg} 成功") + # 保存已发送消息 + if "开始下载" in str(title): + self._extra_msg_history[ + f"{user_id}-{self.__parse_tv_title(title)}"] = time.strftime( + "%Y-%m-%d %H:%M:%S", time.localtime(time.time())) + is_save_history = True # 保存额外消息历史 if is_save_history: @@ -888,7 +910,7 @@ class WeChatForward(_PluginBase): return self.__post_request(access_token=access_token, req_json=req_json, appid=appid, title=title, text=text, userid=userid) - def __send_image_message(self, title: str, text: str, image_url: str, userid: str = None, + def __send_image_message(self, title: str, image_url: str, text: str = None, userid: str = None, access_token: str = None, appid: int = None) -> Optional[bool]: """ 发送图文消息 From 1fb976d83853d34ab51f2a5b07eb5dc64c09d8d7 Mon Sep 17 00:00:00 2001 From: thsrite Date: Sat, 8 Jun 2024 12:04:10 +0800 Subject: [PATCH 04/21] =?UTF-8?q?fix=20=E5=BE=AE=E4=BF=A1=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E8=BD=AC=E5=8F=91v2.6\n=E5=B7=B2=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E8=AE=A2=E9=98=85=E9=A2=9D=E5=A4=96=E6=B6=88=E6=81=AF=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E8=AE=A2=E9=98=85=E5=8E=86=E5=8F=B2=E8=AE=A2=E9=98=85?= =?UTF-8?q?=E7=94=A8=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- package.json | 3 ++- plugins/wechatforward/__init__.py | 5 ++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1c723cd..10c1776 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ MoviePilot三方插件市场:https://github.com/thsrite/MoviePilot-Plugins/ - [短剧刮削 v3.2](docs%2FShortPlayMonitor.md) - 云盘实时监控 v2.1 - 源文件恢复 v1.2 -- [微信消息转发 v2.5.1](docs%2FWeChatForward.md) +- [微信消息转发 v2.6](docs%2FWeChatForward.md) - 订阅下载统计 v1.5 - [自定义命令 v1.7](docs%2FCustomCommand.md) - docker自定义任务 v1.3 diff --git a/package.json b/package.json index 2d270ed..86f80b4 100644 --- a/package.json +++ b/package.json @@ -286,11 +286,12 @@ "name": "微信消息转发", "description": "根据正则转发通知到其他WeChat应用。", "labels": "消息通知", - "version": "2.5.1", + "version": "2.6", "icon": "Wechat_A.png", "author": "thsrite", "level": 1, "history": { + "v2.6": "已完成订阅额外消息查询订阅历史订阅用户", "v2.5.1": "修复token过期重发未存储userid问题", "v2.5": "增强额外消息发送", "v2.4": "修复配置修改后不重建缓存bug", diff --git a/plugins/wechatforward/__init__.py b/plugins/wechatforward/__init__.py index 76cf3d5..26c3335 100644 --- a/plugins/wechatforward/__init__.py +++ b/plugins/wechatforward/__init__.py @@ -22,7 +22,7 @@ class WeChatForward(_PluginBase): # 插件图标 plugin_icon = "Wechat_A.png" # 插件版本 - plugin_version = "2.5.1" + plugin_version = "2.6" # 插件作者 plugin_author = "thsrite" # 作者主页 @@ -811,10 +811,13 @@ class WeChatForward(_PluginBase): # 电影 功夫熊猫 (2008) 已添加订阅 # 电视剧 追风者 (2024) S01 E01-E04 开始下载 # 电视剧 追风者 (2024) S01 已添加订阅 + # 电视剧 追风者 (2024) S01 已完成订阅 if '开始下载' in sub_title_str: continue if '已添加订阅' in sub_title_str: continue + if '已完成订阅' in sub_title_str: + continue _title += f"{sub_title_str} " return self.__convert_season_episode(str(_title.rstrip())) From 0a5b69742aabd6bad27ef25e98017d4f1942fbce Mon Sep 17 00:00:00 2001 From: thsrite Date: Sat, 8 Jun 2024 12:08:29 +0800 Subject: [PATCH 05/21] fix --- plugins/wechatforward/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/wechatforward/__init__.py b/plugins/wechatforward/__init__.py index 26c3335..187840e 100644 --- a/plugins/wechatforward/__init__.py +++ b/plugins/wechatforward/__init__.py @@ -729,7 +729,8 @@ class WeChatForward(_PluginBase): user_id = subscribe.username logger.info(f"{title} 获取到订阅用户 {user_id}") - self.__send_image_message(title=extra_msg, + self.__send_image_message(title=title, + text=extra_msg, userid=user_id, access_token=access_token, appid=wechat_appid, From 6c39b01712ce178ca023d7c25e44cf232a641ea4 Mon Sep 17 00:00:00 2001 From: thsrite Date: Sat, 8 Jun 2024 12:12:23 +0800 Subject: [PATCH 06/21] =?UTF-8?q?fix=20=E5=B7=B2=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E8=AE=A2=E9=98=85=E6=B6=88=E6=81=AF=E6=8C=87=E5=AE=9A=E7=89=B9?= =?UTF-8?q?=E5=9C=B0=E7=94=A8=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/wechatforward/__init__.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/plugins/wechatforward/__init__.py b/plugins/wechatforward/__init__.py index 187840e..84d92ab 100644 --- a/plugins/wechatforward/__init__.py +++ b/plugins/wechatforward/__init__.py @@ -728,14 +728,15 @@ class WeChatForward(_PluginBase): or f"{subscribe.name} ({subscribe.year}) S{str(subscribe.season).rjust(2, '0')} 已完成订阅" == title: user_id = subscribe.username logger.info(f"{title} 获取到订阅用户 {user_id}") - - self.__send_image_message(title=title, - text=extra_msg, - userid=user_id, - access_token=access_token, - appid=wechat_appid, - image_url=subscribe.backdrop) - logger.info(f"{wechat_appid} 发送额外消息 {extra_msg} 成功") + if user_id and any(user_id == user for user in extra_userid.split(",")): + logger.info(f"{title} 消息用户 {user_id} 匹配到目标用户 {extra_userid}") + self.__send_image_message(title=title, + text=extra_msg, + userid=user_id, + access_token=access_token, + appid=wechat_appid, + image_url=subscribe.backdrop) + logger.info(f"{wechat_appid} 发送额外消息 {extra_msg} 成功") break else: # 搜索消息,获取消息text中的用户 From b29f47f24650ae0cff3364d39cde45d7aae735bc Mon Sep 17 00:00:00 2001 From: thsrite Date: Sat, 8 Jun 2024 14:40:54 +0800 Subject: [PATCH 07/21] fix #53 --- plugins/cloudstrm/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/cloudstrm/__init__.py b/plugins/cloudstrm/__init__.py index db218fa..c2eb3b7 100644 --- a/plugins/cloudstrm/__init__.py +++ b/plugins/cloudstrm/__init__.py @@ -26,7 +26,7 @@ class CloudStrm(_PluginBase): # 插件图标 plugin_icon = "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/create.png" # 插件版本 - plugin_version = "4.1" + plugin_version = "4.2" # 插件作者 plugin_author = "thsrite" # 作者主页 @@ -236,7 +236,7 @@ class CloudStrm(_PluginBase): continue # 不复制非媒体文件时直接过滤掉非媒体文件 - if not self._copy_files and Path(file).suffix not in [ext.strip() for ext in + if not self._copy_files and Path(file).suffix.lower() not in [ext.strip() for ext in self._rmt_mediaext.split(",")]: continue @@ -284,7 +284,7 @@ class CloudStrm(_PluginBase): continue # 不复制非媒体文件时直接过滤掉非媒体文件 - if not self._copy_files and Path(file).suffix not in [ext.strip() for ext in + if not self._copy_files and Path(file).suffix.lower() not in [ext.strip() for ext in self._rmt_mediaext.split(",")]: continue @@ -348,7 +348,7 @@ class CloudStrm(_PluginBase): os.makedirs(Path(dest_file).parent) # 视频文件创建.strm文件 - if Path(dest_file).suffix in [ext.strip() for ext in + if Path(dest_file).suffix.lower() in [ext.strip() for ext in self._rmt_mediaext.split(",")]: # 创建.strm文件 self.__create_strm_file(scheme="https" if self._https else "http", From 0ef3f5a63c9e694d0e00197a221cdf98be8dbe01 Mon Sep 17 00:00:00 2001 From: thsrite Date: Sat, 8 Jun 2024 14:42:50 +0800 Subject: [PATCH 08/21] Update package.json --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 86f80b4..4d217e9 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,12 @@ "name": "云盘Strm生成", "description": "监控文件创建,生成Strm文件。", "labels": "云盘", - "version": "4.1", + "version": "4.2", "icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/create.png", "author": "thsrite", "level": 1, "history": { + "v4.2": "扩展名转小写", "v4.1": "支持自定义媒体类型", "v4.0": "回归老版本", "v3.8": "支持增量路径、支持自定义媒体类型(注:本次更新需修改配置使用)", From 35c5122e0076444e3d8c1672cd43bf87a7e2ea44 Mon Sep 17 00:00:00 2001 From: thsrite Date: Sat, 8 Jun 2024 18:49:28 +0800 Subject: [PATCH 09/21] fix log --- plugins/actorsubscribe/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/actorsubscribe/__init__.py b/plugins/actorsubscribe/__init__.py index 2b953e1..c62ecca 100644 --- a/plugins/actorsubscribe/__init__.py +++ b/plugins/actorsubscribe/__init__.py @@ -283,6 +283,7 @@ class ActorSubscribe(_PluginBase): # 保存历史记录 self.save_data('history', history) self.save_data('already_handle', already_handle) + logger.info(f"演员订阅任务完成") def __get_douban_actors(self, mediainfo: MediaInfo, season: int = None) -> List[dict]: """ From e93bee5f095488e9d27b6d44b9268c4dcdc33601 Mon Sep 17 00:00:00 2001 From: thsrite Date: Sat, 8 Jun 2024 18:51:31 +0800 Subject: [PATCH 10/21] fix desc --- README.md | 2 +- package.json | 2 +- plugins/actorsubscribe/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 10c1776..95011c0 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ MoviePilot三方插件市场:https://github.com/thsrite/MoviePilot-Plugins/ - 站点数据统计 v1.4 (无未读消息版本)(废弃) - 站点未读消息 v1.9 (依赖于[站点数据统计]插件) -- [云盘Strm生成 v4.1](docs%2FCloudStrm.md) +- [云盘Strm生成 v4.2](docs%2FCloudStrm.md) - [云盘Strm生成(增量版) v1.0](docs%2FCloudStrmIncrement.md) - [Strm文件模式转换 v1.0](docs%2FStrmConvert.md) - 清理订阅缓存 v1.0 diff --git a/package.json b/package.json index 4d217e9..58f5ecd 100644 --- a/package.json +++ b/package.json @@ -213,7 +213,7 @@ }, "ActorSubscribe": { "name": "演员订阅", - "description": "自动订阅指定演员热映或最新电影或电视剧。", + "description": "自动订阅指定演员热映电影、电视剧。", "labels": "订阅", "version": "2.1", "icon": "Mdcng_A.png", diff --git a/plugins/actorsubscribe/__init__.py b/plugins/actorsubscribe/__init__.py index c62ecca..ffd7f16 100644 --- a/plugins/actorsubscribe/__init__.py +++ b/plugins/actorsubscribe/__init__.py @@ -23,7 +23,7 @@ class ActorSubscribe(_PluginBase): # 插件名称 plugin_name = "演员订阅" # 插件描述 - plugin_desc = "自动订阅指定演员热映或最新电影或电视剧。" + plugin_desc = "自动订阅指定演员热映电影、电视剧。" # 插件图标 plugin_icon = "Mdcng_A.png" # 插件版本 From 097294f05af2cf3b4a55542e7157b2c1f09cbe0b Mon Sep 17 00:00:00 2001 From: thsrite Date: Sat, 8 Jun 2024 19:29:23 +0800 Subject: [PATCH 11/21] fix log --- plugins/actorsubscribe/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/actorsubscribe/__init__.py b/plugins/actorsubscribe/__init__.py index ffd7f16..e5aceca 100644 --- a/plugins/actorsubscribe/__init__.py +++ b/plugins/actorsubscribe/__init__.py @@ -250,7 +250,8 @@ class ActorSubscribe(_PluginBase): if actor and actor in subscribe_actors: # 开始订阅 logger.info( - f"{mediainfo.type.value} {mediainfo.title_year} TMDBID {mediainfo.tmdb_id} DOUBANID {mediainfo.douban_id} 命中订阅演员 {actor},开始订阅") + f"{mediainfo.type.value} {mediainfo.title_year} TMDBID {mediainfo.tmdb_id} DOUBANID {mediainfo.douban_id} 命中订阅演员 {actor}," + f"开始订阅。订阅规则:{self._quality} {self._resolution} {self._effect} {self._username}") is_subscribe = True # 添加订阅 self.subscribechain.add(title=mediainfo.title, From 630f796f8feab0da682e71d81f86400d64459c0b Mon Sep 17 00:00:00 2001 From: thsrite Date: Sun, 9 Jun 2024 11:23:16 +0800 Subject: [PATCH 12/21] =?UTF-8?q?feat=20=E5=91=BD=E4=BB=A4=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E5=99=A8=E6=8F=92=E4=BB=B6=E3=80=81Sql=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E5=99=A8=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- icons/command.png | Bin 0 -> 6799 bytes icons/sqlite.png | Bin 0 -> 15554 bytes package.json | 24 ++++ plugins/commandexecute/__init__.py | 171 +++++++++++++++++++++++++++++ plugins/sqlexecute/__init__.py | 170 ++++++++++++++++++++++++++++ 5 files changed, 365 insertions(+) create mode 100644 icons/command.png create mode 100644 icons/sqlite.png create mode 100644 plugins/commandexecute/__init__.py create mode 100644 plugins/sqlexecute/__init__.py diff --git a/icons/command.png b/icons/command.png new file mode 100644 index 0000000000000000000000000000000000000000..8cfae4dc1a052618a78e690d2961227f5e1af994 GIT binary patch literal 6799 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 literal 0 HcmV?d00001 diff --git a/icons/sqlite.png b/icons/sqlite.png new file mode 100644 index 0000000000000000000000000000000000000000..eb2e91015aca176726d601036205a86017aade9f GIT binary patch literal 15554 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 literal 0 HcmV?d00001 diff --git a/package.json b/package.json index 58f5ecd..888f5da 100644 --- a/package.json +++ b/package.json @@ -479,5 +479,29 @@ "history": { "v1.0": "同步merge主仓库[目录监控]插件,增加统一发送消息逻辑(Testing…)" } + }, + "SqlExecute": { + "name": "Sql执行器", + "description": "自定义MoviePilot数据库Sql执行。", + "labels": "工具", + "version": "1.0", + "icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/sqlite.png", + "author": "thsrite", + "level": 1, + "history": { + "v1.0": "自定义MoviePilot数据库Sql执行" + } + }, + "CommandExecute": { + "name": "命令执行器", + "description": "自定义容器命令执行。", + "labels": "工具", + "version": "1.0", + "icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/command.png", + "author": "thsrite", + "level": 1, + "history": { + "v1.0": "自定义容器命令执行" + } } } diff --git a/plugins/commandexecute/__init__.py b/plugins/commandexecute/__init__.py new file mode 100644 index 0000000..0f924ad --- /dev/null +++ b/plugins/commandexecute/__init__.py @@ -0,0 +1,171 @@ +import subprocess + +from app.plugins import _PluginBase +from typing import Any, List, Dict, Tuple +from app.log import logger + + +class CommandExecute(_PluginBase): + # 插件名称 + plugin_name = "命令执行器" + # 插件描述 + plugin_desc = "自定义容器命令执行。" + # 插件图标 + plugin_icon = "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/command.png" + # 插件版本 + plugin_version = "1.0" + # 插件作者 + plugin_author = "thsrite" + # 作者主页 + author_url = "https://github.com/thsrite" + # 插件配置项ID前缀 + plugin_config_prefix = "commandexecute_" + # 加载顺序 + plugin_order = 30 + # 可使用的用户级别 + auth_level = 1 + + # 私有属性 + _onlyonce = None + _command = None + + def init_plugin(self, config: dict = None): + if config: + self._onlyonce = config.get("onlyonce") + self._command = config.get("command") + + if self._onlyonce and self._command: + # 执行SQL语句 + try: + for command in self._command.split("\n"): + logger.info(f"开始执行命令 {command}") + result = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + last_output = None + last_error = None + while True: + error = result.stderr.readline().decode("utf-8") + if error == '' and result.poll() is not None: + break + if error: + logger.info(error.strip()) + last_error = error.strip() + while True: + output = result.stdout.readline().decode("utf-8") + if output == '' and result.poll() is not None: + break + if output: + logger.info(output.strip()) + last_output = output.strip() + print(last_output if last_output else last_error) + except Exception as e: + logger.error(f"命令执行失败 {str(e)}") + return + finally: + self._onlyonce = False + self.update_config({ + "onlyonce": self._onlyonce, + "command": self._command + }) + + def get_state(self) -> bool: + return False + + @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、数据结构 + """ + return [ + { + 'component': 'VForm', + 'content': [ + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'onlyonce', + 'label': '执行命令' + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + }, + 'content': [ + { + 'component': 'VTextarea', + 'props': { + 'model': 'command', + 'rows': '2', + 'label': 'command命令', + 'placeholder': '一行一条' + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + }, + 'content': [ + { + 'component': 'VAlert', + 'props': { + 'type': 'info', + 'variant': 'tonal' + }, + 'content': [ + { + 'component': 'span', + 'text': '执行日志将会输出到控制台,请谨慎操作。' + } + ] + } + ] + } + ] + } + ] + } + ], { + "onlyonce": False, + "command": "", + } + + def get_page(self) -> List[dict]: + pass + + def stop_service(self): + """ + 退出插件 + """ + pass diff --git a/plugins/sqlexecute/__init__.py b/plugins/sqlexecute/__init__.py new file mode 100644 index 0000000..beca2ec --- /dev/null +++ b/plugins/sqlexecute/__init__.py @@ -0,0 +1,170 @@ +import sqlite3 + +from app.plugins import _PluginBase +from typing import Any, List, Dict, Tuple +from app.log import logger + + +class SqlExecute(_PluginBase): + # 插件名称 + plugin_name = "Sql执行器" + # 插件描述 + plugin_desc = "自定义MoviePilot数据库Sql执行。" + # 插件图标 + plugin_icon = "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/sqlite.png" + # 插件版本 + plugin_version = "1.0" + # 插件作者 + plugin_author = "thsrite" + # 作者主页 + author_url = "https://github.com/thsrite" + # 插件配置项ID前缀 + plugin_config_prefix = "sqlexecute_" + # 加载顺序 + plugin_order = 30 + # 可使用的用户级别 + auth_level = 1 + + # 私有属性 + _onlyonce = None + _sql = None + + def init_plugin(self, config: dict = None): + if config: + self._onlyonce = config.get("onlyonce") + self._sql = config.get("sql") + + if self._onlyonce and self._sql: + # 读取sqlite数据 + try: + gradedb = sqlite3.connect("/config/user.db") + except Exception as e: + logger.error(f"数据库链接失败 {str(e)}") + return + + # 创建游标cursor来执行executeSQL语句 + cursor = gradedb.cursor() + + # 执行SQL语句 + try: + for sql in self._sql.split("\n"): + logger.info(f"开始执行SQL语句 {sql}") + # 执行SQL语句 + cursor.execute(sql) + + print(cursor.fetchall()) + except Exception as e: + logger.error(f"SQL语句执行失败 {str(e)}") + return + finally: + # 关闭游标 + cursor.close() + + self._onlyonce = False + self.update_config({ + "onlyonce": self._onlyonce, + "sql": self._sql + }) + + def get_state(self) -> bool: + return False + + @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、数据结构 + """ + return [ + { + 'component': 'VForm', + 'content': [ + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'onlyonce', + 'label': '执行sql' + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + }, + 'content': [ + { + 'component': 'VTextarea', + 'props': { + 'model': 'sql', + 'rows': '2', + 'label': 'sql语句', + 'placeholder': '一行一条' + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + }, + 'content': [ + { + 'component': 'VAlert', + 'props': { + 'type': 'info', + 'variant': 'tonal' + }, + 'content': [ + { + 'component': 'span', + 'text': '执行日志将会输出到控制台,请谨慎操作。' + } + ] + } + ] + } + ] + } + ] + } + ], { + "onlyonce": False, + "sql": "", + } + + def get_page(self) -> List[dict]: + pass + + def stop_service(self): + """ + 退出插件 + """ + pass From 4bc784b29ebce1eeb69921de5b85dc69a8258cdb Mon Sep 17 00:00:00 2001 From: thsrite Date: Sun, 9 Jun 2024 11:23:51 +0800 Subject: [PATCH 13/21] fix README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 95011c0..c6c84bc 100644 --- a/README.md +++ b/README.md @@ -39,4 +39,6 @@ MoviePilot三方插件市场:https://github.com/thsrite/MoviePilot-Plugins/ - Emby媒体标签 v1.1 - 热门媒体订阅 v1.7 - [HomePage v1.2](docs%2FHomePage.md) -- 目录监控(统一入库消息增强版) v1.0 \ No newline at end of file +- 目录监控(统一入库消息增强版) v1.0 +- Sql执行器 v1.0 +- 命令执行器 v1.0 \ No newline at end of file From 2ad3e9aac7ff8ba3528754211e7ab4c45ec10c55 Mon Sep 17 00:00:00 2001 From: thsrite Date: Sun, 9 Jun 2024 11:29:59 +0800 Subject: [PATCH 14/21] fix log --- plugins/sqlexecute/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/sqlexecute/__init__.py b/plugins/sqlexecute/__init__.py index beca2ec..1e55126 100644 --- a/plugins/sqlexecute/__init__.py +++ b/plugins/sqlexecute/__init__.py @@ -52,7 +52,7 @@ class SqlExecute(_PluginBase): # 执行SQL语句 cursor.execute(sql) - print(cursor.fetchall()) + logger.info(cursor.fetchall()) except Exception as e: logger.error(f"SQL语句执行失败 {str(e)}") return From fecd271947fb79229e343fb6a66942bd045af59e Mon Sep 17 00:00:00 2001 From: thsrite Date: Sun, 9 Jun 2024 11:31:03 +0800 Subject: [PATCH 15/21] fix icon --- icons/command.png | Bin 6799 -> 3763 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/command.png b/icons/command.png index 8cfae4dc1a052618a78e690d2961227f5e1af994..f077761b6726f910f414b49e7ec6e14293886f7e 100644 GIT binary patch literal 3763 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 literal 6799 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 From e7b998a2ef598b35c29a4ddde2359ce5051209b6 Mon Sep 17 00:00:00 2001 From: thsrite Date: Sun, 9 Jun 2024 11:37:19 +0800 Subject: [PATCH 16/21] fix order --- plugins/commandexecute/__init__.py | 2 +- plugins/sqlexecute/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/commandexecute/__init__.py b/plugins/commandexecute/__init__.py index 0f924ad..c693c2d 100644 --- a/plugins/commandexecute/__init__.py +++ b/plugins/commandexecute/__init__.py @@ -21,7 +21,7 @@ class CommandExecute(_PluginBase): # 插件配置项ID前缀 plugin_config_prefix = "commandexecute_" # 加载顺序 - plugin_order = 30 + plugin_order = 99 # 可使用的用户级别 auth_level = 1 diff --git a/plugins/sqlexecute/__init__.py b/plugins/sqlexecute/__init__.py index 1e55126..5a9270f 100644 --- a/plugins/sqlexecute/__init__.py +++ b/plugins/sqlexecute/__init__.py @@ -21,7 +21,7 @@ class SqlExecute(_PluginBase): # 插件配置项ID前缀 plugin_config_prefix = "sqlexecute_" # 加载顺序 - plugin_order = 30 + plugin_order = 99 # 可使用的用户级别 auth_level = 1 From 20debbadcff5193b5996a82d6e5a21115e1b9d06 Mon Sep 17 00:00:00 2001 From: thsrite Date: Sun, 9 Jun 2024 12:56:30 +0800 Subject: [PATCH 17/21] =?UTF-8?q?fix=20=E6=94=AF=E6=8C=81=E4=BA=A4?= =?UTF-8?q?=E4=BA=92=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- package.json | 6 ++- plugins/commandexecute/__init__.py | 83 ++++++++++++++++++++++-------- plugins/sqlexecute/__init__.py | 61 ++++++++++++++++++++-- 4 files changed, 126 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index c6c84bc..595c921 100644 --- a/README.md +++ b/README.md @@ -40,5 +40,5 @@ MoviePilot三方插件市场:https://github.com/thsrite/MoviePilot-Plugins/ - 热门媒体订阅 v1.7 - [HomePage v1.2](docs%2FHomePage.md) - 目录监控(统一入库消息增强版) v1.0 -- Sql执行器 v1.0 -- 命令执行器 v1.0 \ No newline at end of file +- Sql执行器 v1.1 +- 命令执行器 v1.1 \ No newline at end of file diff --git a/package.json b/package.json index 888f5da..b835347 100644 --- a/package.json +++ b/package.json @@ -484,11 +484,12 @@ "name": "Sql执行器", "description": "自定义MoviePilot数据库Sql执行。", "labels": "工具", - "version": "1.0", + "version": "1.1", "icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/sqlite.png", "author": "thsrite", "level": 1, "history": { + "v1.1": "支持交互命令/cmd [command]执行,需主程序1.9.4+", "v1.0": "自定义MoviePilot数据库Sql执行" } }, @@ -496,11 +497,12 @@ "name": "命令执行器", "description": "自定义容器命令执行。", "labels": "工具", - "version": "1.0", + "version": "1.1", "icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/command.png", "author": "thsrite", "level": 1, "history": { + "v1.1": "支持交互命令/sql [sql]执行,需主程序1.9.4+", "v1.0": "自定义容器命令执行" } } diff --git a/plugins/commandexecute/__init__.py b/plugins/commandexecute/__init__.py index c693c2d..b848f9b 100644 --- a/plugins/commandexecute/__init__.py +++ b/plugins/commandexecute/__init__.py @@ -1,8 +1,10 @@ import subprocess +from app.core.event import eventmanager, Event from app.plugins import _PluginBase from typing import Any, List, Dict, Tuple from app.log import logger +from app.schemas.types import EventType class CommandExecute(_PluginBase): @@ -13,7 +15,7 @@ class CommandExecute(_PluginBase): # 插件图标 plugin_icon = "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/command.png" # 插件版本 - plugin_version = "1.0" + plugin_version = "1.1" # 插件作者 plugin_author = "thsrite" # 作者主页 @@ -39,24 +41,8 @@ class CommandExecute(_PluginBase): try: for command in self._command.split("\n"): logger.info(f"开始执行命令 {command}") - result = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - last_output = None - last_error = None - while True: - error = result.stderr.readline().decode("utf-8") - if error == '' and result.poll() is not None: - break - if error: - logger.info(error.strip()) - last_error = error.strip() - while True: - output = result.stdout.readline().decode("utf-8") - if output == '' and result.poll() is not None: - break - if output: - logger.info(output.strip()) - last_output = output.strip() - print(last_output if last_output else last_error) + last_output, last_error = self.execute_command(command) + logger.info(last_output if last_output else last_error) except Exception as e: logger.error(f"命令执行失败 {str(e)}") return @@ -67,12 +53,67 @@ class CommandExecute(_PluginBase): "command": self._command }) + @staticmethod + def execute_command(command: str): + """ + 执行命令 + :param command: 命令 + """ + result = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + last_output = None + last_error = None + while True: + error = result.stderr.readline().decode("utf-8") + if error == '' and result.poll() is not None: + break + if error: + logger.info(error.strip()) + last_error = error.strip() + while True: + output = result.stdout.readline().decode("utf-8") + if output == '' and result.poll() is not None: + break + if output: + logger.info(output.strip()) + last_output = output.strip() + + return last_output, last_error + + @eventmanager.register(EventType.PluginAction) + def execute(self, event: Event = None): + if event: + event_data = event.event_data + if not event_data or event_data.get("action") != "command_execute": + return + args = event_data.get("args") + if not args: + return + + logger.info(f"收到命令,开始执行命令 ...{args}") + last_output, last_error = self.execute_command(args) + self.post_message(channel=event.event_data.get("channel"), + title="命令执行结果", + text=last_output if last_output else last_error, + userid=event.event_data.get("user")) + def get_state(self) -> bool: - return False + return True @staticmethod def get_command() -> List[Dict[str, Any]]: - pass + """ + 定义远程控制命令 + :return: 命令关键字、事件、描述、附带数据 + """ + return [{ + "cmd": "/cmd", + "event": EventType.PluginAction, + "desc": "自定义命令执行", + "category": "", + "data": { + "action": "command_execute" + } + }] def get_api(self) -> List[Dict[str, Any]]: pass diff --git a/plugins/sqlexecute/__init__.py b/plugins/sqlexecute/__init__.py index 5a9270f..cdcc550 100644 --- a/plugins/sqlexecute/__init__.py +++ b/plugins/sqlexecute/__init__.py @@ -1,8 +1,10 @@ import sqlite3 +from app.core.event import eventmanager, Event from app.plugins import _PluginBase from typing import Any, List, Dict, Tuple from app.log import logger +from app.schemas.types import EventType class SqlExecute(_PluginBase): @@ -13,7 +15,7 @@ class SqlExecute(_PluginBase): # 插件图标 plugin_icon = "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/sqlite.png" # 插件版本 - plugin_version = "1.0" + plugin_version = "1.1" # 插件作者 plugin_author = "thsrite" # 作者主页 @@ -66,12 +68,65 @@ class SqlExecute(_PluginBase): "sql": self._sql }) + @eventmanager.register(EventType.PluginAction) + def execute(self, event: Event = None): + if event: + event_data = event.event_data + if not event_data or event_data.get("action") != "sql_execute": + return + args = event_data.get("args") + if not args: + return + + logger.info(f"收到命令,开始执行SQL ...{args}") + + # 读取sqlite数据 + try: + gradedb = sqlite3.connect("/config/user.db") + except Exception as e: + logger.error(f"数据库链接失败 {str(e)}") + return + + # 创建游标cursor来执行executeSQL语句 + cursor = gradedb.cursor() + + # 执行SQL语句 + try: + for sql in self._sql.split("\n"): + logger.info(f"开始执行SQL语句 {sql}") + # 执行SQL语句 + cursor.execute(sql) + + logger.info(cursor.fetchall()) + self.post_message(channel=event.event_data.get("channel"), + title="SQL执行结果", + text='\n'.join(cursor.fetchall()), + userid=event.event_data.get("user")) + except Exception as e: + logger.error(f"SQL语句执行失败 {str(e)}") + return + finally: + # 关闭游标 + cursor.close() + def get_state(self) -> bool: - return False + return True @staticmethod def get_command() -> List[Dict[str, Any]]: - pass + """ + 定义远程控制命令 + :return: 命令关键字、事件、描述、附带数据 + """ + return [{ + "cmd": "/sql", + "event": EventType.PluginAction, + "desc": "自定义sql执行", + "category": "", + "data": { + "action": "sql_execute" + } + }] def get_api(self) -> List[Dict[str, Any]]: pass From 9627fed64e0449f996df2b63f206ff2cee3f343d Mon Sep 17 00:00:00 2001 From: thsrite Date: Sun, 9 Jun 2024 18:27:23 +0800 Subject: [PATCH 18/21] =?UTF-8?q?fix=20v1.2=E8=B0=83=E6=95=B4=E4=BA=A4?= =?UTF-8?q?=E4=BA=92=E5=91=BD=E4=BB=A4=E8=BF=94=E5=9B=9E=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- package.json | 7 ++++--- plugins/commandexecute/__init__.py | 21 +++++++++++---------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 595c921..87bc3c5 100644 --- a/README.md +++ b/README.md @@ -41,4 +41,4 @@ MoviePilot三方插件市场:https://github.com/thsrite/MoviePilot-Plugins/ - [HomePage v1.2](docs%2FHomePage.md) - 目录监控(统一入库消息增强版) v1.0 - Sql执行器 v1.1 -- 命令执行器 v1.1 \ No newline at end of file +- 命令执行器 v1.2 \ No newline at end of file diff --git a/package.json b/package.json index b835347..001b679 100644 --- a/package.json +++ b/package.json @@ -489,7 +489,7 @@ "author": "thsrite", "level": 1, "history": { - "v1.1": "支持交互命令/cmd [command]执行,需主程序1.9.4+", + "v1.1": "支持交互命令/sql [command]执行,需主程序1.9.4+", "v1.0": "自定义MoviePilot数据库Sql执行" } }, @@ -497,12 +497,13 @@ "name": "命令执行器", "description": "自定义容器命令执行。", "labels": "工具", - "version": "1.1", + "version": "1.2", "icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/command.png", "author": "thsrite", "level": 1, "history": { - "v1.1": "支持交互命令/sql [sql]执行,需主程序1.9.4+", + "v1.2": "调整交互命令返回信息", + "v1.1": "支持交互命令/cmd [sql]执行,需主程序1.9.4+", "v1.0": "自定义容器命令执行" } } diff --git a/plugins/commandexecute/__init__.py b/plugins/commandexecute/__init__.py index b848f9b..d05a08b 100644 --- a/plugins/commandexecute/__init__.py +++ b/plugins/commandexecute/__init__.py @@ -15,7 +15,7 @@ class CommandExecute(_PluginBase): # 插件图标 plugin_icon = "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/command.png" # 插件版本 - plugin_version = "1.1" + plugin_version = "1.2" # 插件作者 plugin_author = "thsrite" # 作者主页 @@ -41,8 +41,8 @@ class CommandExecute(_PluginBase): try: for command in self._command.split("\n"): logger.info(f"开始执行命令 {command}") - last_output, last_error = self.execute_command(command) - logger.info(last_output if last_output else last_error) + ouptut = self.execute_command(command) + # logger.info('\n'.join(ouptut)) except Exception as e: logger.error(f"命令执行失败 {str(e)}") return @@ -60,24 +60,23 @@ class CommandExecute(_PluginBase): :param command: 命令 """ result = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - last_output = None - last_error = None + ouptut = [] while True: error = result.stderr.readline().decode("utf-8") if error == '' and result.poll() is not None: break if error: logger.info(error.strip()) - last_error = error.strip() + ouptut.append(error.strip()) while True: output = result.stdout.readline().decode("utf-8") if output == '' and result.poll() is not None: break if output: logger.info(output.strip()) - last_output = output.strip() + ouptut.append(output.strip()) - return last_output, last_error + return ouptut @eventmanager.register(EventType.PluginAction) def execute(self, event: Event = None): @@ -85,15 +84,17 @@ class CommandExecute(_PluginBase): event_data = event.event_data if not event_data or event_data.get("action") != "command_execute": return + logger.info(f"收到命令执行事件 ...{event_data}") args = event_data.get("args") if not args: return logger.info(f"收到命令,开始执行命令 ...{args}") - last_output, last_error = self.execute_command(args) + ouptut = self.execute_command(args) + # logger.info('\n'.join(ouptut)) self.post_message(channel=event.event_data.get("channel"), title="命令执行结果", - text=last_output if last_output else last_error, + text='\n'.join(ouptut), userid=event.event_data.get("user")) def get_state(self) -> bool: From 2e809d7751b76baade839884ea9a312ffc7e25b7 Mon Sep 17 00:00:00 2001 From: thsrite Date: Sun, 9 Jun 2024 18:53:47 +0800 Subject: [PATCH 19/21] =?UTF-8?q?fix=20v1.2=E8=B0=83=E6=95=B4=E4=BA=A4?= =?UTF-8?q?=E4=BA=92=E5=91=BD=E4=BB=A4=E8=BF=94=E5=9B=9E=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- package.json | 3 +- plugins/sqlexecute/__init__.py | 52 ++++++++++++++++++++++++++-------- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 87bc3c5..c497467 100644 --- a/README.md +++ b/README.md @@ -40,5 +40,5 @@ MoviePilot三方插件市场:https://github.com/thsrite/MoviePilot-Plugins/ - 热门媒体订阅 v1.7 - [HomePage v1.2](docs%2FHomePage.md) - 目录监控(统一入库消息增强版) v1.0 -- Sql执行器 v1.1 +- Sql执行器 v1.2 - 命令执行器 v1.2 \ No newline at end of file diff --git a/package.json b/package.json index 001b679..61337e4 100644 --- a/package.json +++ b/package.json @@ -484,11 +484,12 @@ "name": "Sql执行器", "description": "自定义MoviePilot数据库Sql执行。", "labels": "工具", - "version": "1.1", + "version": "1.2", "icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/sqlite.png", "author": "thsrite", "level": 1, "history": { + "v1.2": "调整交互命令返回信息", "v1.1": "支持交互命令/sql [command]执行,需主程序1.9.4+", "v1.0": "自定义MoviePilot数据库Sql执行" } diff --git a/plugins/sqlexecute/__init__.py b/plugins/sqlexecute/__init__.py index cdcc550..3aff415 100644 --- a/plugins/sqlexecute/__init__.py +++ b/plugins/sqlexecute/__init__.py @@ -4,7 +4,7 @@ from app.core.event import eventmanager, Event from app.plugins import _PluginBase from typing import Any, List, Dict, Tuple from app.log import logger -from app.schemas.types import EventType +from app.schemas.types import EventType, MessageChannel class SqlExecute(_PluginBase): @@ -15,7 +15,7 @@ class SqlExecute(_PluginBase): # 插件图标 plugin_icon = "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/sqlite.png" # 插件版本 - plugin_version = "1.1" + plugin_version = "1.2" # 插件作者 plugin_author = "thsrite" # 作者主页 @@ -54,7 +54,21 @@ class SqlExecute(_PluginBase): # 执行SQL语句 cursor.execute(sql) - logger.info(cursor.fetchall()) + rows = cursor.fetchall() + if 'select' in sql.lower(): + # 获取列名 + columns = [desc[0] for desc in cursor.description] + # 将查询结果转换为key-value对的列表 + results = [] + for row in rows: + result = dict(zip(columns, row)) + results.append(result) + result = "\n".join([str(i) for i in results]) + else: + result = "\n".join([str(i) for i in rows]) + + result = str(result).replace("'", "\"") + logger.info(result) except Exception as e: logger.error(f"SQL语句执行失败 {str(e)}") return @@ -92,16 +106,30 @@ class SqlExecute(_PluginBase): # 执行SQL语句 try: - for sql in self._sql.split("\n"): - logger.info(f"开始执行SQL语句 {sql}") - # 执行SQL语句 - cursor.execute(sql) + # 执行SQL语句 + cursor.execute(args) + rows = cursor.fetchall() + if 'select' in args.lower(): + # 获取列名 + columns = [desc[0] for desc in cursor.description] + # 将查询结果转换为key-value对的列表 + results = [] + for row in rows: + result = dict(zip(columns, row)) + results.append(result) + result = "\n".join([str(i) for i in results]) + else: + result = "\n".join([str(i) for i in rows]) - logger.info(cursor.fetchall()) - self.post_message(channel=event.event_data.get("channel"), - title="SQL执行结果", - text='\n'.join(cursor.fetchall()), - userid=event.event_data.get("user")) + result = str(result).replace("'", "\"") + logger.info(result) + + if event.event_data.get("channel") == MessageChannel.Telegram: + result = f"```plaintext\n{result}\n```" + self.post_message(channel=event.event_data.get("channel"), + title="SQL执行结果", + text=result, + userid=event.event_data.get("user")) except Exception as e: logger.error(f"SQL语句执行失败 {str(e)}") return From 82f649b4a9dfd7b6c4af75f2361b63714589fb8c Mon Sep 17 00:00:00 2001 From: thsrite Date: Sun, 9 Jun 2024 18:56:24 +0800 Subject: [PATCH 20/21] fix --- plugins/commandexecute/__init__.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/commandexecute/__init__.py b/plugins/commandexecute/__init__.py index d05a08b..5747647 100644 --- a/plugins/commandexecute/__init__.py +++ b/plugins/commandexecute/__init__.py @@ -4,7 +4,7 @@ from app.core.event import eventmanager, Event from app.plugins import _PluginBase from typing import Any, List, Dict, Tuple from app.log import logger -from app.schemas.types import EventType +from app.schemas.types import EventType, MessageChannel class CommandExecute(_PluginBase): @@ -91,10 +91,13 @@ class CommandExecute(_PluginBase): logger.info(f"收到命令,开始执行命令 ...{args}") ouptut = self.execute_command(args) - # logger.info('\n'.join(ouptut)) + result = '\n'.join(ouptut) + + if event.event_data.get("channel") == MessageChannel.Telegram: + result = f"```plaintext\n{result}\n```" self.post_message(channel=event.event_data.get("channel"), title="命令执行结果", - text='\n'.join(ouptut), + text=result, userid=event.event_data.get("user")) def get_state(self) -> bool: From 2ff19ba35fa4b872ca8986af575992ded6edadb2 Mon Sep 17 00:00:00 2001 From: thsrite Date: Sun, 9 Jun 2024 19:01:44 +0800 Subject: [PATCH 21/21] fix alert --- plugins/commandexecute/__init__.py | 26 ++++++++++++++++++++++++++ plugins/sqlexecute/__init__.py | 26 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/plugins/commandexecute/__init__.py b/plugins/commandexecute/__init__.py index 5747647..8d16d91 100644 --- a/plugins/commandexecute/__init__.py +++ b/plugins/commandexecute/__init__.py @@ -198,6 +198,32 @@ class CommandExecute(_PluginBase): ] } ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + }, + 'content': [ + { + 'component': 'VAlert', + 'props': { + 'type': 'info', + 'variant': 'tonal' + }, + 'content': [ + { + 'component': 'span', + 'text': '可使用交互命令/cmd ls' + } + ] + } + ] + } + ] } ] } diff --git a/plugins/sqlexecute/__init__.py b/plugins/sqlexecute/__init__.py index 3aff415..d544aa5 100644 --- a/plugins/sqlexecute/__init__.py +++ b/plugins/sqlexecute/__init__.py @@ -235,6 +235,32 @@ class SqlExecute(_PluginBase): ] } ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + }, + 'content': [ + { + 'component': 'VAlert', + 'props': { + 'type': 'info', + 'variant': 'tonal' + }, + 'content': [ + { + 'component': 'span', + 'text': '可使用交互命令/sql select *****' + } + ] + } + ] + } + ] } ] }