From 36dbdb57f03f15070ad5dce068efb8be199e16e7 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 20 Aug 2023 08:23:17 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E7=9B=AE=E5=BD=95=E7=9B=91=E6=8E=A7?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E9=85=8D=E7=BD=AE=E7=8B=AC=E7=AB=8B=E7=9A=84?= =?UTF-8?q?=E7=9B=AE=E7=9A=84=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/chain/__init__.py | 4 +- app/modules/filetransfer/__init__.py | 10 +- app/plugins/dirmonitor/__init__.py | 321 +++++++++++++++------------ 3 files changed, 182 insertions(+), 153 deletions(-) diff --git a/app/chain/__init__.py b/app/chain/__init__.py index 21f3feaa..8d0266a8 100644 --- a/app/chain/__init__.py +++ b/app/chain/__init__.py @@ -271,17 +271,19 @@ class ChainBase(metaclass=ABCMeta): def transfer(self, path: Path, mediainfo: MediaInfo, transfer_type: str, + target: Path = None, meta: MetaBase = None) -> Optional[TransferInfo]: """ 文件转移 :param path: 文件路径 :param mediainfo: 识别的媒体信息 :param transfer_type: 转移模式 + :param target: 转移目标路径 :param meta: 预识别的元数据,仅单文件转移时传递 :return: {path, target_path, message} """ return self.run_module("transfer", path=path, mediainfo=mediainfo, - transfer_type=transfer_type, meta=meta) + transfer_type=transfer_type, target=target, meta=meta) def transfer_completed(self, hashs: Union[str, list], transinfo: TransferInfo) -> None: """ diff --git a/app/modules/filetransfer/__init__.py b/app/modules/filetransfer/__init__.py index 98cc2178..e77e35e2 100644 --- a/app/modules/filetransfer/__init__.py +++ b/app/modules/filetransfer/__init__.py @@ -30,25 +30,27 @@ class FileTransferModule(_ModuleBase): pass def transfer(self, path: Path, mediainfo: MediaInfo, - transfer_type: str, meta: MetaBase = None) -> TransferInfo: + transfer_type: str, target: Path = None, meta: MetaBase = None) -> TransferInfo: """ 文件转移 :param path: 文件路径 :param mediainfo: 识别的媒体信息 :param transfer_type: 转移方式 + :param target: 目标路径 :param meta: 预识别的元数据,仅单文件转移时传递 :return: {path, target_path, message} """ # 获取目标路径 - target_path = self.get_target_path(in_path=path) - if not target_path: + if not target: + target = self.get_target_path(in_path=path) + if not target: logger.error("未找到媒体库目录,无法转移文件") return TransferInfo(message="未找到媒体库目录,无法转移文件") # 转移 return self.transfer_media(in_path=path, mediainfo=mediainfo, transfer_type=transfer_type, - target_dir=target_path, + target_dir=target, in_meta=meta) @staticmethod diff --git a/app/plugins/dirmonitor/__init__.py b/app/plugins/dirmonitor/__init__.py index 1c79a1e6..20a1d335 100644 --- a/app/plugins/dirmonitor/__init__.py +++ b/app/plugins/dirmonitor/__init__.py @@ -33,10 +33,12 @@ class FileMonitorHandler(FileSystemEventHandler): self.sync = sync def on_created(self, event): - self.sync.file_change_handler(event, "创建", event.src_path) + self.sync.event_handler(event=event, text="创建", + mon_path=self._watch_path, event_path=event.src_path) def on_moved(self, event): - self.sync.file_change_handler(event, "移动", event.dest_path) + self.sync.event_handler(event=event, text="移动", + mon_path=self._watch_path, event_path=event.dest_path) class DirMonitor(_PluginBase): @@ -77,12 +79,17 @@ class DirMonitor(_PluginBase): _transfer_type = settings.TRANSFER_TYPE _monitor_dirs = "" _exclude_keywords = "" + # 存储源目录与目的目录关系 + _dirconf: Dict[str, str] = {} def init_plugin(self, config: dict = None): self.transferhis = TransferHistoryOper() self.downloadhis = DownloadHistoryOper() self.transferchian = TransferChain() + # 清空配置 + self._dirconf = {} + # 读取配置 if config: self._enabled = config.get("enabled") @@ -101,13 +108,24 @@ class DirMonitor(_PluginBase): if not monitor_dirs: return for mon_path in monitor_dirs: + # 格式源目录:目的目录 if not mon_path: continue + + # 存储目的目录 + paths = mon_path.split(":") + if len(paths > 1): + mon_path = paths[0] + self._dirconf[mon_path] = paths[1] + # 检查目录是不是媒体库目录的子目录 - if Path(mon_path).is_relative_to(settings.LIBRARY_PATH): - logger.warn(f"{mon_path} 是媒体库目录的子目录,无法监控") - self.systemmessage.put(f"{mon_path} 是媒体库目录的子目录,无法监控") - continue + try: + if Path(mon_path).is_relative_to(settings.LIBRARY_PATH): + logger.warn(f"{mon_path} 是媒体库目录的子目录,无法监控") + self.systemmessage.put(f"{mon_path} 是媒体库目录的子目录,无法监控") + continue + except Exception as e: + pass try: if self._mode == "compatibility": @@ -135,10 +153,11 @@ class DirMonitor(_PluginBase): logger.error(f"{mon_path} 启动目录监控失败:{err_msg}") self.systemmessage.put(f"{mon_path} 启动目录监控失败:{err_msg}") - def file_change_handler(self, event, text: str, event_path: str): + def event_handler(self, event, mon_path: str, text: str, event_path: str): """ 处理文件变化 :param event: 事件 + :param mon_path: 监控目录 :param text: 事件描述 :param event_path: 事件文件路径 """ @@ -210,10 +229,14 @@ class DirMonitor(_PluginBase): # 更新媒体图片 self.chain.obtain_images(mediainfo=mediainfo) + # 查询转移目的目录 + target = self._dirconf.get(mon_path) + # 转移 transferinfo: TransferInfo = self.chain.transfer(mediainfo=mediainfo, path=file_path, transfer_type=self._transfer_type, + target=target, meta=file_meta) if not transferinfo: @@ -287,147 +310,149 @@ class DirMonitor(_PluginBase): def get_form(self) -> Tuple[List[dict], Dict[str, Any]]: return [ - { - 'component': 'VForm', - 'content': [ - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 6 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'enabled', - 'label': '启用插件', - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 6 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'notify', - 'label': '发送通知', - } - } - ] - } - ] - }, - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 6 - }, - 'content': [ - { - 'component': 'VSelect', - 'props': { - 'model': 'mode', - 'label': '监控模式', - 'items': [ - {'title': '兼容模式', 'value': 'compatibility'}, - {'title': '性能模式', 'value': 'fast'} - ] - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 6 - }, - 'content': [ - { - 'component': 'VSelect', - 'props': { - 'model': 'transfer_type', - 'label': '转移方式', - 'items': [ - {'title': '移动', 'value': 'move'}, - {'title': '复制', 'value': 'copy'}, - {'title': '硬链接', 'value': 'link'}, - {'title': '软链接', 'value': 'softlink'} - ] - } - } - ] - } - ] - }, - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12 - }, - 'content': [ - { - 'component': 'VTextarea', - 'props': { - 'model': 'monitor_dirs', - 'label': '监控目录', - 'rows': 5, - 'placeholder': '每一行一个目录' - } - } - ] - } - ] - }, - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12 - }, - 'content': [ - { - 'component': 'VTextarea', - 'props': { - 'model': 'exclude_keywords', - 'label': '排除关键词', - 'rows': 2, - 'placeholder': '每一行一个关键词' - } - } - ] - } - ] - } - ] - } - ], { - "enabled": False, - "notify": False, - "mode": "fast", - "transfer_type": settings.TRANSFER_TYPE, - "monitor_dirs": "", - "exclude_keywords": "" - } + { + 'component': 'VForm', + 'content': [ + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'enabled', + 'label': '启用插件', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'notify', + 'label': '发送通知', + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'model': 'mode', + 'label': '监控模式', + 'items': [ + {'title': '兼容模式', 'value': 'compatibility'}, + {'title': '性能模式', 'value': 'fast'} + ] + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'model': 'transfer_type', + 'label': '转移方式', + 'items': [ + {'title': '移动', 'value': 'move'}, + {'title': '复制', 'value': 'copy'}, + {'title': '硬链接', 'value': 'link'}, + {'title': '软链接', 'value': 'softlink'} + ] + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12 + }, + 'content': [ + { + 'component': 'VTextarea', + 'props': { + 'model': 'monitor_dirs', + 'label': '监控目录', + 'rows': 5, + 'placeholder': '每一行一个目录,支持两种配置方式:\n' + '监控目录\n' + '监控目录:转移目的目录' + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12 + }, + 'content': [ + { + 'component': 'VTextarea', + 'props': { + 'model': 'exclude_keywords', + 'label': '排除关键词', + 'rows': 2, + 'placeholder': '每一行一个关键词' + } + } + ] + } + ] + } + ] + } + ], { + "enabled": False, + "notify": False, + "mode": "fast", + "transfer_type": settings.TRANSFER_TYPE, + "monitor_dirs": "", + "exclude_keywords": "" + } def get_page(self) -> List[dict]: pass