feat 目录监控支持配置独立的目的目录

This commit is contained in:
jxxghp 2023-08-20 08:23:17 +08:00
parent 29568b43d8
commit 36dbdb57f0
3 changed files with 182 additions and 153 deletions

View File

@ -271,17 +271,19 @@ class ChainBase(metaclass=ABCMeta):
def transfer(self, path: Path, mediainfo: MediaInfo, def transfer(self, path: Path, mediainfo: MediaInfo,
transfer_type: str, transfer_type: str,
target: Path = None,
meta: MetaBase = None) -> Optional[TransferInfo]: meta: MetaBase = None) -> Optional[TransferInfo]:
""" """
文件转移 文件转移
:param path: 文件路径 :param path: 文件路径
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息
:param transfer_type: 转移模式 :param transfer_type: 转移模式
:param target: 转移目标路径
:param meta: 预识别的元数据仅单文件转移时传递 :param meta: 预识别的元数据仅单文件转移时传递
:return: {path, target_path, message} :return: {path, target_path, message}
""" """
return self.run_module("transfer", path=path, mediainfo=mediainfo, 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: def transfer_completed(self, hashs: Union[str, list], transinfo: TransferInfo) -> None:
""" """

View File

@ -30,25 +30,27 @@ class FileTransferModule(_ModuleBase):
pass pass
def transfer(self, path: Path, mediainfo: MediaInfo, 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 path: 文件路径
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息
:param transfer_type: 转移方式 :param transfer_type: 转移方式
:param target: 目标路径
:param meta: 预识别的元数据仅单文件转移时传递 :param meta: 预识别的元数据仅单文件转移时传递
:return: {path, target_path, message} :return: {path, target_path, message}
""" """
# 获取目标路径 # 获取目标路径
target_path = self.get_target_path(in_path=path) if not target:
if not target_path: target = self.get_target_path(in_path=path)
if not target:
logger.error("未找到媒体库目录,无法转移文件") logger.error("未找到媒体库目录,无法转移文件")
return TransferInfo(message="未找到媒体库目录,无法转移文件") return TransferInfo(message="未找到媒体库目录,无法转移文件")
# 转移 # 转移
return self.transfer_media(in_path=path, return self.transfer_media(in_path=path,
mediainfo=mediainfo, mediainfo=mediainfo,
transfer_type=transfer_type, transfer_type=transfer_type,
target_dir=target_path, target_dir=target,
in_meta=meta) in_meta=meta)
@staticmethod @staticmethod

View File

@ -33,10 +33,12 @@ class FileMonitorHandler(FileSystemEventHandler):
self.sync = sync self.sync = sync
def on_created(self, event): 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): 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): class DirMonitor(_PluginBase):
@ -77,12 +79,17 @@ class DirMonitor(_PluginBase):
_transfer_type = settings.TRANSFER_TYPE _transfer_type = settings.TRANSFER_TYPE
_monitor_dirs = "" _monitor_dirs = ""
_exclude_keywords = "" _exclude_keywords = ""
# 存储源目录与目的目录关系
_dirconf: Dict[str, str] = {}
def init_plugin(self, config: dict = None): def init_plugin(self, config: dict = None):
self.transferhis = TransferHistoryOper() self.transferhis = TransferHistoryOper()
self.downloadhis = DownloadHistoryOper() self.downloadhis = DownloadHistoryOper()
self.transferchian = TransferChain() self.transferchian = TransferChain()
# 清空配置
self._dirconf = {}
# 读取配置 # 读取配置
if config: if config:
self._enabled = config.get("enabled") self._enabled = config.get("enabled")
@ -101,13 +108,24 @@ class DirMonitor(_PluginBase):
if not monitor_dirs: if not monitor_dirs:
return return
for mon_path in monitor_dirs: for mon_path in monitor_dirs:
# 格式源目录:目的目录
if not mon_path: if not mon_path:
continue 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): try:
logger.warn(f"{mon_path} 是媒体库目录的子目录,无法监控") if Path(mon_path).is_relative_to(settings.LIBRARY_PATH):
self.systemmessage.put(f"{mon_path} 是媒体库目录的子目录,无法监控") logger.warn(f"{mon_path} 是媒体库目录的子目录,无法监控")
continue self.systemmessage.put(f"{mon_path} 是媒体库目录的子目录,无法监控")
continue
except Exception as e:
pass
try: try:
if self._mode == "compatibility": if self._mode == "compatibility":
@ -135,10 +153,11 @@ class DirMonitor(_PluginBase):
logger.error(f"{mon_path} 启动目录监控失败:{err_msg}") logger.error(f"{mon_path} 启动目录监控失败:{err_msg}")
self.systemmessage.put(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 event: 事件
:param mon_path: 监控目录
:param text: 事件描述 :param text: 事件描述
:param event_path: 事件文件路径 :param event_path: 事件文件路径
""" """
@ -210,10 +229,14 @@ class DirMonitor(_PluginBase):
# 更新媒体图片 # 更新媒体图片
self.chain.obtain_images(mediainfo=mediainfo) self.chain.obtain_images(mediainfo=mediainfo)
# 查询转移目的目录
target = self._dirconf.get(mon_path)
# 转移 # 转移
transferinfo: TransferInfo = self.chain.transfer(mediainfo=mediainfo, transferinfo: TransferInfo = self.chain.transfer(mediainfo=mediainfo,
path=file_path, path=file_path,
transfer_type=self._transfer_type, transfer_type=self._transfer_type,
target=target,
meta=file_meta) meta=file_meta)
if not transferinfo: if not transferinfo:
@ -287,147 +310,149 @@ class DirMonitor(_PluginBase):
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]: def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
return [ return [
{ {
'component': 'VForm', 'component': 'VForm',
'content': [ 'content': [
{ {
'component': 'VRow', 'component': 'VRow',
'content': [ 'content': [
{ {
'component': 'VCol', 'component': 'VCol',
'props': { 'props': {
'cols': 12, 'cols': 12,
'md': 6 'md': 6
}, },
'content': [ 'content': [
{ {
'component': 'VSwitch', 'component': 'VSwitch',
'props': { 'props': {
'model': 'enabled', 'model': 'enabled',
'label': '启用插件', 'label': '启用插件',
} }
} }
] ]
}, },
{ {
'component': 'VCol', 'component': 'VCol',
'props': { 'props': {
'cols': 12, 'cols': 12,
'md': 6 'md': 6
}, },
'content': [ 'content': [
{ {
'component': 'VSwitch', 'component': 'VSwitch',
'props': { 'props': {
'model': 'notify', 'model': 'notify',
'label': '发送通知', 'label': '发送通知',
} }
} }
] ]
} }
] ]
}, },
{ {
'component': 'VRow', 'component': 'VRow',
'content': [ 'content': [
{ {
'component': 'VCol', 'component': 'VCol',
'props': { 'props': {
'cols': 12, 'cols': 12,
'md': 6 'md': 6
}, },
'content': [ 'content': [
{ {
'component': 'VSelect', 'component': 'VSelect',
'props': { 'props': {
'model': 'mode', 'model': 'mode',
'label': '监控模式', 'label': '监控模式',
'items': [ 'items': [
{'title': '兼容模式', 'value': 'compatibility'}, {'title': '兼容模式', 'value': 'compatibility'},
{'title': '性能模式', 'value': 'fast'} {'title': '性能模式', 'value': 'fast'}
] ]
} }
} }
] ]
}, },
{ {
'component': 'VCol', 'component': 'VCol',
'props': { 'props': {
'cols': 12, 'cols': 12,
'md': 6 'md': 6
}, },
'content': [ 'content': [
{ {
'component': 'VSelect', 'component': 'VSelect',
'props': { 'props': {
'model': 'transfer_type', 'model': 'transfer_type',
'label': '转移方式', 'label': '转移方式',
'items': [ 'items': [
{'title': '移动', 'value': 'move'}, {'title': '移动', 'value': 'move'},
{'title': '复制', 'value': 'copy'}, {'title': '复制', 'value': 'copy'},
{'title': '硬链接', 'value': 'link'}, {'title': '硬链接', 'value': 'link'},
{'title': '软链接', 'value': 'softlink'} {'title': '软链接', 'value': 'softlink'}
] ]
} }
} }
] ]
} }
] ]
}, },
{ {
'component': 'VRow', 'component': 'VRow',
'content': [ 'content': [
{ {
'component': 'VCol', 'component': 'VCol',
'props': { 'props': {
'cols': 12 'cols': 12
}, },
'content': [ 'content': [
{ {
'component': 'VTextarea', 'component': 'VTextarea',
'props': { 'props': {
'model': 'monitor_dirs', 'model': 'monitor_dirs',
'label': '监控目录', 'label': '监控目录',
'rows': 5, 'rows': 5,
'placeholder': '每一行一个目录' 'placeholder': '每一行一个目录,支持两种配置方式:\n'
} '监控目录\n'
} '监控目录:转移目的目录'
] }
} }
] ]
}, }
{ ]
'component': 'VRow', },
'content': [ {
{ 'component': 'VRow',
'component': 'VCol', 'content': [
'props': { {
'cols': 12 'component': 'VCol',
}, 'props': {
'content': [ 'cols': 12
{ },
'component': 'VTextarea', 'content': [
'props': { {
'model': 'exclude_keywords', 'component': 'VTextarea',
'label': '排除关键词', 'props': {
'rows': 2, 'model': 'exclude_keywords',
'placeholder': '每一行一个关键词' 'label': '排除关键词',
} 'rows': 2,
} 'placeholder': '每一行一个关键词'
] }
} }
] ]
} }
] ]
} }
], { ]
"enabled": False, }
"notify": False, ], {
"mode": "fast", "enabled": False,
"transfer_type": settings.TRANSFER_TYPE, "notify": False,
"monitor_dirs": "", "mode": "fast",
"exclude_keywords": "" "transfer_type": settings.TRANSFER_TYPE,
} "monitor_dirs": "",
"exclude_keywords": ""
}
def get_page(self) -> List[dict]: def get_page(self) -> List[dict]:
pass pass