Merge pull request #116 from sleikang/main

实时软连接增加可配置遍历文件夹的等待时间
This commit is contained in:
thsrite
2024-11-10 17:58:27 +08:00
committed by GitHub
4 changed files with 2098 additions and 1867 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,446 +1,447 @@
{
"EmbyMetaRefresh": {
"name": "Emby元数据刷新",
"description": "定时刷新Emby媒体库元数据演职人员中文。",
"labels": "Emby",
"version": "2.1.3",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/emby-icon.png",
"author": "thsrite",
"level": 1,
"history": {
"v2.1.3": "增加自定义延迟",
"v2.1.1": "优化刷新逻辑,过滤掉信息全的媒体",
"v2.0.1": "获取tmdb图片时使用PROXY_HOST代理",
"v2.0": "适配v2",
"v1.8": "适配v2多媒体服务器",
"v1.7.3": "优化剧集演员刮削",
"v1.7.2": "优化剧集演员刮削",
"v1.7.1": "修复演员刮削",
"v1.7": "精细化刷新,最新入库支持刷新单集演职人员中文",
"v1.6": "修复豆瓣查询bug丰富日志",
"v1.5": "支持刷新演员中文路径关键词多个英文逗号分隔。建议覆盖元数据修改为False防止演员中文被刷新覆盖",
"v1.4": "支持刷新演员中文",
"v1.3": "支持自定义覆盖元数据、图片",
"v1.2": "支持获取Emby最新媒体刷新",
"v1.1": "添加远程交互命令",
"v1.0": "定时刷新Emby媒体库元数据"
"EmbyMetaRefresh": {
"name": "Emby元数据刷新",
"description": "定时刷新Emby媒体库元数据演职人员中文。",
"labels": "Emby",
"version": "2.1.3",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/emby-icon.png",
"author": "thsrite",
"level": 1,
"history": {
"v2.1.3": "增加自定义延迟",
"v2.1.1": "优化刷新逻辑,过滤掉信息全的媒体",
"v2.0.1": "获取tmdb图片时使用PROXY_HOST代理",
"v2.0": "适配v2",
"v1.8": "适配v2多媒体服务器",
"v1.7.3": "优化剧集演员刮削",
"v1.7.2": "优化剧集演员刮削",
"v1.7.1": "修复演员刮削",
"v1.7": "精细化刷新,最新入库支持刷新单集演职人员中文",
"v1.6": "修复豆瓣查询bug丰富日志",
"v1.5": "支持刷新演员中文路径关键词多个英文逗号分隔。建议覆盖元数据修改为False防止演员中文被刷新覆盖",
"v1.4": "支持刷新演员中文",
"v1.3": "支持自定义覆盖元数据、图片",
"v1.2": "支持获取Emby最新媒体刷新",
"v1.1": "添加远程交互命令",
"v1.0": "定时刷新Emby媒体库元数据"
}
},
"EmbyMetaTag": {
"name": "Emby媒体标签",
"description": "自动给媒体库媒体添加标签。",
"labels": "Emby",
"version": "1.3",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/tag.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.3": "适配v2多媒体服务器",
"v1.2": "支持指定特殊媒体名称添加标签",
"v1.1": "添加远程交互命令",
"v1.0": "自动给媒体库媒体添加标签"
}
},
"EmbyReporter": {
"name": "Emby观影报告",
"description": "推送Emby观影报告需Emby安装Playback Report 插件。",
"labels": "Emby",
"version": "2.1.1",
"icon": "Pydiocells_A.png",
"author": "thsrite",
"level": 1,
"history": {
"v2.1.1": "修复媒体库黑名单设置",
"v2.1": "支持媒体库黑名单设置",
"v2.0": "修复获取媒体服务器配置",
"v1.9": "适配v2多媒体服务器",
"v1.8": "推送微信增加时间戳,防止使用缓存",
"v1.7": "分块发送,兼容微信推送",
"v1.6": "fix #67",
"v1.5": "按观影市场排序",
"v1.4": "支持自定义emby && 支持每日一言",
"v1.3": "修复bug",
"v1.2": "过滤已删除媒体",
"v1.1": "修复推送",
"v1.0": "推送Emby观影报告"
}
},
"WeChatForward": {
"name": "微信消息转发",
"description": "根据正则转发通知到其他WeChat应用。",
"labels": "消息通知",
"version": "2.8",
"icon": "Wechat_A.png",
"author": "thsrite",
"level": 1,
"history": {
"v2.8": "兼容v2",
"v2.7": "特殊消息指定用户支持title匹配",
"v2.6": "已完成订阅额外消息查询订阅历史订阅用户",
"v2.5.1": "修复token过期重发未存储userid问题",
"v2.5": "增强额外消息发送",
"v2.4": "修复配置修改后不重建缓存bug",
"v2.3": "增加重建缓存,丰富转发历史",
"v2.2": "增加消息发送历史",
"v2.1": "微信配置持久化存库",
"v2.0": "优化微信配置,兼容旧版本配置",
"v1.6": "修改获取指定用户订阅列表方法",
"v1.5": "丰富日志",
"v1.4": "特定消息强制指定userid",
"v1.3": "防重复发送额外消息",
"v1.2": "fix规则",
"v1.1": "自定义发送额外消息",
"v1.0": "根据正则转发通知到其他WeChat应用"
}
},
"EmbyDanmu": {
"name": "Emby弹幕下载",
"description": "通知Emby Danmu插件下载弹幕。",
"labels": "Emby,媒体库",
"version": "1.6",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/danmu.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.6": "增加Emby、MoviePilot目录映射相同可不填",
"v1.5.1": "Emby4.8.8 Items API修改",
"v1.5": "修复获取弹幕源",
"v1.4": "修复自定义参数",
"v1.3": "适配v2多媒体服务器",
"v1.2": "检查本地弹幕文件是否已存在,避免重复下载。",
"v1.1": "解析Emby日志判断已配置弹幕源是否全部匹配失败。",
"v1.0": "通知Emby Danmu插件下载弹幕。"
}
},
"EmbyExtendType": {
"name": "Emby视频类型检查",
"description": "定期检查Emby媒体库中是否包含指定的视频类型发送通知。",
"labels": "Emby,媒体库",
"version": "1.1",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/extendtype.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.1": "适配v2多媒体服务器",
"v1.0": "定期检查Emby媒体库中是否包含指定的视频类型发送通知。"
}
},
"EmbyAudioBook": {
"name": "Emby有声书整理",
"description": "还在为Emby有声书整理烦恼吗入库存在很多单集",
"labels": "Emby,媒体库",
"version": "1.4",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/audiobook.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.4": "交互命令支持多媒体库",
"v1.3": "修复自定义参数",
"v1.2": "适配v2多媒体服务器",
"v1.1": "整理完锁定,防止数据被刷新",
"v1.0": "还在为Emby有声书整理烦恼吗入库存在很多单集。"
}
},
"EmbyCollectionSort": {
"name": "Emby合集媒体排序",
"description": "Emby保留按照加入时间倒序的前提下把合集中的媒体按照发布日期排序修改加入时间已到达顺序排列的目的。",
"labels": "媒体库",
"version": "1.2",
"icon": "Element_A.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.2": "适配v2多媒体服务器",
"v1.1": "优化处理逻辑",
"v1.0": "保留按照加入时间倒序的前提下,把合集中的媒体放一块,不用到处找。"
}
},
"EmbyActorSync": {
"name": "Emby剧集演员同步",
"description": "同步剧演员信息到集演员信息。",
"labels": "Emby,媒体库",
"version": "1.5",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/embyactorsync.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.5": "修复自定义参数",
"v1.4": "适配v2多媒体服务器",
"v1.3": "剧集优先使用季演员。",
"v1.2": "交互命令返回处理完成信息。",
"v1.1": "支持交互命令手动同步单个剧集 /as 媒体库名 剧集名。",
"v1.0": "同步剧演员信息到集演员信息。"
}
},
"LibraryDuplicateCheck": {
"name": "Emby媒体库重复媒体检测",
"description": "媒体库重复媒体检查,可选保留规则保留其一。",
"labels": "Emby,云盘,媒体库",
"version": "2.0.1",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/libraryduplicate.png",
"author": "thsrite",
"level": 2,
"history": {
"v2.0.1": "适配v2多媒体服务器",
"v1.9": "修复删除软连接",
"v1.8": "仅检查模式下,预览操作不会删除任何文件。",
"v1.7": "修复特殊场景下删除问题",
"v1.6": "同步删除thumb图片等刮削文件",
"v1.5": "删除重复文件时再刷新媒体库逻辑",
"v1.4": "修复删除时文件不存在bug",
"v1.3": "各路径支持自定义保留规则",
"v1.2": "支持通知推送",
"v1.1": "支持自动刷新媒体库",
"v1.0": "媒体库重复媒体检查,可选择保留规则保留其一"
}
},
"MediaSyncDel": {
"name": "媒体文件同步删除",
"description": "同步删除历史记录、源文件和下载任务。",
"labels": "媒体库,文件整理",
"version": "1.8.4",
"icon": "mediasyncdel.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.8.4": "修复暂停种子失败",
"v1.8.3": "修复源文件删除",
"v1.8.1": "适配v2多媒体服务器移除日志方式",
"v1.7": "修复重新整理被一并删除问题",
"v1.6": "修复删除辅种",
"v1.5": "支持手动删除订阅历史记录(本次更新之后的历史)"
}
},
"SyncDownloadFiles": {
"name": "下载器文件同步",
"description": "同步下载器的文件信息到数据库,删除文件时联动删除下载任务。",
"labels": "下载管理",
"version": "1.1.3",
"icon": "Youtube-dl_A.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.1.3": "支持v2",
"v1.1.1": "修复时区问题导致的上次同步后8h内的种子不同步的问题"
}
},
"HomePage": {
"name": "HomePage",
"description": "HomePage自定义API。",
"labels": "工具",
"version": "1.3",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/homepage.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.3": "兼容v2",
"v1.2": "适配v1.9.1-beta不生效就重启",
"v1.1": "支持更多返回值、插件展示数据",
"v1.0": "HomePage自定义API"
}
},
"FileSoftLink": {
"name": "实时软连接",
"description": "监控目录文件变化,媒体文件软连接,其他文件可选复制。",
"labels": "文件管理",
"version": "2.0.4",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/softlink.png",
"author": "thsrite",
"level": 1,
"history": {
"v2.0.4": "增加同步遍历文件间隔",
"v2.0.3": "增加强制覆盖选项",
"v2.0.2": "兼容v2",
"v2.0.1": "不重要的更新",
"v2.0": "修复交互命令",
"v1.9.9": "交互命令更多玩法",
"v1.9.8": "新增模糊匹配交互命令",
"v1.9.7": "接收云盘实时监控处理单文件",
"v1.9.6": "优化log",
"v1.9.5": "增强交互命令",
"v1.9.4": "监控目录自定义监控模式",
"v1.9.3": "增强交互命令模糊匹配",
"v1.9.2": "增强交互命令模糊匹配",
"v1.9.1": "增强交互命令",
"v1.9": "交互命令定向软连接",
"v1.8": "修复bug",
"v1.6": "bug修复",
"v1.5": "优化性能,提高处理速度",
"v1.4": "支持自定义视频格式",
"v1.3": "异步启动"
}
},
"Cd2Assistant": {
"name": "CloudDrive2助手",
"description": "监控上传任务,检测是否有异常,发送通知。",
"labels": "云盘",
"version": "1.8.5",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/clouddrive.png",
"author": "thsrite",
"level": 2,
"history": {
"v1.8.5": "兼容v2",
"v1.8.4": "添加115 429消息通知",
"v1.8.3": "添加异常处理解决cd2上本地目录获取存储空间失败的问题",
"v1.8.2": "插件页面密码类型设置为pasword",
"v1.8.1": "云下载支持自定义路径 /cd /cd2路径 磁链",
"v1.8": "修复插件依赖安装问题",
"v1.7": "增加HomePage自定义API详见插件说明",
"v1.6": "支持交互命令云下载",
"v1.5": "增加云盘同步黑名单(排序挂载本地目录)",
"v1.4": "增加云盘存储空间展示",
"v1.3": "增加云盘Cookie失效检测",
"v1.2": "实时速率显示",
"v1.1": "交互命令重启cd2、获取cd2系统信息支持仪表盘",
"v1.0": "监控上传任务,检测是否有异常,发送通知"
}
},
"MediaRelease": {
"name": "影视将映订阅",
"description": "监控未上线影视作品,自动添加订阅。",
"labels": "订阅",
"version": "1.2",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/mediarelease.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.2": "兼容v2",
"v1.1": "bug修复",
"v1.0": "监控未上线影视作品,自动添加订阅。"
}
},
"SubscribeGroup": {
"name": "订阅规则自动填充",
"description": "电视剧下载后自动添加官组等信息到订阅;添加订阅后根据二级分类名称自定义订阅规则。",
"labels": "订阅",
"version": "2.8.2",
"icon": "teamwork.png",
"author": "thsrite",
"level": 2,
"history": {
"v2.8.2": "订阅填充规则支持优先级规则组",
"v2.8.1": "修复种子下载自定义填充站点后订阅无法打开问题",
"v2.8": "兼容v2",
"v2.7": "下载填充判断当前站点是否在已选订阅站点范围内",
"v2.6": "兼容属性值包含:号",
"v2.5": "操作历史Unicode编码转中文",
"v2.4": "保存路径支持变量{name} (订阅名称 (年份)",
"v2.3": "二级分类自定义填充支持保存路径",
"v2.1": "站点与官组分开,修复质量无填充",
"v2.0": "种子下载自定义填充支持自定义占位符",
"v1.8": "修复种子下载不填充bug",
"v1.7": "操作历史Unicode编码转中文",
"v1.6": "支持一行配置多个二级分类名称",
"v1.5": "支持操作历史",
"v1.4": "支持根据二级分类名称自定义订阅规则",
"v1.3": "增加质量、分辨率、特效信息填充",
"v1.2": "修复订阅已存在包含关键词和订阅站点"
}
},
"SqlExecute": {
"name": "Sql执行器",
"description": "自定义MoviePilot数据库Sql执行。",
"labels": "工具",
"version": "1.4",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/sqlite.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.4": "兼容v2",
"v1.3": "修复执行delete锁表失败的bug",
"v1.2": "调整交互命令返回信息",
"v1.1": "支持交互命令/sql [command]执行需主程序1.9.4+",
"v1.0": "自定义MoviePilot数据库Sql执行"
}
},
"CommandExecute": {
"name": "命令执行器",
"description": "自定义容器命令执行。",
"labels": "工具",
"version": "1.3",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/command.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.3": "兼容v2",
"v1.2": "调整交互命令返回信息",
"v1.1": "支持交互命令/cmd [sql]执行需主程序1.9.4+",
"v1.0": "自定义容器命令执行"
}
},
"AutoBackup": {
"name": "自动备份",
"description": "自动备份数据和配置文件。",
"labels": "系统设置",
"version": "2.0.1",
"icon": "Time_machine_B.png",
"author": "thsrite",
"level": 1,
"history": {
"v2.0.1": "修复cookies文件夹备份失败",
"v2.0": "支持备份app.env及cookies,支持自定义保存路径",
"v1.3": "去除已废弃的环境变量引用",
"v1.2": "增强API安全性"
}
},
"CloudLinkMonitor": {
"name": "目录实时监控",
"description": "监控云盘目录文件变化,自动转移媒体文件。",
"labels": "云盘,工具",
"version": "2.5.1",
"icon": "Linkease_A.png",
"author": "thsrite",
"level": 1,
"history": {
"v2.5.1": "修复媒体刮削",
"v2.5": "兼容v2",
"v2.4.5": "联动实时软连接插件(近媒体文件)",
"v2.4.4": "修复刷新媒体库",
"v2.4.3": "可选转移完刷新媒体库",
"v2.4.2": "fix #65",
"v2.4.1": "增加log",
"v2.4": "修复二级目录",
"v2.3": "去除无效变量",
"v2.2": "优化配置一二级分类流程",
"v2.1": "可配置是否存储转移记录",
"v2.0": "修复不刮削不生效bug",
"v1.8": "fix S00转移",
"v1.7": "fix 刮削",
"v1.6": "可配置是否刮削",
"v1.5": "fix 消息推送",
"v1.4": "fix 转移后路径",
"v1.3": "修复bug",
"v1.2": "修复订阅重复处理的bug",
"v1.1": "自动转移链接(不刮削)",
"v1.0": "监控云盘目录文件变化,按原文件名软连接"
}
},
"CloudStrmCompanion": {
"name": "云盘Strm助手",
"description": "实时监控、定时全量增量生成strm文件。",
"labels": "云盘",
"version": "1.0.5",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/cloudcompanion.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.0.5": "增加复制非媒体文件选项",
"v1.0.4": "修复实时监控,只处理指定类型的文件",
"v1.0.3": "修复重建索引缓存",
"v1.0.2": "增加可玩性交互命令",
"v1.0": "实时监控、定时全量增量生成strm文件"
}
},
"StrmRedirect": {
"name": "Strm重定向",
"description": "重写Strm文件内容。",
"labels": "云盘",
"version": "1.0",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/softlinkredirect.png",
"author": "thsrite",
"level": 1,
"v2": true,
"history": {
"v1.0": "重写Strm文件内容"
}
}
},
"EmbyMetaTag": {
"name": "Emby媒体标签",
"description": "自动给媒体库媒体添加标签。",
"labels": "Emby",
"version": "1.3",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/tag.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.3": "适配v2多媒体服务器",
"v1.2": "支持指定特殊媒体名称添加标签",
"v1.1": "添加远程交互命令",
"v1.0": "自动给媒体库媒体添加标签"
}
},
"EmbyReporter": {
"name": "Emby观影报告",
"description": "推送Emby观影报告需Emby安装Playback Report 插件。",
"labels": "Emby",
"version": "2.1.1",
"icon": "Pydiocells_A.png",
"author": "thsrite",
"level": 1,
"history": {
"v2.1.1": "修复媒体库黑名单设置",
"v2.1": "支持媒体库黑名单设置",
"v2.0": "修复获取媒体服务器配置",
"v1.9": "适配v2多媒体服务器",
"v1.8": "推送微信增加时间戳,防止使用缓存",
"v1.7": "分块发送,兼容微信推送",
"v1.6": "fix #67",
"v1.5": "按观影市场排序",
"v1.4": "支持自定义emby && 支持每日一言",
"v1.3": "修复bug",
"v1.2": "过滤已删除媒体",
"v1.1": "修复推送",
"v1.0": "推送Emby观影报告"
}
},
"WeChatForward": {
"name": "微信消息转发",
"description": "根据正则转发通知到其他WeChat应用。",
"labels": "消息通知",
"version": "2.8",
"icon": "Wechat_A.png",
"author": "thsrite",
"level": 1,
"history": {
"v2.8": "兼容v2",
"v2.7": "特殊消息指定用户支持title匹配",
"v2.6": "已完成订阅额外消息查询订阅历史订阅用户",
"v2.5.1": "修复token过期重发未存储userid问题",
"v2.5": "增强额外消息发送",
"v2.4": "修复配置修改后不重建缓存bug",
"v2.3": "增加重建缓存,丰富转发历史",
"v2.2": "增加消息发送历史",
"v2.1": "微信配置持久化存库",
"v2.0": "优化微信配置,兼容旧版本配置",
"v1.6": "修改获取指定用户订阅列表方法",
"v1.5": "丰富日志",
"v1.4": "特定消息强制指定userid",
"v1.3": "防重复发送额外消息",
"v1.2": "fix规则",
"v1.1": "自定义发送额外消息",
"v1.0": "根据正则转发通知到其他WeChat应用"
}
},
"EmbyDanmu": {
"name": "Emby弹幕下载",
"description": "通知Emby Danmu插件下载弹幕。",
"labels": "Emby,媒体库",
"version": "1.6",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/danmu.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.6": "增加Emby、MoviePilot目录映射相同可不填",
"v1.5.1": "Emby4.8.8 Items API修改",
"v1.5": "修复获取弹幕源",
"v1.4": "修复自定义参数",
"v1.3": "适配v2多媒体服务器",
"v1.2": "检查本地弹幕文件是否已存在,避免重复下载。",
"v1.1": "解析Emby日志判断已配置弹幕源是否全部匹配失败。",
"v1.0": "通知Emby Danmu插件下载弹幕。"
}
},
"EmbyExtendType": {
"name": "Emby视频类型检查",
"description": "定期检查Emby媒体库中是否包含指定的视频类型发送通知。",
"labels": "Emby,媒体库",
"version": "1.1",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/extendtype.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.1": "适配v2多媒体服务器",
"v1.0": "定期检查Emby媒体库中是否包含指定的视频类型发送通知。"
}
},
"EmbyAudioBook": {
"name": "Emby有声书整理",
"description": "还在为Emby有声书整理烦恼吗入库存在很多单集",
"labels": "Emby,媒体库",
"version": "1.4",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/audiobook.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.4": "交互命令支持多媒体库",
"v1.3": "修复自定义参数",
"v1.2": "适配v2多媒体服务器",
"v1.1": "整理完锁定,防止数据被刷新",
"v1.0": "还在为Emby有声书整理烦恼吗入库存在很多单集。"
}
},
"EmbyCollectionSort": {
"name": "Emby合集媒体排序",
"description": "Emby保留按照加入时间倒序的前提下把合集中的媒体按照发布日期排序修改加入时间已到达顺序排列的目的。",
"labels": "媒体库",
"version": "1.2",
"icon": "Element_A.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.2": "适配v2多媒体服务器",
"v1.1": "优化处理逻辑",
"v1.0": "保留按照加入时间倒序的前提下,把合集中的媒体放一块,不用到处找。"
}
},
"EmbyActorSync": {
"name": "Emby剧集演员同步",
"description": "同步剧演员信息到集演员信息。",
"labels": "Emby,媒体库",
"version": "1.5",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/embyactorsync.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.5": "修复自定义参数",
"v1.4": "适配v2多媒体服务器",
"v1.3": "剧集优先使用季演员。",
"v1.2": "交互命令返回处理完成信息。",
"v1.1": "支持交互命令手动同步单个剧集 /as 媒体库名 剧集名。",
"v1.0": "同步剧演员信息到集演员信息。"
}
},
"LibraryDuplicateCheck": {
"name": "Emby媒体库重复媒体检测",
"description": "媒体库重复媒体检查,可选保留规则保留其一。",
"labels": "Emby,云盘,媒体库",
"version": "2.0.1",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/libraryduplicate.png",
"author": "thsrite",
"level": 2,
"history": {
"v2.0.1": "适配v2多媒体服务器",
"v1.9": "修复删除软连接",
"v1.8": "仅检查模式下,预览操作不会删除任何文件。",
"v1.7": "修复特殊场景下删除问题",
"v1.6": "同步删除thumb图片等刮削文件",
"v1.5": "删除重复文件时再刷新媒体库逻辑",
"v1.4": "修复删除时文件不存在bug",
"v1.3": "各路径支持自定义保留规则",
"v1.2": "支持通知推送",
"v1.1": "支持自动刷新媒体库",
"v1.0": "媒体库重复媒体检查,可选择保留规则保留其一"
}
},
"MediaSyncDel": {
"name": "媒体文件同步删除",
"description": "同步删除历史记录、源文件和下载任务。",
"labels": "媒体库,文件整理",
"version": "1.8.4",
"icon": "mediasyncdel.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.8.4": "修复暂停种子失败",
"v1.8.3": "修复源文件删除",
"v1.8.1": "适配v2多媒体服务器移除日志方式",
"v1.7": "修复重新整理被一并删除问题",
"v1.6": "修复删除辅种",
"v1.5": "支持手动删除订阅历史记录(本次更新之后的历史)"
}
},
"SyncDownloadFiles": {
"name": "下载器文件同步",
"description": "同步下载器的文件信息到数据库,删除文件时联动删除下载任务。",
"labels": "下载管理",
"version": "1.1.3",
"icon": "Youtube-dl_A.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.1.3": "支持v2",
"v1.1.1": "修复时区问题导致的上次同步后8h内的种子不同步的问题"
}
},
"HomePage": {
"name": "HomePage",
"description": "HomePage自定义API。",
"labels": "工具",
"version": "1.3",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/homepage.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.3": "兼容v2",
"v1.2": "适配v1.9.1-beta不生效就重启",
"v1.1": "支持更多返回值、插件展示数据",
"v1.0": "HomePage自定义API"
}
},
"FileSoftLink": {
"name": "实时软连接",
"description": "监控目录文件变化,媒体文件软连接,其他文件可选复制。",
"labels": "文件管理",
"version": "2.0.3",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/softlink.png",
"author": "thsrite",
"level": 1,
"history": {
"v2.0.3": "增加强制覆盖选项",
"v2.0.2": "兼容v2",
"v2.0.1": "不重要的更新",
"v2.0": "修复交互命令",
"v1.9.9": "交互命令更多玩法",
"v1.9.8": "新增模糊匹配交互命令",
"v1.9.7": "接收云盘实时监控处理单文件",
"v1.9.6": "优化log",
"v1.9.5": "增强交互命令",
"v1.9.4": "监控目录自定义监控模式",
"v1.9.3": "增强交互命令模糊匹配",
"v1.9.2": "增强交互命令模糊匹配",
"v1.9.1": "增强交互命令",
"v1.9": "交互命令定向软连接",
"v1.8": "修复bug",
"v1.6": "bug修复",
"v1.5": "优化性能,提高处理速度",
"v1.4": "支持自定义视频格式",
"v1.3": "异步启动"
}
},
"Cd2Assistant": {
"name": "CloudDrive2助手",
"description": "监控上传任务,检测是否有异常,发送通知。",
"labels": "云盘",
"version": "1.8.5",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/clouddrive.png",
"author": "thsrite",
"level": 2,
"history": {
"v1.8.5": "兼容v2",
"v1.8.4": "添加115 429消息通知",
"v1.8.3": "添加异常处理解决cd2上本地目录获取存储空间失败的问题",
"v1.8.2": "插件页面密码类型设置为pasword",
"v1.8.1": "云下载支持自定义路径 /cd /cd2路径 磁链",
"v1.8": "修复插件依赖安装问题",
"v1.7": "增加HomePage自定义API详见插件说明",
"v1.6": "支持交互命令云下载",
"v1.5": "增加云盘同步黑名单(排序挂载本地目录)",
"v1.4": "增加云盘存储空间展示",
"v1.3": "增加云盘Cookie失效检测",
"v1.2": "实时速率显示",
"v1.1": "交互命令重启cd2、获取cd2系统信息支持仪表盘",
"v1.0": "监控上传任务,检测是否有异常,发送通知"
}
},
"MediaRelease": {
"name": "影视将映订阅",
"description": "监控未上线影视作品,自动添加订阅。",
"labels": "订阅",
"version": "1.2",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/mediarelease.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.2": "兼容v2",
"v1.1": "bug修复",
"v1.0": "监控未上线影视作品,自动添加订阅。"
}
},
"SubscribeGroup": {
"name": "订阅规则自动填充",
"description": "电视剧下载后自动添加官组等信息到订阅;添加订阅后根据二级分类名称自定义订阅规则。",
"labels": "订阅",
"version": "2.8.2",
"icon": "teamwork.png",
"author": "thsrite",
"level": 2,
"history": {
"v2.8.2": "订阅填充规则支持优先级规则组",
"v2.8.1": "修复种子下载自定义填充站点后订阅无法打开问题",
"v2.8": "兼容v2",
"v2.7": "下载填充判断当前站点是否在已选订阅站点范围内",
"v2.6": "兼容属性值包含:号",
"v2.5": "操作历史Unicode编码转中文",
"v2.4": "保存路径支持变量{name} (订阅名称 (年份)",
"v2.3": "二级分类自定义填充支持保存路径",
"v2.1": "站点与官组分开,修复质量无填充",
"v2.0": "种子下载自定义填充支持自定义占位符",
"v1.8": "修复种子下载不填充bug",
"v1.7": "操作历史Unicode编码转中文",
"v1.6": "支持一行配置多个二级分类名称",
"v1.5": "支持操作历史",
"v1.4": "支持根据二级分类名称自定义订阅规则",
"v1.3": "增加质量、分辨率、特效信息填充",
"v1.2": "修复订阅已存在包含关键词和订阅站点"
}
},
"SqlExecute": {
"name": "Sql执行器",
"description": "自定义MoviePilot数据库Sql执行。",
"labels": "工具",
"version": "1.4",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/sqlite.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.4": "兼容v2",
"v1.3": "修复执行delete锁表失败的bug",
"v1.2": "调整交互命令返回信息",
"v1.1": "支持交互命令/sql [command]执行需主程序1.9.4+",
"v1.0": "自定义MoviePilot数据库Sql执行"
}
},
"CommandExecute": {
"name": "命令执行器",
"description": "自定义容器命令执行。",
"labels": "工具",
"version": "1.3",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/command.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.3": "兼容v2",
"v1.2": "调整交互命令返回信息",
"v1.1": "支持交互命令/cmd [sql]执行需主程序1.9.4+",
"v1.0": "自定义容器命令执行"
}
},
"AutoBackup": {
"name": "自动备份",
"description": "自动备份数据和配置文件。",
"labels": "系统设置",
"version": "2.0.1",
"icon": "Time_machine_B.png",
"author": "thsrite",
"level": 1,
"history": {
"v2.0.1": "修复cookies文件夹备份失败",
"v2.0": "支持备份app.env及cookies,支持自定义保存路径",
"v1.3": "去除已废弃的环境变量引用",
"v1.2": "增强API安全性"
}
},
"CloudLinkMonitor": {
"name": "目录实时监控",
"description": "监控云盘目录文件变化,自动转移媒体文件。",
"labels": "云盘,工具",
"version": "2.5.1",
"icon": "Linkease_A.png",
"author": "thsrite",
"level": 1,
"history": {
"v2.5.1": "修复媒体刮削",
"v2.5": "兼容v2",
"v2.4.5": "联动实时软连接插件(近媒体文件)",
"v2.4.4": "修复刷新媒体库",
"v2.4.3": "可选转移完刷新媒体库",
"v2.4.2": "fix #65",
"v2.4.1": "增加log",
"v2.4": "修复二级目录",
"v2.3": "去除无效变量",
"v2.2": "优化配置一二级分类流程",
"v2.1": "可配置是否存储转移记录",
"v2.0": "修复不刮削不生效bug",
"v1.8": "fix S00转移",
"v1.7": "fix 刮削",
"v1.6": "可配置是否刮削",
"v1.5": "fix 消息推送",
"v1.4": "fix 转移后路径",
"v1.3": "修复bug",
"v1.2": "修复订阅重复处理的bug",
"v1.1": "自动转移链接(不刮削)",
"v1.0": "监控云盘目录文件变化,按原文件名软连接"
}
},
"CloudStrmCompanion": {
"name": "云盘Strm助手",
"description": "实时监控、定时全量增量生成strm文件。",
"labels": "云盘",
"version": "1.0.5",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/cloudcompanion.png",
"author": "thsrite",
"level": 1,
"history": {
"v1.0.5": "增加复制非媒体文件选项",
"v1.0.4": "修复实时监控,只处理指定类型的文件",
"v1.0.3": "修复重建索引缓存",
"v1.0.2": "增加可玩性交互命令",
"v1.0": "实时监控、定时全量增量生成strm文件"
}
},
"StrmRedirect": {
"name": "Strm重定向",
"description": "重写Strm文件内容。",
"labels": "云盘",
"version": "1.0",
"icon": "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/softlinkredirect.png",
"author": "thsrite",
"level": 1,
"v2": true,
"history": {
"v1.0": "重写Strm文件内容"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@ import re
import shutil
import threading
import traceback
import time
from pathlib import Path
from typing import List, Tuple, Dict, Any, Optional
@@ -37,12 +38,20 @@ class FileMonitorHandler(FileSystemEventHandler):
self.sync = sync
def on_created(self, event):
self.sync.event_handler(event=event, text="创建",
mon_path=self._watch_path, event_path=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.event_handler(event=event, text="移动",
mon_path=self._watch_path, event_path=event.dest_path)
self.sync.event_handler(
event=event,
text="移动",
mon_path=self._watch_path,
event_path=event.dest_path,
)
class FileSoftLink(_PluginBase):
@@ -53,7 +62,7 @@ class FileSoftLink(_PluginBase):
# 插件图标
plugin_icon = "https://raw.githubusercontent.com/thsrite/MoviePilot-Plugins/main/icons/softlink.png"
# 插件版本
plugin_version = "2.0.1"
plugin_version = "2.0.2"
# 插件作者
plugin_author = "thsrite"
# 作者主页
@@ -71,6 +80,7 @@ class FileSoftLink(_PluginBase):
_enabled = False
_onlyonce = False
_copy_files = False
_sync_interval = 0
_cron = None
_url = None
_size = 0
@@ -97,14 +107,17 @@ class FileSoftLink(_PluginBase):
self._enabled = config.get("enabled")
self._onlyonce = config.get("onlyonce")
self._copy_files = config.get("copy_files")
self._sync_interval = float(config.get("sync_interval"))
self._mode = config.get("mode")
self._monitor_dirs = config.get("monitor_dirs") or ""
self._exclude_keywords = config.get("exclude_keywords") or ""
self._cron = config.get("cron")
self._url = config.get("url")
self._size = config.get("size") or 0
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._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()
@@ -135,8 +148,10 @@ class FileSoftLink(_PluginBase):
# 存储目的目录
if SystemUtils.is_windows():
if mon_path.count(":") > 1:
paths = [mon_path.split(":")[0] + ":" + mon_path.split(":")[1],
mon_path.split(":")[2] + ":" + mon_path.split(":")[3]]
paths = [
mon_path.split(":")[0] + ":" + mon_path.split(":")[1],
mon_path.split(":")[2] + ":" + mon_path.split(":")[3],
]
else:
paths = [mon_path]
else:
@@ -158,8 +173,12 @@ class FileSoftLink(_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} 的子目录,无法监控")
logger.warn(
f"{target_path}监控目录 {mon_path} 的子目录,无法监控"
)
self.systemmessage.put(
f"{target_path} 是下载目录 {mon_path} 的子目录,无法监控"
)
continue
except Exception as e:
logger.debug(str(e))
@@ -168,23 +187,31 @@ class FileSoftLink(_PluginBase):
# 异步开启云盘监控
self._mode = monitor or self._mode
if str(self._mode) != "nomonitor":
logger.info(f"异步开启实时软连接链接 {mon_path} {self._mode}延迟3s启动")
self._scheduler.add_job(func=self.start_monitor, trigger='date',
run_date=datetime.datetime.now(
tz=pytz.timezone(settings.TZ)) + datetime.timedelta(seconds=3),
name=f"实时软连接 {mon_path}",
kwargs={
"source_dir": mon_path
})
logger.info(
f"异步开启实时软连接链接 {mon_path} {self._mode}延迟3s启动"
)
self._scheduler.add_job(
func=self.start_monitor,
trigger="date",
run_date=datetime.datetime.now(
tz=pytz.timezone(settings.TZ)
)
+ datetime.timedelta(seconds=3),
name=f"实时软连接 {mon_path}",
kwargs={"source_dir": mon_path},
)
else:
logger.info(f"{mon_path} 实时软链接服务已关闭")
# 运行一次定时服务
if self._onlyonce:
logger.info("实时软连接服务启动,立即运行一次")
self._scheduler.add_job(name="实时软连接", func=self.sync_all, trigger='date',
run_date=datetime.datetime.now(
tz=pytz.timezone(settings.TZ)) + datetime.timedelta(seconds=3)
)
self._scheduler.add_job(
name="实时软连接",
func=self.sync_all,
trigger="date",
run_date=datetime.datetime.now(tz=pytz.timezone(settings.TZ))
+ datetime.timedelta(seconds=3),
)
# 关闭一次性开关
self._onlyonce = False
# 保存配置
@@ -207,7 +234,9 @@ class FileSoftLink(_PluginBase):
# 内部处理系统操作类型选择最优解
observer = Observer(timeout=10)
self._observer.append(observer)
observer.schedule(FileMonitorHandler(source_dir, self), path=source_dir, recursive=True)
observer.schedule(
FileMonitorHandler(source_dir, self), path=source_dir, recursive=True
)
observer.daemon = True
observer.start()
logger.info(f"{source_dir} 的实时软链接服务启动")
@@ -220,7 +249,8 @@ class FileSoftLink(_PluginBase):
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
echo fs.inotify.max_user_instances=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
""")
"""
)
else:
logger.error(f"{source_dir} 启动云盘监控失败:{err_msg}")
self.systemmessage.put(f"{source_dir} 启动云盘监控失败:{err_msg}")
@@ -229,18 +259,21 @@ class FileSoftLink(_PluginBase):
"""
更新配置
"""
self.update_config({
"enabled": self._enabled,
"onlyonce": self._onlyonce,
"copy_files": self._copy_files,
"mode": self._mode,
"monitor_dirs": self._monitor_dirs,
"exclude_keywords": self._exclude_keywords,
"cron": self._cron,
"url": self._url,
"size": self._size,
"rmt_mediaext": self._rmt_mediaext
})
self.update_config(
{
"enabled": self._enabled,
"onlyonce": self._onlyonce,
"copy_files": self._copy_files,
"sync_interval": self._sync_interval,
"mode": self._mode,
"monitor_dirs": self._monitor_dirs,
"exclude_keywords": self._exclude_keywords,
"cron": self._cron,
"url": self._url,
"size": self._size,
"rmt_mediaext": self._rmt_mediaext,
}
)
@eventmanager.register(EventType.PluginAction)
def remote_sync(self, event: Event):
@@ -251,13 +284,18 @@ class FileSoftLink(_PluginBase):
event_data = event.event_data
if not event_data or event_data.get("action") != "softlink_sync":
return
self.post_message(channel=event.event_data.get("channel"),
title="开始同步监控目录 ...",
userid=event.event_data.get("user"))
self.post_message(
channel=event.event_data.get("channel"),
title="开始同步监控目录 ...",
userid=event.event_data.get("user"),
)
self.sync_all()
if event:
self.post_message(channel=event.event_data.get("channel"),
title="监控目录同步完成!", userid=event.event_data.get("user"))
self.post_message(
channel=event.event_data.get("channel"),
title="监控目录同步完成!",
userid=event.event_data.get("user"),
)
@eventmanager.register(EventType.PluginAction)
def softlink_file(self, event: Event = None):
@@ -289,7 +327,9 @@ class FileSoftLink(_PluginBase):
if event:
event_data = event.event_data
if not event_data or (
event_data.get("action") != "softlink_one" and event_data.get("action") != "softlink_all"):
event_data.get("action") != "softlink_one"
and event_data.get("action") != "softlink_all"
):
return
args = event_data.get("args")
if not args:
@@ -309,7 +349,11 @@ class FileSoftLink(_PluginBase):
if category:
# 判断是不是目录
if Path(category).is_dir() and Path(category).exists() and limit is not None:
if (
Path(category).is_dir()
and Path(category).exists()
and limit is not None
):
# 遍历所有监控目录
mon_path = None
for mon in self._dirconf.keys():
@@ -322,7 +366,9 @@ class FileSoftLink(_PluginBase):
logger.error(f"未找到 {category} 对应的监控目录")
return
self.__handle_limit(path=category, mon_path=mon_path, limit=limit, event=event)
self.__handle_limit(
path=category, mon_path=mon_path, limit=limit, event=event
)
return
else:
for mon_path in self._categoryconf.keys():
@@ -331,13 +377,26 @@ class FileSoftLink(_PluginBase):
if mon_category and str(category) in mon_category:
parent_path = os.path.join(mon_path, category)
if limit:
logger.info(f"获取到 {category} 对应的监控目录 {parent_path}")
self.__handle_limit(path=parent_path, mon_path=mon_path, limit=limit, event=event)
logger.info(
f"获取到 {category} 对应的监控目录 {parent_path}"
)
self.__handle_limit(
path=parent_path,
mon_path=mon_path,
limit=limit,
event=event,
)
else:
logger.info(f"获取到 {category} {args} 对应的监控目录 {parent_path}")
target_paths = self.__find_related_paths(os.path.join(str(parent_path), args))
logger.info(
f"获取到 {category} {args} 对应的监控目录 {parent_path}"
)
target_paths = self.__find_related_paths(
os.path.join(str(parent_path), args)
)
if not target_paths:
logger.error(f"未查找到 {category} {args} 对应的具体目录")
logger.error(
f"未查找到 {category} {args} 对应的具体目录"
)
return
for target_path in target_paths:
logger.info(f"开始定向处理文件夹 ...{target_path}")
@@ -345,14 +404,27 @@ class FileSoftLink(_PluginBase):
for file_name in sdirs + sfiles:
src_file = os.path.join(sroot, file_name)
if Path(src_file).is_file():
self.__handle_file(event_path=str(src_file), mon_path=mon_path)
self.__handle_file(
event_path=str(src_file),
mon_path=mon_path,
)
logger.info(
f"等待 {self._sync_interval}"
)
time.sleep(self._sync_interval)
if event.event_data.get("user"):
self.post_message(channel=event.event_data.get("channel"),
title=f"{target_path} 软连接完成!",
userid=event.event_data.get("user"))
self.post_message(
channel=event.event_data.get("channel"),
title=f"{target_path} 软连接完成!",
userid=event.event_data.get("user"),
)
if limit is None and event_data and event_data.get("action") == "softlink_one":
if (
limit is None
and event_data
and event_data.get("action") == "softlink_one"
):
return
return
else:
@@ -381,10 +453,17 @@ class FileSoftLink(_PluginBase):
for file_name in sdirs + sfiles:
src_file = os.path.join(sroot, file_name)
if Path(str(src_file)).is_file():
self.__handle_file(event_path=str(src_file), mon_path=mon_path)
self.__handle_file(
event_path=str(src_file), mon_path=mon_path
)
logger.info(f"等待 {self._sync_interval}")
time.sleep(self._sync_interval)
if event.event_data.get("user"):
self.post_message(channel=event.event_data.get("channel"),
title=f"{all_args} 软连接完成!", userid=event.event_data.get("user"))
self.post_message(
channel=event.event_data.get("channel"),
title=f"{all_args} 软连接完成!",
userid=event.event_data.get("user"),
)
return
else:
for mon_path in self._categoryconf.keys():
@@ -397,16 +476,24 @@ class FileSoftLink(_PluginBase):
for file_name in sdirs + sfiles:
src_file = os.path.join(sroot, file_name)
if Path(str(src_file)).is_file():
self.__handle_file(event_path=str(src_file), mon_path=mon_path)
self.__handle_file(
event_path=str(src_file), mon_path=mon_path
)
logger.info(f"等待 {self._sync_interval}")
time.sleep(self._sync_interval)
if event.event_data.get("user"):
self.post_message(channel=event.event_data.get("channel"),
title=f"{all_args} 软连接完成!",
userid=event.event_data.get("user"))
self.post_message(
channel=event.event_data.get("channel"),
title=f"{all_args} 软连接完成!",
userid=event.event_data.get("user"),
)
return
if event.event_data.get("user"):
self.post_message(channel=event.event_data.get("channel"),
title=f"{all_args} 未检索到,请检查输入是否正确!",
userid=event.event_data.get("user"))
self.post_message(
channel=event.event_data.get("channel"),
title=f"{all_args} 未检索到,请检查输入是否正确!",
userid=event.event_data.get("user"),
)
def __handle_limit(self, path, limit, mon_path, event):
"""
@@ -432,9 +519,14 @@ class FileSoftLink(_PluginBase):
src_file = os.path.join(sroot, file_name)
if Path(src_file).is_file():
self.__handle_file(event_path=str(src_file), mon_path=mon_path)
logger.info(f"等待 {self._sync_interval}")
time.sleep(self._sync_interval)
if event.event_data.get("user"):
self.post_message(channel=event.event_data.get("channel"),
title=f"{sub_path} 软连接完成!", userid=event.event_data.get("user"))
self.post_message(
channel=event.event_data.get("channel"),
title=f"{sub_path} 软连接完成!",
userid=event.event_data.get("user"),
)
@staticmethod
def __find_related_paths(base_path):
@@ -466,6 +558,8 @@ class FileSoftLink(_PluginBase):
path = os.path.join(root, name)
if Path(path).is_file():
self.__handle_file(event_path=str(path), mon_path=mon_path)
logger.info(f"等待 {self._sync_interval}")
time.sleep(self._sync_interval)
logger.info("全量同步监控目录完成!")
def event_handler(self, event, mon_path: str, text: str, event_path: str):
@@ -494,10 +588,12 @@ class FileSoftLink(_PluginBase):
# 全程加锁
with lock:
# 回收站及隐藏的文件不处理
if event_path.find('/@Recycle/') != -1 \
or event_path.find('/#recycle/') != -1 \
or event_path.find('/.') != -1 \
or event_path.find('/@eaDir') != -1:
if (
event_path.find("/@Recycle/") != -1
or event_path.find("/#recycle/") != -1
or event_path.find("/.") != -1
or event_path.find("/@eaDir") != -1
):
logger.debug(f"{event_path} 是回收站或隐藏的文件")
return
@@ -505,28 +601,42 @@ class FileSoftLink(_PluginBase):
if self._exclude_keywords:
for keyword in self._exclude_keywords.split("\n"):
if keyword and re.findall(keyword, event_path):
logger.info(f"{event_path} 命中过滤关键字 {keyword},不处理")
logger.info(
f"{event_path} 命中过滤关键字 {keyword},不处理"
)
return
# 整理屏蔽词不处理
transfer_exclude_words = self.systemconfig.get(SystemConfigKey.TransferExcludeWords)
transfer_exclude_words = self.systemconfig.get(
SystemConfigKey.TransferExcludeWords
)
if transfer_exclude_words:
for keyword in transfer_exclude_words:
if not keyword:
continue
if keyword and re.search(r"%s" % keyword, event_path, re.IGNORECASE):
logger.info(f"{event_path} 命中整理屏蔽词 {keyword},不处理")
if keyword and re.search(
r"%s" % keyword, event_path, re.IGNORECASE
):
logger.info(
f"{event_path} 命中整理屏蔽词 {keyword},不处理"
)
return
# 判断是不是蓝光目录
if re.search(r"BDMV[/\\]STREAM", event_path, re.IGNORECASE):
# 截取BDMV前面的路径
blurray_dir = event_path[:event_path.find("BDMV")]
blurray_dir = event_path[: event_path.find("BDMV")]
file_path = Path(blurray_dir)
logger.info(f"{event_path} 是蓝光目录,更正文件路径为:{str(file_path)}")
logger.info(
f"{event_path} 是蓝光目录,更正文件路径为:{str(file_path)}"
)
# 判断文件大小
if self._size and float(self._size) > 0 and file_path.stat().st_size < float(self._size) * 1024 ** 3:
if (
self._size
and float(self._size) > 0
and file_path.stat().st_size < float(self._size) * 1024**3
):
logger.info(f"{file_path} 文件大小小于监控文件大小,不处理")
return
@@ -555,20 +665,27 @@ class FileSoftLink(_PluginBase):
os.makedirs(Path(target_file).parent)
# 媒体文件软连接
if Path(target_file).suffix.lower() in [ext.strip() for ext in
self._rmt_mediaext.split(",")]:
retcode, retmsg = SystemUtils.softlink(file_path, Path(target_file))
logger.info(f"创建媒体文件软连接 {str(file_path)}{target_file} {retcode} {retmsg}")
if Path(target_file).suffix.lower() in [
ext.strip() for ext in self._rmt_mediaext.split(",")
]:
retcode, retmsg = SystemUtils.softlink(
file_path, Path(target_file)
)
logger.info(
f"创建媒体文件软连接 {str(file_path)}{target_file} {retcode} {retmsg}"
)
if self._url and file_path.suffix in settings.RMT_MEDIAEXT:
RequestUtils(content_type="application/json").post(url=self._url, json={
"path": str(file_path),
"type": "add"
})
RequestUtils(content_type="application/json").post(
url=self._url,
json={"path": str(file_path), "type": "add"},
)
else:
if self._copy_files:
# 其他nfo、jpg等复制文件
shutil.copy2(str(file_path), target_file)
logger.info(f"复制其他文件 {str(file_path)}{target_file}")
logger.info(
f"复制其他文件 {str(file_path)}{target_file}"
)
except Exception as e:
logger.error("软连接发生错误:%s - %s" % (str(e), traceback.format_exc()))
@@ -587,38 +704,34 @@ class FileSoftLink(_PluginBase):
"event": EventType.PluginAction,
"desc": "文件软连接同步",
"category": "",
"data": {
"action": "softlink_sync"
}
"data": {"action": "softlink_sync"},
},
{
"cmd": "/soft",
"event": EventType.PluginAction,
"desc": "定向软连接处理",
"category": "",
"data": {
"action": "softlink_one"
}
"data": {"action": "softlink_one"},
},
{
"cmd": "/softall",
"event": EventType.PluginAction,
"desc": "定向软连接处理",
"category": "",
"data": {
"action": "softlink_all"
}
}
"data": {"action": "softlink_all"},
},
]
def get_api(self) -> List[Dict[str, Any]]:
return [{
"path": "/softlink_sync",
"endpoint": self.sync,
"methods": ["GET"],
"summary": "实时软连接同步",
"description": "实时软连接同步",
}]
return [
{
"path": "/softlink_sync",
"endpoint": self.sync,
"methods": ["GET"],
"summary": "实时软连接同步",
"description": "实时软连接同步",
}
]
def get_service(self) -> List[Dict[str, Any]]:
"""
@@ -632,13 +745,15 @@ class FileSoftLink(_PluginBase):
}]
"""
if self._enabled and self._cron:
return [{
"id": "FileSoftLink",
"name": "实时软连接全量同步服务",
"trigger": CronTrigger.from_crontab(self._cron),
"func": self.sync_all,
"kwargs": {}
}]
return [
{
"id": "FileSoftLink",
"name": "实时软连接全量同步服务",
"trigger": CronTrigger.from_crontab(self._cron),
"func": self.sync_all,
"kwargs": {},
}
]
return []
def sync(self) -> schemas.Response:
@@ -651,242 +766,241 @@ class FileSoftLink(_PluginBase):
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
return [
{
'component': 'VForm',
'content': [
"component": "VForm",
"content": [
{
'component': 'VRow',
'content': [
"component": "VRow",
"content": [
{
'component': 'VCol',
'props': {
'cols': 12,
'md': 4
},
'content': [
"component": "VCol",
"props": {"cols": 12, "md": 4},
"content": [
{
'component': 'VSwitch',
'props': {
'model': 'enabled',
'label': '启用插件',
}
"component": "VSwitch",
"props": {
"model": "enabled",
"label": "启用插件",
},
}
]
],
},
{
'component': 'VCol',
'props': {
'cols': 12,
'md': 4
},
'content': [
"component": "VCol",
"props": {"cols": 12, "md": 4},
"content": [
{
'component': 'VSwitch',
'props': {
'model': 'onlyonce',
'label': '立即运行一次',
}
"component": "VSwitch",
"props": {
"model": "onlyonce",
"label": "立即运行一次",
},
}
]
],
},
{
'component': 'VCol',
'props': {
'cols': 12,
'md': 4
},
'content': [
"component": "VCol",
"props": {"cols": 12, "md": 4},
"content": [
{
'component': 'VSwitch',
'props': {
'model': 'copy_files',
'label': '复制非媒体文件',
}
"component": "VSwitch",
"props": {
"model": "copy_files",
"label": "复制非媒体文件",
},
}
]
}
]
],
},
],
},
{
'component': 'VRow',
'content': [
"component": "VRow",
"content": [
{
'component': 'VCol',
'props': {
'cols': 12,
'md': 4
},
'content': [
"component": "VCol",
"props": {"cols": 12, "md": 4},
"content": [
{
'component': 'VSelect',
'props': {
'model': 'mode',
'label': '监控模式',
'items': [
{'title': '兼容模式', 'value': 'compatibility'},
{'title': '性能模式', 'value': 'fast'},
{'title': '不监控', 'value': 'nomonitor'},
]
}
"component": "VSelect",
"props": {
"model": "mode",
"label": "监控模式",
"items": [
{
"title": "兼容模式",
"value": "compatibility",
},
{"title": "性能模式", "value": "fast"},
{
"title": "不监控",
"value": "nomonitor",
},
],
},
}
]
],
},
{
'component': 'VCol',
'props': {
'cols': 12,
'md': 4
},
'content': [
"component": "VCol",
"props": {"cols": 12, "md": 4},
"content": [
{
'component': 'VTextField',
'props': {
'model': 'cron',
'label': '定时全量同步周期',
'placeholder': '5位cron表达式留空关闭'
}
"component": "VTextField",
"props": {
"model": "cron",
"label": "定时全量同步周期",
"placeholder": "5位cron表达式留空关闭",
},
}
]
],
},
{
'component': 'VCol',
'props': {
'cols': 12,
'md': 4
},
'content': [
"component": "VCol",
"props": {"cols": 12, "md": 4},
"content": [
{
'component': 'VTextField',
'props': {
'model': 'size',
'label': '监控文件大小GB',
'placeholder': '0'
}
"component": "VTextField",
"props": {
"model": "size",
"label": "监控文件大小GB",
"placeholder": "0",
},
}
]
}
]
},
{
'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': '每一行一个关键词'
}
}
]
}
]
},
{
'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': [
{
'component': 'VCol',
'props': {
'cols': 12,
},
'content': [
{
'component': 'VTextField',
'props': {
'model': 'url',
'label': '任务推送url',
'placeholder': 'post请求json方式推送path和type(add)字段'
}
}
]
],
},
]
{
"component": "VCol",
"props": {"cols": 12, "md": 4},
"content": [
{
"component": "VTextField",
"props": {
"model": "sync_interval",
"label": "同步间隔(秒)",
"placeholder": "0",
},
}
],
},
],
},
{
'component': 'VRow',
'content': [
"component": "VRow",
"content": [
{
'component': 'VCol',
'props': {
'cols': 12,
},
'content': [
"component": "VCol",
"props": {"cols": 12},
"content": [
{
'component': 'VAlert',
'props': {
'type': 'info',
'variant': 'tonal',
'text': '监控文件大小单位GB0为不开启低于监控文件大小的文件不会被监控转移。'
}
"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": "每一行一个关键词",
},
}
],
}
],
},
{
"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": [
{
"component": "VCol",
"props": {
"cols": 12,
},
"content": [
{
"component": "VTextField",
"props": {
"model": "url",
"label": "任务推送url",
"placeholder": "post请求json方式推送path和type(add)字段",
},
}
],
},
],
},
{
"component": "VRow",
"content": [
{
"component": "VCol",
"props": {
"cols": 12,
},
"content": [
{
"component": "VAlert",
"props": {
"type": "info",
"variant": "tonal",
"text": "监控文件大小单位GB0为不开启低于监控文件大小的文件不会被监控转移。",
},
}
],
}
],
},
],
}
], {
"enabled": False,
"onlyonce": False,
"copy_files": True,
"sync_interval": 0,
"mode": "compatibility",
"monitor_dirs": "",
"exclude_keywords": "",
"cron": "",
"size": 0,
"url": "",
"rmt_mediaext": ".mp4, .mkv, .ts, .iso,.rmvb, .avi, .mov, .mpeg,.mpg, .wmv, .3gp, .asf, .m4v, .flv, .m2ts, .strm,.tp, .f4v"
"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]: