Merge pull request #220 from DzAvril/dev

This commit is contained in:
jxxghp
2024-04-20 19:50:03 +08:00
committed by GitHub
2 changed files with 87 additions and 23 deletions

View File

@@ -387,11 +387,12 @@
"RemoveLink": {
"name": "清理硬链接",
"description": "监控目录内文件被删除时,同步删除监控目录内所有和它硬链接的文件",
"version": "1.7",
"version": "1.8",
"icon": "Ombi_A.png",
"author": "DzAvril",
"level": 1,
"history": {
"v1.8": "增加清理空目录功能beta",
"v1.7": "修复因未监测重命名事件导致的清理硬链接失败的问题",
"v1.6": "提升插件性能"
}

View File

@@ -40,7 +40,7 @@ class FileMonitorHandler(FileSystemEventHandler):
# 新增文件记录
with state_lock:
self.sync.state_set[str(file_path)] = file_path.stat().st_ino
def on_moved(self, event):
if event.is_directory:
return
@@ -106,7 +106,7 @@ class RemoveLink(_PluginBase):
# 插件图标
plugin_icon = "Ombi_A.png"
# 插件版本
plugin_version = "1.7"
plugin_version = "1.8"
# 插件作者
plugin_author = "DzAvril"
# 作者主页
@@ -124,6 +124,7 @@ class RemoveLink(_PluginBase):
exclude_keywords = ""
_enabled = False
_notify = False
_delete_empty = False
_observer = []
# 监控目录的文件列表
state_set: Dict[str, int] = {}
@@ -136,6 +137,7 @@ class RemoveLink(_PluginBase):
self.monitor_dirs = config.get("monitor_dirs")
self.exclude_dirs = config.get("exclude_dirs") or ""
self.exclude_keywords = config.get("exclude_keywords") or ""
self._delete_empty = config.get("delete_empty")
# 停止现有任务
self.stop_service()
@@ -224,6 +226,19 @@ class RemoveLink(_PluginBase):
}
],
},
{
"component": "VCol",
"props": {"cols": 12, "md": 4},
"content": [
{
"component": "VSwitch",
"props": {
"model": "delete_empty",
"label": "清理空目录(beta)",
},
}
],
},
],
},
{
@@ -289,32 +304,47 @@ class RemoveLink(_PluginBase):
],
},
{
'component': 'VRow',
'content': [
"component": "VRow",
"content": [
{
'component': 'VCol',
'props': {
'cols': 12,
"component": "VCol",
"props": {
"cols": 12,
},
'content': [
"content": [
{
'component': 'VAlert',
'props': {
'type': 'info',
'variant': 'tonal',
'text': '监控目录如有多个需换行,源目录和硬链接目录都需要添加到监控目录中;如需实现删除硬链接时不删除源文件,可把源文件目录配置到不删除目录中。'
}
"component": "VAlert",
"props": {
"type": "info",
"variant": "tonal",
"text": "监控目录如有多个需换行,源目录和硬链接目录都需要添加到监控目录中;如需实现删除硬链接时不删除源文件,可把源文件目录配置到不删除目录中。",
},
}
]
}
]
}
],
},
{
"component": "VCol",
"props": {
"cols": 12,
},
"content": [
{
"component": "VAlert",
"props": {
"type": "info",
"variant": "tonal",
"text": "清理空目录为测试功能,请谨慎开启。",
},
}
],
},
],
},
],
}
], {
"enabled": False,
"notify": False,
"onlyonce": False,
"monitor_dirs": "",
"exclude_keywords": "",
}
@@ -344,13 +374,42 @@ class RemoveLink(_PluginBase):
if exclude_dir and exclude_dir in str(file_path):
return True
return False
def delete_empty_folders(self, path):
"""
从指定路径开始,逐级向上层目录检测并删除空目录,直到遇到非空目录或到达指定监控目录为止
"""
if not self._delete_empty:
return
while True:
parent_path = os.path.dirname(path)
# parent_path如已被删除则退出检查
if not os.path.exists(parent_path):
break
# 如果当前路径等于监控目录之一,停止向上检查
if parent_path in self.monitor_dirs.split("\n"):
break
# 检查当前目录是否为空且不在排除列表内
if not os.listdir(parent_path) and not self.__is_excluded(parent_path):
os.rmdir(parent_path)
logger.info(f"清理空目录:{parent_path}")
if self._notify:
self.post_message(
mtype=NotificationType.SiteMessage,
title=f"【清理硬链接】",
text=f"清理空文件夹:[{parent_path}]\n",
)
else:
break
# 更新路径为父目录,准备下一轮检查
path = parent_path
def handle_deleted(self, file_path: Path):
"""
处理删除事件
"""
# 删除的文件对应的监控信息
with state_lock:
# 清理空目录
self.delete_empty_folders(file_path)
# 删除的文件inode
deleted_inode = self.state_set.get(str(file_path))
if not deleted_inode:
@@ -369,12 +428,16 @@ class RemoveLink(_PluginBase):
# 删除硬链接文件
logger.info(f"删除硬链接文件:{path} inode: {inode}")
file.unlink()
# 清理空目录
self.delete_empty_folders(file)
if self._notify:
self.post_message(
mtype=NotificationType.SiteMessage,
title=f"【清理硬链接】",
text=f"监控到删除源文件:[{file_path}]\n"
f"同步删除硬链接文件:[{path}]",
f"同步删除硬链接文件:[{path}]",
)
except Exception as e:
logger.error("删除硬链接文件发生错误:%s - %s" % (str(e), traceback.format_exc()))
logger.error(
"删除硬链接文件发生错误:%s - %s" % (str(e), traceback.format_exc())
)