From a82967eeafbd995fb5985c080a35a9f1a5d6f269 Mon Sep 17 00:00:00 2001 From: thsrite Date: Mon, 3 Jun 2024 16:06:48 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E7=9B=AE=E5=BD=95=E7=9B=91=E6=8E=A7?= =?UTF-8?q?=EF=BC=88=E7=BB=9F=E4=B8=80=E5=85=A5=E5=BA=93=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E7=89=88=EF=BC=89=20v1.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 61 +++++---- package.json | 12 ++ .../__init__.py | 129 +++++++++++++++--- 3 files changed, 150 insertions(+), 52 deletions(-) rename plugins/{dirmonitor => dirmonitorEnhanced}/__init__.py (86%) diff --git a/README.md b/README.md index 7f6cdf1..37c3fb3 100644 --- a/README.md +++ b/README.md @@ -9,33 +9,34 @@ MoviePilot三方插件市场:https://github.com/thsrite/MoviePilot-Plugins/ ### 插件新增 -- 站点数据统计 1.4 (无未读消息版本)(废弃) -- 站点未读消息 1.9 (依赖于[站点数据统计]插件) -- [云盘Strm生成 4.0](docs%2FCloudStrm.md) -- [云盘Strm生成(增量版) 1.0](docs%2FCloudStrmIncrement.md) -- [Strm文件模式转换 1.0](docs%2FStrmConvert.md) -- 清理订阅缓存 1.0 -- 添加种子下载 1.0 -- 删除站点种子 1.2 -- 插件更新管理 1.9 -- 插件强制重装 1.7 -- 群辉Webhook通知 1.1 -- 同步CookieCloud 1.2 -- 日程提醒 1.0 -- 订阅提醒 1.1 -- [Emby观影报告 1.5](docs%2FEmbyReporter.md) -- 演员订阅 1.8 -- [短剧刮削 3.2](docs%2FShortPlayMonitor.md) -- 云盘实时监控 2.1 -- 源文件恢复 1.2 -- [微信消息转发 2.5](docs%2FWeChatForward.md) -- 订阅下载统计 1.5 -- [自定义命令 1.7](docs%2FCustomCommand.md) -- docker自定义任务 1.3 -- 插件彻底卸载 1.0 -- 实时软连接 1.3 -- 订阅规则自动填充 2.7 -- Emby元数据刷新 1.1 -- Emby媒体标签 1.1 -- 热门媒体订阅 1.7 -- [HomePage 1.2](docs%2FHomePage.md) +- 站点数据统计 v1.4 (无未读消息版本)(废弃) +- 站点未读消息 v1.9 (依赖于[站点数据统计]插件) +- [云盘Strm生成 v4.0](docs%2FCloudStrm.md) +- [云盘Strm生成(增量版) v1.0](docs%2FCloudStrmIncrement.md) +- [Strm文件模式转换 v1.0](docs%2FStrmConvert.md) +- 清理订阅缓存 v1.0 +- 添加种子下载 v1.0 +- 删除站点种子 v1.2 +- 插件更新管理 v1.9 +- 插件强制重装 v1.7 +- 群辉Webhook通知 v1.1 +- 同步CookieCloud v1.2 +- 日程提醒 v1.0 +- 订阅提醒 v1.1 +- [Emby观影报告 v1.5](docs%2FEmbyReporter.md) +- 演员订阅 v1.8 +- [短剧刮削 v3.2](docs%2FShortPlayMonitor.md) +- 云盘实时监控 v2.1 +- 源文件恢复 v1.2 +- [微信消息转发 v2.5](docs%2FWeChatForward.md) +- 订阅下载统计 v1.5 +- [自定义命令 v1.7](docs%2FCustomCommand.md) +- docker自定义任务 v1.3 +- 插件彻底卸载 v1.0 +- 实时软连接 v1.3 +- 订阅规则自动填充 v2.7 +- Emby元数据刷新 v1.1 +- Emby媒体标签 v1.1 +- 热门媒体订阅 v1.7 +- [HomePage v1.2](docs%2FHomePage.md) +- 目录监控(统一入库消息增强版) v1.0 \ No newline at end of file diff --git a/package.json b/package.json index 5d82f05..95964c5 100644 --- a/package.json +++ b/package.json @@ -461,5 +461,17 @@ "v1.1": "支持更多返回值、插件展示数据", "v1.0": "HomePage自定义API" } + }, + "DirMonitorEnhanced": { + "name": "目录监控", + "description": "监控目录文件发生变化时实时整理到媒体库。(统一入库消息增强版)", + "labels": "文件整理", + "version": "1.0", + "icon": "directory.png", + "author": "thsrite", + "level": 1, + "history": { + "v1.0": "同步merge主仓库[目录监控]插件,增加统一发送消息逻辑(Testing…)" + } } } diff --git a/plugins/dirmonitor/__init__.py b/plugins/dirmonitorEnhanced/__init__.py similarity index 86% rename from plugins/dirmonitor/__init__.py rename to plugins/dirmonitorEnhanced/__init__.py index ac83f5d..fb54ace 100644 --- a/plugins/dirmonitor/__init__.py +++ b/plugins/dirmonitorEnhanced/__init__.py @@ -51,21 +51,21 @@ class FileMonitorHandler(FileSystemEventHandler): mon_path=self._watch_path, event_path=event.dest_path) -class DirMonitor(_PluginBase): +class DirMonitorEnhanced(_PluginBase): # 插件名称 plugin_name = "目录监控" # 插件描述 - plugin_desc = "监控目录文件发生变化时实时整理到媒体库。" + plugin_desc = "监控目录文件发生变化时实时整理到媒体库。(统一入库消息增强版)" # 插件图标 plugin_icon = "directory.png" # 插件版本 - plugin_version = "2.0" + plugin_version = "1.0" # 插件作者 - plugin_author = "jxxghp" + plugin_author = "thsrite" # 作者主页 - author_url = "https://github.com/jxxghp" + author_url = "https://github.com/thsrite" # 插件配置项ID前缀 - plugin_config_prefix = "dirmonitor_" + plugin_config_prefix = "dirmonitorenhanced_" # 加载顺序 plugin_order = 4 # 可使用的用户级别 @@ -83,10 +83,11 @@ class DirMonitor(_PluginBase): _onlyonce = False _cron = None _size = 0 + _scrape = True # 模式 compatibility/fast _mode = "fast" # 转移方式 - _transfer_type = settings.TRANSFER_TYPE + _transfer_type = "link" _monitor_dirs = "" _exclude_keywords = "" _interval: int = 10 @@ -119,6 +120,7 @@ class DirMonitor(_PluginBase): self._interval = config.get("interval") or 10 self._cron = config.get("cron") self._size = config.get("size") or 0 + self._scrape = config.get("scrape") or False # 停止现有任务 self.stop_service() @@ -172,7 +174,8 @@ class DirMonitor(_PluginBase): try: if target_path and target_path.is_relative_to(Path(mon_path)): logger.warn(f"{target_path} 是监控目录 {mon_path} 的子目录,无法监控") - self.systemmessage.put(f"{target_path} 是下载目录 {mon_path} 的子目录,无法监控") + self.systemmessage.put(f"{target_path} 是下载目录 {mon_path} 的子目录,无法监控", + title="目录监控") continue except Exception as e: logger.debug(str(e)) @@ -202,7 +205,7 @@ class DirMonitor(_PluginBase): """) else: logger.error(f"{mon_path} 启动目录监控失败:{err_msg}") - self.systemmessage.put(f"{mon_path} 启动目录监控失败:{err_msg}") + self.systemmessage.put(f"{mon_path} 启动目录监控失败:{err_msg}", title="目录监控") # 运行一次定时服务 if self._onlyonce: @@ -235,7 +238,8 @@ class DirMonitor(_PluginBase): "exclude_keywords": self._exclude_keywords, "interval": self._interval, "cron": self._cron, - "size": self._size + "size": self._size, + "scrape": self._scrape }) @eventmanager.register(EventType.PluginAction) @@ -426,6 +430,20 @@ class DirMonitor(_PluginBase): return if not transferinfo.success: + # 判断是否转移后文件已存在,补充转移成功历史记录 + if transferinfo.target_path and transferinfo.target_path.exists(): + logger.info(f"{file_path.name} 目标文件已存在,补充转移成功历史记录") + # 补充转移成功历史记录 + self.transferhis.add_success( + src_path=file_path, + mode=transfer_type, + download_hash=download_hash, + meta=file_meta, + mediainfo=mediainfo, + transferinfo=transferinfo + ) + return + # 转移失败 logger.warn(f"{file_path.name} 入库失败:{transferinfo.message}") # 新增转移失败历史记录 @@ -457,7 +475,7 @@ class DirMonitor(_PluginBase): ) # 刮削单个文件 - if settings.SCRAP_METADATA: + if self._scrape: self.chain.scrape_metadata(path=transferinfo.target_path, mediainfo=mediainfo, transfer_type=transfer_type) @@ -473,7 +491,8 @@ class DirMonitor(_PluginBase): "transferinfo": } ], - "time": "2023-08-24 23:23:23.332" + "time": "2023-08-24 23:23:23.332", + "all_files_cnt": 20 } } """ @@ -505,9 +524,13 @@ class DirMonitor(_PluginBase): ] media_list = { "files": media_files, - "time": datetime.datetime.now() + "time": datetime.datetime.now(), + "all_files_cnt": media_list.get("all_files_cnt") } else: + # 获取当前媒体本次下载的文件数 + recent_download_files_cnt = self.__get_recent_download_files_cnt(download_hash=download_hash) + media_list = { "files": [ { @@ -517,7 +540,8 @@ class DirMonitor(_PluginBase): "transferinfo": transferinfo } ], - "time": datetime.datetime.now() + "time": datetime.datetime.now(), + "all_files_cnt": recent_download_files_cnt } self._medias[mediainfo.title_year + " " + file_meta.season] = media_list @@ -542,6 +566,40 @@ class DirMonitor(_PluginBase): except Exception as e: logger.error("目录监控发生错误:%s - %s" % (str(e), traceback.format_exc())) + def __get_recent_download_files_cnt(self, download_hash: str): + """ + 1。根据download_hash查询下载历史 + 2。查询该下载历史记录创建时间前1分钟及以后的所有的该type和tmdbid下的下载历史(订阅批量下载的话,下载时间间隔应该不会超过一分钟吧。) + 3。根据查询到的下载历史列表遍历查询对应的下载文件记录 + 4。根据统计的下载文件记录数目,等待入库消息统一发送。 + 5。统一入库消息(如果当前入库的媒体数据 < 本次批量下载的文件数量,暂不处理,等待一会(容错:最大retry 5次)) + """ + # 根据download_hash查询下载记录 + recent_download_files = 0 + try: + download_history = self.downloadhis.get_by_hash(download_hash=download_hash) + if download_history: + # 根据下载历史查询 下载时间前一分钟及以后的下载记录 + # 将时间字符串转换为datetime对象 - 减去一分钟 + new_dt = datetime.datetime.strptime(download_history.date, "%Y-%m-%d %H:%M:%S") - datetime.timedelta( + minutes=1) + download_historys = self.downloadhis.list_by_date(date=new_dt.strftime("%Y-%m-%d %H:%M:%S"), + type=download_history.type, + tmdbid=str(download_history.tmdbid), + seasons=download_history.seasons) + if download_historys: + for download_his in download_historys: + # 根据download_hash获取下载文件列表 + download_files = self.downloadhis.get_files_by_hash( + download_hash=download_his.download_hash, + state=1) + if download_files: + recent_download_files += len(download_files) + except Exception as e: + print(str(e)) + + return recent_download_files + def send_msg(self): """ 定时检查是否有媒体处理完,发送统一消息 @@ -563,15 +621,25 @@ class DirMonitor(_PluginBase): if not last_update_time or not media_files: continue + all_files_cnt = media_list.get("all_files_cnt") or 0 + retry_cnt = media_list.get("retry_cnt") or 0 transferinfo = media_files[0].get("transferinfo") file_meta = media_files[0].get("file_meta") mediainfo = media_files[0].get("mediainfo") # 判断剧集最后更新时间距现在是已超过10秒或者电影,发送消息 if (datetime.datetime.now() - last_update_time).total_seconds() > int(self._interval) \ or mediainfo.type == MediaType.MOVIE: + + # 如果当前入库的媒体数据 < 本次批量下载的文件数量,暂不处理,等待一会(容错:最大retry 5次) + if all_files_cnt > 0 and len(media_files) < all_files_cnt and retry_cnt < 5: + # 更新重试次数 + media_list['retry_cnt'] = retry_cnt + 1 + self._medias[medis_title_year_season] = media_list + logger.info(f"本次批量下载任务未完成转移,等待{int(self._interval)}秒开始重试{retry_cnt + 1}次") + continue + # 发送通知 if self._notify: - # 汇总处理文件总大小 total_size = 0 file_count = 0 @@ -756,7 +824,7 @@ class DirMonitor(_PluginBase): 'component': 'VSelect', 'props': { 'model': 'transfer_type', - 'label': '转移方式', + 'label': '整理方式', 'items': [ {'title': '移动', 'value': 'move'}, {'title': '复制', 'value': 'copy'}, @@ -824,6 +892,22 @@ class DirMonitor(_PluginBase): } } ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'scrape', + 'label': '刮削元数据', + } + } + ] } ] }, @@ -844,9 +928,9 @@ class DirMonitor(_PluginBase): 'rows': 5, 'placeholder': '每一行一个目录,支持以下几种配置方式,转移方式支持 move、copy、link、softlink、rclone_copy、rclone_move:\n' '监控目录\n' - '监控目录#转移方式\n' - '监控目录:转移目的目录\n' - '监控目录:转移目的目录#转移方式' + '监控目录#整理方式\n' + '监控目录:整理目的目录\n' + '监控目录:整理目的目录#转移方式' } } ] @@ -889,7 +973,7 @@ class DirMonitor(_PluginBase): 'props': { 'type': 'info', 'variant': 'tonal', - 'text': '监控目录不指定目的目录时,将转移到媒体库目录,并自动创建一级分类目录,同时按配置创建二级分类目录;监控目录指定了目的目录时,不会自动创建一级目录,但会根据配置创建二级分类目录。' + 'text': '支持4种配置方式:1、监控目录,2、监控目录#整理方式,3、监控目录:整理目的目录,4、监控目录:整理目的目录#转移方式。监控目录不指定目的目录时,将按媒体库目录设置整理到媒体库目录,并根据目录的分类设置自动创建一二级分类目录;监控目录指定了目的目录时,会尝试在媒体库目录设定中查找对应路径的目录配置,如存在则以目录设定的分类选项创建子目录,否则直接整理到该目的目录下。建议不设置目的目录,由系统根据目录设定自动分类整理。' } } ] @@ -945,12 +1029,13 @@ class DirMonitor(_PluginBase): "notify": False, "onlyonce": False, "mode": "fast", - "transfer_type": settings.TRANSFER_TYPE, + "transfer_type": "link", "monitor_dirs": "", "exclude_keywords": "", "interval": 10, "cron": "", - "size": 0 + "size": 0, + "scrape": True } def get_page(self) -> List[dict]: