mirror of
https://github.com/d0zingcat/MoviePilot-Plugins.git
synced 2026-05-22 07:26:45 +00:00
Merge branch 'main' of https://github.com/InfinityPacer/MoviePilot-Plugins-PR
This commit is contained in:
30
README.md
30
README.md
@@ -80,6 +80,8 @@ class EventType(Enum):
|
||||
SubscribeAdded = "subscribe.added"
|
||||
# 订阅已完成
|
||||
SubscribeComplete = "subscribe.complete"
|
||||
# 系统错误
|
||||
SystemError = "system.error"
|
||||
```
|
||||
|
||||
### 2. 如何在插件中实现远程命令响应?
|
||||
@@ -426,7 +428,7 @@ class EventType(Enum):
|
||||
- **请不要添加对黄赌毒站点的支持,否则随时封闭接口。**
|
||||
|
||||
### 7. 如何在插件中调用API接口?
|
||||
- 目前仅在插件的数据页面支持`GET/POST`API接口调用,可调用插件自身、主程序或其它插件的API(v1.8.4+)。
|
||||
- `v1.8.4+` 在插件的数据页面支持`GET/POST`API接口调用,可调用插件自身、主程序或其它插件的API。
|
||||
- 在`get_page`中定义好元素的事件,以及相应的API参数,具体可参考插件`豆瓣想看`:
|
||||
```json
|
||||
{
|
||||
@@ -448,11 +450,27 @@ class EventType(Enum):
|
||||
### 8. 如何将插件内容显示到仪表板?
|
||||
- `v1.8.7+` 支持将插件的内容显示到仪表盘,并支持定义占据的单元格大小,插件产生的仪表板仅管理员可见。
|
||||
- 1. 根据插件需要展示的Widget内容规划展示内容的样式和规格,也可设计多个规格样式并提供配置项供用户选择。
|
||||
- 2. 实现 `get_dashboard` 方法,返回仪表盘的配置信息,包括仪表盘的cols列配置(适配不同屏幕),以及仪表盘的页面配置json,具体可参考插件`站点数据统计`:
|
||||
- 2. 实现 `get_dashboard_meta` 方法,定义仪表板key及名称,支持一个插件有多个仪表板:
|
||||
```python
|
||||
def get_dashboard(self, **kwargs) -> Optional[Tuple[Dict[str, Any], Dict[str, Any], List[dict]]]:
|
||||
def get_dashboard_meta(self) -> Optional[List[Dict[str, str]]]:
|
||||
"""
|
||||
获取插件仪表盘页面,需要返回:1、仪表板cols配置字典;2、全局配置(自动刷新等);2、仪表板页面元素配置json(含数据)
|
||||
获取插件仪表盘元信息
|
||||
返回示例:
|
||||
[{
|
||||
"key": "dashboard1", // 仪表盘的key,在当前插件范围唯一
|
||||
"name": "仪表盘1" // 仪表盘的名称
|
||||
}, {
|
||||
"key": "dashboard2",
|
||||
"name": "仪表盘2"
|
||||
}]
|
||||
"""
|
||||
pass
|
||||
```
|
||||
- 3. 实现 `get_dashboard` 方法,根据key返回仪表盘的详细配置信息,包括仪表盘的cols列配置(适配不同屏幕),以及仪表盘的页面配置json,具体可参考插件`站点数据统计`:
|
||||
```python
|
||||
def get_dashboard(self, key: str, **kwargs) -> Optional[Tuple[Dict[str, Any], Dict[str, Any], List[dict]]]:
|
||||
"""
|
||||
获取插件仪表盘页面,需要返回:1、仪表板col配置字典;2、全局配置(自动刷新等);3、仪表板页面元素配置json(含数据)
|
||||
1、col配置参考:
|
||||
{
|
||||
"cols": 12, "md": 6
|
||||
@@ -465,8 +483,10 @@ def get_dashboard(self, **kwargs) -> Optional[Tuple[Dict[str, Any], Dict[str, An
|
||||
"subtitle": "组件子标题", // 组件子标题,缺省时不展示子标题
|
||||
}
|
||||
3、页面配置使用Vuetify组件拼装,参考:https://vuetifyjs.com/
|
||||
|
||||
|
||||
kwargs参数可获取的值:1、user_agent:浏览器UA
|
||||
|
||||
:param key: 仪表盘key,根据指定的key返回相应的仪表盘数据,缺省时返回一个固定的仪表盘数据(兼容旧版)
|
||||
"""
|
||||
pass
|
||||
```
|
||||
|
||||
BIN
icons/TrendingShow.jpg
Normal file
BIN
icons/TrendingShow.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 121 KiB |
52
package.json
52
package.json
@@ -3,11 +3,12 @@
|
||||
"name": "站点自动签到",
|
||||
"description": "自动模拟登录、签到站点。",
|
||||
"labels": "站点",
|
||||
"version": "2.3.1",
|
||||
"version": "2.3.2",
|
||||
"icon": "signin.png",
|
||||
"author": "thsrite",
|
||||
"level": 2,
|
||||
"history": {
|
||||
"v2.3.2": "修复YemaPT登录失败,支持YemaPT自动签到",
|
||||
"v2.3.1": "修复签到报错问题",
|
||||
"v2.3": "优化模拟登录逻辑,支持YemaPT模拟登录",
|
||||
"v2.2": "适配馒头最新变化,需要升级至v1.8.5+版本且维护好Authorization",
|
||||
@@ -74,11 +75,13 @@
|
||||
"name": "目录监控",
|
||||
"description": "监控目录文件发生变化时实时整理到媒体库。",
|
||||
"labels": "文件整理",
|
||||
"version": "2.0",
|
||||
"version": "2.2",
|
||||
"icon": "directory.png",
|
||||
"author": "jxxghp",
|
||||
"level": 1,
|
||||
"history": {
|
||||
"v2.2": "更新目录设置说明",
|
||||
"v2.1": "增加了元数据刮削开关,升级后需要手动打开,否则默认不刮削",
|
||||
"v2.0": "增强API安全性",
|
||||
"v1.9": "修复目录监控不能正确获取下载历史记录进行识别的问题"
|
||||
}
|
||||
@@ -110,10 +113,13 @@
|
||||
"name": "媒体库刮削",
|
||||
"description": "定时对媒体库进行刮削,补齐缺失元数据和图片。",
|
||||
"labels": "刮削",
|
||||
"version": "1.4",
|
||||
"version": "1.4.1",
|
||||
"icon": "scraper.png",
|
||||
"author": "jxxghp",
|
||||
"level": 1
|
||||
"level": 1,
|
||||
"history": {
|
||||
"v1.4.1": "修复nfo文件读取失败时任务中断问题"
|
||||
}
|
||||
},
|
||||
"TorrentRemover": {
|
||||
"name": "自动删种",
|
||||
@@ -128,11 +134,12 @@
|
||||
"name": "媒体文件同步删除",
|
||||
"description": "同步删除历史记录、源文件和下载任务。",
|
||||
"labels": "文件整理",
|
||||
"version": "1.5",
|
||||
"version": "1.6",
|
||||
"icon": "mediasyncdel.png",
|
||||
"author": "thsrite",
|
||||
"level": 1,
|
||||
"history": {
|
||||
"v1.6": "修复删除辅种",
|
||||
"v1.5": "支持手动删除订阅历史记录(本次更新之后的历史)"
|
||||
}
|
||||
},
|
||||
@@ -278,11 +285,12 @@
|
||||
"name": "整理VCB动漫压制组作品",
|
||||
"description": "提高部分VCB-Studio作品的识别准确率,将VCB-Studio的作品统一转移到指定目录同时进行刮削整理",
|
||||
"labels": "文件整理,识别",
|
||||
"version": "1.7.1",
|
||||
"version": "1.8",
|
||||
"icon": "vcbmonitor.png",
|
||||
"author": "pixel@qingwa",
|
||||
"level": 2,
|
||||
"history": {
|
||||
"v1.8": "增加了元数据刮削开关,升级后需要手动打开,否则默认不刮削",
|
||||
"v1.7.1": "修复偶尔安装失败问题"
|
||||
}
|
||||
},
|
||||
@@ -302,11 +310,12 @@
|
||||
"name": "自定义订阅",
|
||||
"description": "定时刷新RSS报文,识别内容后添加订阅或直接下载。",
|
||||
"labels": "订阅",
|
||||
"version": "1.3",
|
||||
"version": "1.4",
|
||||
"icon": "rss.png",
|
||||
"author": "jxxghp",
|
||||
"level": 2,
|
||||
"history": {
|
||||
"v1.4": "修复剧集本地是否存在的判断错误问题",
|
||||
"v1.3": "支持手动删除订阅历史记录"
|
||||
}
|
||||
},
|
||||
@@ -529,7 +538,7 @@
|
||||
"name": "二级分类策略",
|
||||
"description": "编辑下载目录和媒体库目录的二级分类规则。",
|
||||
"labels": "文件整理",
|
||||
"version": "1.1",
|
||||
"version": "1.2",
|
||||
"icon": "Bookstack_A.png",
|
||||
"author": "jxxghp",
|
||||
"level": 1
|
||||
@@ -631,11 +640,15 @@
|
||||
"name": "下载器助手",
|
||||
"description": "自动做种、站点标签、自动删种。",
|
||||
"labels": "下载管理,仪表板",
|
||||
"version": "2.2",
|
||||
"version": "2.6",
|
||||
"icon": "DownloaderHelper.png",
|
||||
"author": "hotlcc",
|
||||
"level": 2,
|
||||
"level": 1,
|
||||
"history": {
|
||||
"v2.6": "新增仪表板实时速率组件,支持单独展示qb和tr的实时速率(tr未测试,有问题提Issue并@hotlcc)。",
|
||||
"v2.5": "优化通知类型;降低认证级别要求,使MP非认证用户可用,但无法使用【站点名称优先】功能。主程序需升级至v1.9.2及以上版本,否则插件功能异常!",
|
||||
"v2.4": "修复tr活动种子仪表板的种子排序的bug;优化插件的消息发送。",
|
||||
"v2.3": "仪表板支持多个下载器活动种子组件(主程序版本需大于v1.9.1)。",
|
||||
"v2.2": "优化仪表板组件标题;优化仪表板下载剩余时间描述。",
|
||||
"v2.1": "优化了初始配置建议;优化了配置Tracker的弹窗大小。",
|
||||
"v2.0": "优化了仪表板种子状态;提升仪表板对TR的适配度。",
|
||||
@@ -679,11 +692,12 @@
|
||||
"name": "插件自动升级",
|
||||
"description": "定时检测、升级插件。",
|
||||
"labels": "自动更新",
|
||||
"version": "1.8",
|
||||
"version": "1.9",
|
||||
"icon": "PluginAutoUpgrade.png",
|
||||
"author": "hotlcc",
|
||||
"level": 1,
|
||||
"history": {
|
||||
"v1.9": "优化通知类型。主程序需升级至v1.9.2及以上版本,否则插件功能异常!",
|
||||
"v1.8": "修复重置插件后丢失配置建议的问题。",
|
||||
"v1.7": "修复了一些BUG。",
|
||||
"v1.6": "修正数字配置值提交为字符串导致的问题。",
|
||||
@@ -727,11 +741,14 @@
|
||||
"name": "清理QB无效做种",
|
||||
"description": "清理已经被站点删除的种子及对应源文件,仅支持QB",
|
||||
"labels": "Qbittorrent",
|
||||
"version": "1.5",
|
||||
"version": "1.8",
|
||||
"icon": "clean_a.png",
|
||||
"author": "DzAvril",
|
||||
"level": 1,
|
||||
"history": {
|
||||
"v1.8": "增加远程命令切换全量通知;修复bug",
|
||||
"v1.7": "修复因消息内容包含'_'导致telegram API调用失败的问题",
|
||||
"v1.6": "修复当种子有多个标签时,通过标签过滤不删除种子会失效的问题",
|
||||
"v1.5": "1. 增加通过分类、标签过滤不删除种子功能;2. 全量通知提供更多信息",
|
||||
"v1.4": "修复插件功能失效的问题",
|
||||
"v1.3": "1. 增加远程命令 2. 根据tracker error_message字段进行过滤,避免误删",
|
||||
@@ -745,7 +762,16 @@
|
||||
"description": "在仪表板中显示流行趋势海报轮播图。",
|
||||
"labels": "仪表板",
|
||||
"version": "1.0",
|
||||
"icon": "Dsphoto_A.png",
|
||||
"icon": "TrendingShow.jpg",
|
||||
"author": "jxxghp",
|
||||
"level": 1
|
||||
},
|
||||
"DailyWord": {
|
||||
"name": "每日一言",
|
||||
"description": "在仪表板中显示每日一言卡片。",
|
||||
"labels": "仪表板",
|
||||
"version": "1.1",
|
||||
"icon": "Calibre_B.png",
|
||||
"author": "jxxghp",
|
||||
"level": 1
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class AutoSignIn(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "signin.png"
|
||||
# 插件版本
|
||||
plugin_version = "2.3.1"
|
||||
plugin_version = "2.3.2"
|
||||
# 插件作者
|
||||
plugin_author = "thsrite"
|
||||
# 作者主页
|
||||
|
||||
@@ -8,9 +8,9 @@ from app.plugins.autosignin.sites import _ISiteSigninHandler
|
||||
from app.utils.http import RequestUtils
|
||||
|
||||
|
||||
class MTorrent(_ISiteSigninHandler):
|
||||
class YemaPT(_ISiteSigninHandler):
|
||||
"""
|
||||
m-team签到
|
||||
YemaPT 签到
|
||||
"""
|
||||
# 匹配的站点Url,每一个实现类都需要设置为自己的站点Url
|
||||
site_url = "yemapt.org"
|
||||
@@ -26,7 +26,7 @@ class MTorrent(_ISiteSigninHandler):
|
||||
|
||||
def signin(self, site_info: CommentedMap) -> Tuple[bool, str]:
|
||||
"""
|
||||
执行签到操作,馒头实际没有签到,非仿真模式下需要更新访问时间
|
||||
执行签到操作
|
||||
:param site_info: 站点信息,含有站点Url、站点Cookie、UA等信息
|
||||
:return: 签到结果信息
|
||||
"""
|
||||
@@ -35,19 +35,20 @@ class MTorrent(_ISiteSigninHandler):
|
||||
"User-Agent": site_info.get("ua"),
|
||||
"Accept": "application/json, text/plain, */*",
|
||||
}
|
||||
# 更新最后访问时间
|
||||
res = RequestUtils(headers=headers,
|
||||
timeout=15,
|
||||
cookies=site_info.get("cookie"),
|
||||
proxies=settings.PROXY if site_info.get("proxy") else None,
|
||||
referer=site_info.get('url')
|
||||
).post_res(url=urljoin(site_info.get('url'), "api/user/profile"))
|
||||
# 获取用户信息,更新最后访问时间
|
||||
res = (RequestUtils(headers=headers,
|
||||
timeout=15,
|
||||
cookies=site_info.get("cookie"),
|
||||
proxies=settings.PROXY if site_info.get("proxy") else None,
|
||||
referer=site_info.get('url')
|
||||
).get_res(urljoin(site_info.get('url'), "api/consumer/checkIn")))
|
||||
|
||||
if res and res.json().get("success"):
|
||||
return True, "模拟登录成功"
|
||||
return True, "签到成功"
|
||||
elif res is not None:
|
||||
return False, f"模拟登录失败,状态码:{res.status_code}"
|
||||
return False, f"签到失败,签到结果:{res.json().get('errorMessage')}"
|
||||
else:
|
||||
return False, "模拟登录失败,无法打开网站"
|
||||
return False, "签到失败,无法打开网站"
|
||||
|
||||
def login(self, site_info: CommentedMap) -> Tuple[bool, str]:
|
||||
"""
|
||||
@@ -55,4 +56,23 @@ class MTorrent(_ISiteSigninHandler):
|
||||
:param site_info: 站点信息,含有站点Url、站点Cookie、UA等信息
|
||||
:return: 登录结果信息
|
||||
"""
|
||||
return self.signin(site_info)
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": site_info.get("ua"),
|
||||
"Accept": "application/json, text/plain, */*",
|
||||
}
|
||||
# 获取用户信息,更新最后访问时间
|
||||
res = (RequestUtils(headers=headers,
|
||||
timeout=15,
|
||||
cookies=site_info.get("cookie"),
|
||||
proxies=settings.PROXY if site_info.get("proxy") else None,
|
||||
referer=site_info.get('url')
|
||||
).get_res(urljoin(site_info.get('url'), "api/user/profile")))
|
||||
|
||||
if res and res.json().get("success"):
|
||||
return True, "模拟登录成功"
|
||||
elif res is not None:
|
||||
return False, f"模拟登录失败,状态码:{res.status_code}"
|
||||
else:
|
||||
return False, "模拟登录失败,无法打开网站"
|
||||
|
||||
@@ -13,7 +13,7 @@ class CategoryEditor(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "Bookstack_A.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.1"
|
||||
plugin_version = "1.2"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -39,12 +39,9 @@ class CategoryEditor(_PluginBase):
|
||||
# 写入文件
|
||||
if self._enabled:
|
||||
self.user_yaml.write_text(self._content, encoding="utf-8")
|
||||
if not settings.LIBRARY_CATEGORY:
|
||||
self.systemmessage.put("二级分类未开启,策略已保存但未生效!", title="二级分类策略")
|
||||
return
|
||||
# 立即生效
|
||||
CategoryHelper().init()
|
||||
self.systemmessage.put("二级分类策略已更新!", title="二级分类策略")
|
||||
self.systemmessage.put("二级分类策略已更新,请注意同步调整目录设置!", title="二级分类策略")
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled
|
||||
|
||||
@@ -28,7 +28,7 @@ class CleanInvalidSeed(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "clean_a.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.5"
|
||||
plugin_version = "1.8"
|
||||
# 插件作者
|
||||
plugin_author = "DzAvril"
|
||||
# 作者主页
|
||||
@@ -94,22 +94,7 @@ class CleanInvalidSeed(_PluginBase):
|
||||
)
|
||||
# 关闭一次性开关
|
||||
self._onlyonce = False
|
||||
self.update_config(
|
||||
{
|
||||
"onlyonce": False,
|
||||
"cron": self._cron,
|
||||
"enabled": self._enabled,
|
||||
"notify": self._notify,
|
||||
"delete_invalid_torrents": self._delete_invalid_torrents,
|
||||
"delete_invalid_files": self._delete_invalid_files,
|
||||
"detect_invalid_files": self._detect_invalid_files,
|
||||
"notify_all": self._notify_all,
|
||||
"download_dirs": self._download_dirs,
|
||||
"exclude_keywords": self._exclude_keywords,
|
||||
"exclude_categories": self._exclude_categories,
|
||||
"exclude_labels": self._exclude_labels,
|
||||
}
|
||||
)
|
||||
self._update_config()
|
||||
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
@@ -119,6 +104,24 @@ class CleanInvalidSeed(_PluginBase):
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled
|
||||
|
||||
def _update_config(self):
|
||||
self.update_config(
|
||||
{
|
||||
"onlyonce": False,
|
||||
"cron": self._cron,
|
||||
"enabled": self._enabled,
|
||||
"notify": self._notify,
|
||||
"delete_invalid_torrents": self._delete_invalid_torrents,
|
||||
"delete_invalid_files": self._delete_invalid_files,
|
||||
"detect_invalid_files": self._detect_invalid_files,
|
||||
"notify_all": self._notify_all,
|
||||
"download_dirs": self._download_dirs,
|
||||
"exclude_keywords": self._exclude_keywords,
|
||||
"exclude_categories": self._exclude_categories,
|
||||
"exclude_labels": self._exclude_labels,
|
||||
}
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_command() -> List[Dict[str, Any]]:
|
||||
"""
|
||||
@@ -154,6 +157,13 @@ class CleanInvalidSeed(_PluginBase):
|
||||
"category": "QB",
|
||||
"data": {"action": "delete_invalid_files"},
|
||||
},
|
||||
{
|
||||
"cmd": "/toggle_notify_all",
|
||||
"event": EventType.PluginAction,
|
||||
"desc": "QB清理插件切换全量通知",
|
||||
"category": "QB",
|
||||
"data": {"action": "toggle_notify_all"},
|
||||
},
|
||||
]
|
||||
|
||||
@eventmanager.register(EventType.PluginAction)
|
||||
@@ -189,6 +199,22 @@ class CleanInvalidSeed(_PluginBase):
|
||||
logger.info("收到远程命令,开始清理无效源文件")
|
||||
self._delete_invalid_files = True
|
||||
self.detect_invalid_files()
|
||||
elif event_data.get("action") == "toggle_notify_all":
|
||||
self._notify_all = not self._notify_all
|
||||
self._update_config()
|
||||
if self._notify_all:
|
||||
self.post_message(
|
||||
channel=event.event_data.get("channel"),
|
||||
title="已开启全量通知",
|
||||
userid=event.event_data.get("user"),
|
||||
)
|
||||
else:
|
||||
self.post_message(
|
||||
channel=event.event_data.get("channel"),
|
||||
title="已关闭全量通知",
|
||||
userid=event.event_data.get("user"),
|
||||
)
|
||||
return
|
||||
else:
|
||||
logger.error("收到未知远程命令")
|
||||
return
|
||||
@@ -256,8 +282,8 @@ class CleanInvalidSeed(_PluginBase):
|
||||
# tracker未工作,但暂时不能判定为失效做种,需人工判断
|
||||
tracker_not_working_torrents = []
|
||||
working_tracker_set = set()
|
||||
exclude_categories = self._exclude_categories.split("\n")
|
||||
exclude_labels = self._exclude_labels.split("\n")
|
||||
exclude_categories = self._exclude_categories.split("\n") if self._exclude_categories else []
|
||||
exclude_labels = self._exclude_labels.split("\n") if self._exclude_labels else []
|
||||
# 第一轮筛选出所有未工作的种子
|
||||
for torrent in all_torrents:
|
||||
trackers = torrent.trackers
|
||||
@@ -307,7 +333,7 @@ class CleanInvalidSeed(_PluginBase):
|
||||
if torrent.category in exclude_categories:
|
||||
is_excluded = True
|
||||
invalid_torrents_exclude_categories.append(torrent)
|
||||
torrent_labels = torrent.tags.split(",")
|
||||
torrent_labels = [tag.strip() for tag in torrent.tags.split(",")]
|
||||
for label in torrent_labels:
|
||||
if label in exclude_labels:
|
||||
is_excluded = True
|
||||
@@ -398,29 +424,34 @@ class CleanInvalidSeed(_PluginBase):
|
||||
logger.info(exclude_labels_msg)
|
||||
# 通知
|
||||
if self._notify:
|
||||
invalid_msg = invalid_msg.replace('_', '\_')
|
||||
self.post_message(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【清理无效做种】",
|
||||
text=invalid_msg,
|
||||
)
|
||||
if self._notify_all:
|
||||
tracker_not_working_msg = tracker_not_working_msg.replace('_', '\_')
|
||||
self.post_message(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【清理无效做种】",
|
||||
text=tracker_not_working_msg,
|
||||
)
|
||||
if self._delete_invalid_torrents:
|
||||
deleted_msg = deleted_msg.replace('_', '\_')
|
||||
self.post_message(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【清理无效做种】",
|
||||
text=deleted_msg,
|
||||
)
|
||||
if self._notify_all:
|
||||
exclude_categories_msg = exclude_categories_msg.replace('_', '\_')
|
||||
self.post_message(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【清理无效做种】",
|
||||
text=exclude_categories_msg,
|
||||
)
|
||||
exclude_labels_msg = exclude_labels_msg.replace('_', '\_')
|
||||
self.post_message(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【清理无效做种】",
|
||||
@@ -437,7 +468,15 @@ class CleanInvalidSeed(_PluginBase):
|
||||
source_paths = []
|
||||
total_size = 0
|
||||
deleted_file_cnt = 0
|
||||
exclude_key_words = self._exclude_keywords.split("\n")
|
||||
exclude_key_words = self._exclude_keywords.split("\n") if self._exclude_keywords else []
|
||||
if not self._download_dirs:
|
||||
logger.error("未配置下载目录,无法检测未做种无效源文件")
|
||||
self.post_message(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【检测无效源文件】",
|
||||
text="未配置下载目录,无法检测未做种无效源文件",
|
||||
)
|
||||
return
|
||||
for path in self._download_dirs.split("\n"):
|
||||
mp_path, qb_path = path.split(":")
|
||||
source_path_map[mp_path] = qb_path
|
||||
@@ -489,6 +528,7 @@ class CleanInvalidSeed(_PluginBase):
|
||||
message += f"***已删除无效源文件,释放{StringUtils.str_filesize(total_size)}空间!***\n"
|
||||
logger.info(message)
|
||||
if self._notify:
|
||||
message = message.replace('_', '\_')
|
||||
self.post_message(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"【清理无效做种】",
|
||||
@@ -754,3 +794,23 @@ class CleanInvalidSeed(_PluginBase):
|
||||
self._scheduler = None
|
||||
except Exception as e:
|
||||
logger.error("退出插件失败:%s" % str(e))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
clean = CleanInvalidSeed()
|
||||
config = {
|
||||
"enabled": True,
|
||||
"notify": True,
|
||||
"download_dirs": "/sata16t/春天:/保种/春天\n/sata16t/观众:/保种/观众\n/sata16t/UB:/保种/UB\n/sata16t/听听歌:/保种/听听歌\n/ssd/Download/shualiu:/Downloads/shualiu",
|
||||
"delete_invalid_torrents": False,
|
||||
"delete_invalid_files": False,
|
||||
"detect_invalid_files": True,
|
||||
"notify_all": False,
|
||||
"onlyonce": False,
|
||||
"cron": "0 0 * * *",
|
||||
"exclude_keywords": "ABF-075\nIPZZ-002-C_GG5\nIPZZ-061\n.!qB",
|
||||
"exclude_categories": "电影",
|
||||
"exclude_labels": "春天",
|
||||
}
|
||||
clean.init_plugin(config)
|
||||
clean.clean_invalid_seed()
|
||||
@@ -294,7 +294,8 @@ class CrossSeed(_PluginBase):
|
||||
for site_key in self._token.strip().split("\n"):
|
||||
site_key_arr = re.split(r"[\s::]+", site_key.strip())
|
||||
site_name = site_key_arr[0]
|
||||
site_name_key_map[site_name] = site_key_arr[1]
|
||||
if len(site_key_arr) > 1:
|
||||
site_name_key_map[site_name] = site_key_arr[1]
|
||||
if len(site_key_arr) > 2:
|
||||
if str.isdigit(site_key_arr[2]):
|
||||
site_name_gap_map[site_name] = int(site_key_arr[2])
|
||||
|
||||
250
plugins/dailyword/__init__.py
Normal file
250
plugins/dailyword/__init__.py
Normal file
@@ -0,0 +1,250 @@
|
||||
from datetime import datetime
|
||||
from functools import lru_cache
|
||||
from typing import List, Tuple, Dict, Any, Optional
|
||||
|
||||
from app.plugins import _PluginBase
|
||||
from app.utils.http import RequestUtils
|
||||
|
||||
|
||||
class DailyWord(_PluginBase):
|
||||
# 插件名称
|
||||
plugin_name = "每日一言"
|
||||
# 插件描述
|
||||
plugin_desc = "在仪表板中显示每日一言卡片。"
|
||||
# 插件图标
|
||||
plugin_icon = "Calibre_B.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.1"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
author_url = "https://github.com/jxxghp"
|
||||
# 插件配置项ID前缀
|
||||
plugin_config_prefix = "dailyowrd_"
|
||||
# 加载顺序
|
||||
plugin_order = 99
|
||||
# 可使用的用户级别
|
||||
auth_level = 1
|
||||
|
||||
_enable: bool = False
|
||||
_size: str = "mini"
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self._enable = config.get("enable")
|
||||
self._size = config.get("size")
|
||||
|
||||
@staticmethod
|
||||
def get_command() -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
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': 'enable',
|
||||
'label': '启用插件',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12,
|
||||
'md': 4
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VSelect',
|
||||
'props': {
|
||||
'model': 'size',
|
||||
'label': '组件规格',
|
||||
'items': [
|
||||
{"title": "迷你", "value": "mini"},
|
||||
{"title": "小型", "value": "small"},
|
||||
{"title": "中型", "value": "medium"},
|
||||
{"title": "大型", "value": "large"}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
], {
|
||||
"enable": self._enable,
|
||||
"size": self._size
|
||||
}
|
||||
|
||||
def get_page(self) -> List[dict]:
|
||||
pass
|
||||
|
||||
def get_dashboard_meta(self) -> Optional[List[Dict[str, str]]]:
|
||||
"""
|
||||
获取插件仪表盘元信息
|
||||
返回示例:
|
||||
[{
|
||||
"key": "dashboard1", // 仪表盘的key,在当前插件范围唯一
|
||||
"name": "仪表盘1" // 仪表盘的名称
|
||||
}, {
|
||||
"key": "dashboard2",
|
||||
"name": "仪表盘2"
|
||||
}]
|
||||
"""
|
||||
return [{
|
||||
"key": "dailyword_dashboard",
|
||||
"name": "每日一言"
|
||||
}]
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def __get_youngam(self, **kwargs) -> Optional[dict]:
|
||||
"""
|
||||
获取每日一言,缓存12小时
|
||||
"""
|
||||
res = RequestUtils().get_res("https://apier.youngam.cn/essay/one")
|
||||
if res:
|
||||
datalist = res.json().get("dataList")
|
||||
return datalist[0] if datalist else {}
|
||||
return {}
|
||||
|
||||
def get_dashboard(self, key: str = None, **kwargs) -> Optional[Tuple[Dict[str, Any], Dict[str, Any], List[dict]]]:
|
||||
"""
|
||||
获取插件仪表盘页面,需要返回:1、仪表板col配置字典;2、全局配置(自动刷新等);3、仪表板页面元素配置json(含数据)
|
||||
1、col配置参考:
|
||||
{
|
||||
"cols": 12, "md": 6
|
||||
}
|
||||
2、全局配置参考:
|
||||
{
|
||||
"refresh": 10 // 自动刷新时间,单位秒
|
||||
}
|
||||
3、页面配置使用Vuetify组件拼装,参考:https://vuetifyjs.com/
|
||||
"""
|
||||
# 列配置
|
||||
if self._size == "mini":
|
||||
cols = {
|
||||
"cols": 12,
|
||||
"md": 4
|
||||
}
|
||||
height = 160
|
||||
elif self._size == "small":
|
||||
cols = {
|
||||
"cols": 12,
|
||||
"md": 6
|
||||
}
|
||||
height = 262
|
||||
elif self._size == "medium":
|
||||
cols = {
|
||||
"cols": 12,
|
||||
"md": 8
|
||||
}
|
||||
height = 335
|
||||
else:
|
||||
cols = {
|
||||
"cols": 12,
|
||||
"md": 12
|
||||
}
|
||||
height = 500
|
||||
# 全局配置
|
||||
attrs = {
|
||||
"border": False
|
||||
}
|
||||
# 获取流行越势数据
|
||||
data = self.__get_youngam(today=datetime.now().strftime("%Y-%m-%d"))
|
||||
if not data:
|
||||
elements = [
|
||||
{
|
||||
'component': 'VCard',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VCardText',
|
||||
'props': {
|
||||
'class': 'text-center',
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'span',
|
||||
'props': {
|
||||
'class': 'text-h6'
|
||||
},
|
||||
'text': '无数据'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
else:
|
||||
elements = [
|
||||
{
|
||||
'component': 'VCard',
|
||||
'props': {
|
||||
'class': 'p-0'
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VImg',
|
||||
'props': {
|
||||
'src': data.get('src'),
|
||||
'cover': True,
|
||||
'height': height
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VCardText',
|
||||
'props': {
|
||||
'class': 'w-full flex flex-col flex-wrap justify-end align-left text-white absolute bottom-0 pa-4',
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'h1',
|
||||
'props': {
|
||||
'class': 'mb-1 text-white text-shadow text-xl line-clamp-4 overflow-hidden text-ellipsis ...'
|
||||
},
|
||||
'html': data.get('text'),
|
||||
},
|
||||
{
|
||||
'component': 'span',
|
||||
'props': {
|
||||
'class': 'text-right text-shadow line-clamp-2 overflow-hidden text-ellipsis ...'
|
||||
},
|
||||
'text': f"{data.get('year')}年{data.get('month')}月{data.get('day')}日",
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}]
|
||||
|
||||
return cols, attrs, elements
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enable
|
||||
|
||||
def stop_service(self):
|
||||
pass
|
||||
@@ -59,7 +59,7 @@ class DirMonitor(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "directory.png"
|
||||
# 插件版本
|
||||
plugin_version = "2.0"
|
||||
plugin_version = "2.2"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -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()
|
||||
@@ -235,7 +237,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)
|
||||
@@ -457,7 +460,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)
|
||||
@@ -756,7 +759,7 @@ class DirMonitor(_PluginBase):
|
||||
'component': 'VSelect',
|
||||
'props': {
|
||||
'model': 'transfer_type',
|
||||
'label': '转移方式',
|
||||
'label': '整理方式',
|
||||
'items': [
|
||||
{'title': '移动', 'value': 'move'},
|
||||
{'title': '复制', 'value': 'copy'},
|
||||
@@ -824,6 +827,22 @@ class DirMonitor(_PluginBase):
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12,
|
||||
'md': 4
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VSwitch',
|
||||
'props': {
|
||||
'model': 'scrape',
|
||||
'label': '刮削元数据',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -844,9 +863,9 @@ class DirMonitor(_PluginBase):
|
||||
'rows': 5,
|
||||
'placeholder': '每一行一个目录,支持以下几种配置方式,转移方式支持 move、copy、link、softlink、rclone_copy、rclone_move:\n'
|
||||
'监控目录\n'
|
||||
'监控目录#转移方式\n'
|
||||
'监控目录:转移目的目录\n'
|
||||
'监控目录:转移目的目录#转移方式'
|
||||
'监控目录#整理方式\n'
|
||||
'监控目录:整理目的目录\n'
|
||||
'监控目录:整理目的目录#转移方式'
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -889,7 +908,7 @@ class DirMonitor(_PluginBase):
|
||||
'props': {
|
||||
'type': 'info',
|
||||
'variant': 'tonal',
|
||||
'text': '监控目录不指定目的目录时,将转移到媒体库目录,并自动创建一级分类目录,同时按配置创建二级分类目录;监控目录指定了目的目录时,不会自动创建一级目录,但会根据配置创建二级分类目录。'
|
||||
'text': '支持4种配置方式:1、监控目录,2、监控目录#整理方式,3、监控目录:整理目的目录,4、监控目录:整理目的目录#转移方式。监控目录不指定目的目录时,将按媒体库目录设置整理到媒体库目录,并根据目录的分类设置自动创建一二级分类目录;监控目录指定了目的目录时,会尝试在媒体库目录设定中查找对应路径的目录配置,如存在则以目录设定的分类选项创建子目录,否则直接整理到该目的目录下。建议不设置目的目录,由系统根据目录设定自动分类整理。'
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -945,12 +964,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]:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,10 @@ class Downloader(Enum):
|
||||
self.short_name: str = short_name
|
||||
|
||||
|
||||
# Downloader 映射
|
||||
DownloaderMap = dict((d.id, d) for d in Downloader)
|
||||
|
||||
|
||||
class TaskResult:
|
||||
"""
|
||||
任务执行结果
|
||||
@@ -304,3 +308,20 @@ class TorrentField(Enum):
|
||||
|
||||
# TorrentField 映射
|
||||
TorrentFieldMap = dict((field.name, field) for field in TorrentField)
|
||||
|
||||
|
||||
class DownloaderTransferInfo():
|
||||
"""
|
||||
下载器传输信息
|
||||
"""
|
||||
|
||||
# 下载速度
|
||||
download_speed: Optional[str] = '0.00B/s'
|
||||
# 上传速度
|
||||
upload_speed: Optional[str] = '0.00B/s'
|
||||
# 下载量
|
||||
download_size: Optional[str] = '0.00B'
|
||||
# 上传量
|
||||
upload_size: Optional[str] = '0.00B'
|
||||
# 剩余空间
|
||||
free_space: Optional[str] = '0.00B'
|
||||
|
||||
@@ -25,7 +25,7 @@ class LibraryScraper(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "scraper.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.4"
|
||||
plugin_version = "1.4.1"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -410,14 +410,14 @@ class LibraryScraper(_PluginBase):
|
||||
"uniqueid[@type='TMDB']",
|
||||
"tmdbid"
|
||||
]
|
||||
reader = NfoReader(file_path)
|
||||
for xpath in xpaths:
|
||||
try:
|
||||
try:
|
||||
reader = NfoReader(file_path)
|
||||
for xpath in xpaths:
|
||||
tmdbid = reader.get_element_value(xpath)
|
||||
if tmdbid:
|
||||
return tmdbid
|
||||
except Exception as err:
|
||||
print(str(err))
|
||||
except Exception as err:
|
||||
logger.warn(f"从nfo文件中获取tmdbid失败:{str(err)}")
|
||||
return None
|
||||
|
||||
def stop_service(self):
|
||||
|
||||
@@ -17,9 +17,6 @@ from app.db.models.transferhistory import TransferHistory
|
||||
from app.log import logger
|
||||
from app.modules.emby import Emby
|
||||
from app.modules.jellyfin import Jellyfin
|
||||
from app.modules.qbittorrent import Qbittorrent
|
||||
from app.modules.themoviedb.tmdbv3api import Episode
|
||||
from app.modules.transmission import Transmission
|
||||
from app.plugins import _PluginBase
|
||||
from app.schemas.types import NotificationType, EventType, MediaType, MediaImageType
|
||||
|
||||
@@ -32,7 +29,7 @@ class MediaSyncDel(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "mediasyncdel.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.5"
|
||||
plugin_version = "1.6"
|
||||
# 插件作者
|
||||
plugin_author = "thsrite"
|
||||
# 作者主页
|
||||
@@ -45,7 +42,6 @@ class MediaSyncDel(_PluginBase):
|
||||
auth_level = 1
|
||||
|
||||
# 私有属性
|
||||
episode = None
|
||||
_scheduler: Optional[BackgroundScheduler] = None
|
||||
_enabled = False
|
||||
_sync_type: str = ""
|
||||
@@ -58,16 +54,11 @@ class MediaSyncDel(_PluginBase):
|
||||
_transferchain = None
|
||||
_transferhis = None
|
||||
_downloadhis = None
|
||||
qb = None
|
||||
tr = None
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self._transferchain = TransferChain()
|
||||
self._transferhis = self._transferchain.transferhis
|
||||
self._downloadhis = self._transferchain.downloadhis
|
||||
self.episode = Episode()
|
||||
self.qb = Qbittorrent()
|
||||
self.tr = Transmission()
|
||||
|
||||
# 停止现有任务
|
||||
self.stop_service()
|
||||
@@ -1199,12 +1190,8 @@ class MediaSyncDel(_PluginBase):
|
||||
# 删除转种后任务
|
||||
logger.info(f"删除转种后下载任务:{download} - {download_id}")
|
||||
# 删除转种后下载任务
|
||||
if download == "transmission":
|
||||
self.tr.delete_torrents(delete_file=True,
|
||||
ids=download_id)
|
||||
else:
|
||||
self.qb.delete_torrents(delete_file=True,
|
||||
ids=download_id)
|
||||
self.chain.remove_torrents(hashs=torrent_hash,
|
||||
downloader=download)
|
||||
handle_torrent_hashs.append(download_id)
|
||||
else:
|
||||
# 暂停种子
|
||||
@@ -1219,10 +1206,7 @@ class MediaSyncDel(_PluginBase):
|
||||
|
||||
logger.info(f"暂停转种后下载任务:{download} - {download_id}")
|
||||
# 删除转种后下载任务
|
||||
if download == "transmission":
|
||||
self.tr.stop_torrents(ids=download_id)
|
||||
else:
|
||||
self.qb.stop_torrents(ids=download_id)
|
||||
self.chain.stop_torrents(hashs=download_id, downloader=download)
|
||||
handle_torrent_hashs.append(download_id)
|
||||
else:
|
||||
# 未转种de情况
|
||||
@@ -1237,8 +1221,7 @@ class MediaSyncDel(_PluginBase):
|
||||
handle_torrent_hashs.append(download_id)
|
||||
|
||||
# 处理辅种
|
||||
handle_torrent_hashs = self.__del_seed(download=download,
|
||||
download_id=download_id,
|
||||
handle_torrent_hashs = self.__del_seed(download_id=download_id,
|
||||
delete_flag=delete_flag,
|
||||
handle_torrent_hashs=handle_torrent_hashs)
|
||||
# 处理合集
|
||||
@@ -1284,27 +1267,19 @@ class MediaSyncDel(_PluginBase):
|
||||
|
||||
# 删除合集种子
|
||||
if delete_flag:
|
||||
if str(download_file.downloader) == "transmission":
|
||||
self.tr.delete_torrents(delete_file=True,
|
||||
ids=download_file.download_hash)
|
||||
else:
|
||||
self.qb.delete_torrents(delete_file=True,
|
||||
ids=download_file.download_hash)
|
||||
|
||||
self.chain.remove_torrents(hashs=download_file.download_hash,
|
||||
downloader=download_file.downloader)
|
||||
logger.info(f"删除合集种子 {download_file.downloader} {download_file.download_hash}")
|
||||
else:
|
||||
# 暂停合集种子
|
||||
if str(download_file.downloader) == "transmission":
|
||||
self.tr.stop_torrents(ids=download_file.download_hash)
|
||||
else:
|
||||
self.qb.stop_torrents(ids=download_file.download_hash)
|
||||
self.chain.stop_torrents(hashs=download_file.download_hash,
|
||||
downloader=download_file.downloader)
|
||||
logger.info(f"暂停合集种子 {download_file.downloader} {download_file.download_hash}")
|
||||
# 已处理种子+1
|
||||
handle_torrent_hashs.append(download_file.download_hash)
|
||||
|
||||
# 处理合集辅种
|
||||
handle_torrent_hashs = self.__del_seed(download=download_file.downloader,
|
||||
download_id=download_file.download_hash,
|
||||
handle_torrent_hashs = self.__del_seed(download_id=download_file.download_hash,
|
||||
delete_flag=delete_flag,
|
||||
handle_torrent_hashs=handle_torrent_hashs)
|
||||
except Exception as e:
|
||||
@@ -1313,7 +1288,7 @@ class MediaSyncDel(_PluginBase):
|
||||
|
||||
return handle_torrent_hashs
|
||||
|
||||
def __del_seed(self, download, download_id, delete_flag, handle_torrent_hashs):
|
||||
def __del_seed(self, download_id, delete_flag, handle_torrent_hashs):
|
||||
"""
|
||||
删除辅种
|
||||
"""
|
||||
@@ -1337,30 +1312,18 @@ class MediaSyncDel(_PluginBase):
|
||||
# 删除辅种历史
|
||||
for torrent in torrents:
|
||||
handle_torrent_hashs.append(torrent)
|
||||
if str(download) == "qbittorrent":
|
||||
# 删除辅种
|
||||
if delete_flag:
|
||||
logger.info(f"删除辅种:{downloader} - {torrent}")
|
||||
self.qb.delete_torrents(delete_file=True,
|
||||
ids=torrent)
|
||||
# 暂停辅种
|
||||
else:
|
||||
self.qb.stop_torrents(ids=torrent)
|
||||
logger.info(f"辅种:{downloader} - {torrent} 暂停")
|
||||
# 删除辅种
|
||||
if delete_flag:
|
||||
logger.info(f"删除辅种:{downloader} - {torrent}")
|
||||
self.chain.remove_torrents(hashs=torrent,
|
||||
downloader=downloader)
|
||||
# 暂停辅种
|
||||
else:
|
||||
# 删除辅种
|
||||
if delete_flag:
|
||||
logger.info(f"删除辅种:{downloader} - {torrent}")
|
||||
self.tr.delete_torrents(delete_file=True,
|
||||
ids=torrent)
|
||||
# 暂停辅种
|
||||
else:
|
||||
self.tr.stop_torrents(ids=torrent)
|
||||
logger.info(f"辅种:{downloader} - {torrent} 暂停")
|
||||
self.chain.stop_torrents(hashs=torrent, download=downloader)
|
||||
logger.info(f"辅种:{downloader} - {torrent} 暂停")
|
||||
|
||||
# 处理辅种的辅种
|
||||
handle_torrent_hashs = self.__del_seed(download=downloader,
|
||||
download_id=torrent,
|
||||
handle_torrent_hashs = self.__del_seed(download_id=torrent,
|
||||
delete_flag=delete_flag,
|
||||
handle_torrent_hashs=handle_torrent_hashs)
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ from app.helper.plugin import PluginHelper
|
||||
from app.log import logger
|
||||
from app.plugins import _PluginBase
|
||||
from app.scheduler import Scheduler
|
||||
from app.schemas import NotificationType
|
||||
from app.schemas.types import SystemConfigKey
|
||||
|
||||
|
||||
@@ -23,7 +24,7 @@ class PluginAutoUpgrade(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "PluginAutoUpgrade.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.8"
|
||||
plugin_version = "1.9"
|
||||
# 插件作者
|
||||
plugin_author = "hotlcc"
|
||||
# 作者主页
|
||||
@@ -665,7 +666,7 @@ class PluginAutoUpgrade(_PluginBase):
|
||||
text = self.__build_notify_message(results=results)
|
||||
if not text:
|
||||
return
|
||||
self.post_message(title=f'{self.plugin_name}任务执行结果', text=text)
|
||||
self.post_message(title=f'{self.plugin_name}任务执行结果', text=text, mtype=NotificationType.Plugin)
|
||||
|
||||
@staticmethod
|
||||
def __build_notify_message(results: List[Dict[str, Any]]) -> str:
|
||||
|
||||
@@ -19,6 +19,7 @@ from app.core.metainfo import MetaInfo
|
||||
from app.helper.rss import RssHelper
|
||||
from app.log import logger
|
||||
from app.plugins import _PluginBase
|
||||
from app.schemas import ExistMediaInfo
|
||||
from app.schemas.types import SystemConfigKey, MediaType
|
||||
|
||||
lock = Lock()
|
||||
@@ -32,7 +33,7 @@ class RssSubscribe(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "rss.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.3"
|
||||
plugin_version = "1.4"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -656,51 +657,49 @@ class RssSubscribe(_PluginBase):
|
||||
if not result:
|
||||
logger.info(f"{title} {description} 不匹配过滤规则")
|
||||
continue
|
||||
# 查询缺失的媒体信息
|
||||
exist_flag, no_exists = self.downloadchain.get_no_exists_info(meta=meta, mediainfo=mediainfo)
|
||||
if exist_flag:
|
||||
logger.info(f'{mediainfo.title_year} 媒体库中已存在')
|
||||
# 媒体库已存在的剧集
|
||||
exist_info: Optional[ExistMediaInfo] = self.chain.media_exists(mediainfo=mediainfo)
|
||||
if mediainfo.type == MediaType.TV:
|
||||
if exist_info:
|
||||
exist_season = exist_info.seasons
|
||||
if exist_season:
|
||||
exist_episodes = exist_season.get(meta.begin_season)
|
||||
if exist_episodes and set(meta.episode_list).issubset(set(exist_episodes)):
|
||||
logger.info(f'{mediainfo.title_year} {meta.season_episode} 己存在')
|
||||
continue
|
||||
elif exist_info:
|
||||
# 电影已存在
|
||||
logger.info(f'{mediainfo.title_year} 己存在')
|
||||
continue
|
||||
# 下载或订阅
|
||||
if self._action == "download":
|
||||
# 添加下载
|
||||
result = self.downloadchain.download_single(
|
||||
context=Context(
|
||||
meta_info=meta,
|
||||
media_info=mediainfo,
|
||||
torrent_info=torrentinfo,
|
||||
),
|
||||
save_path=self._save_path,
|
||||
username="RSS订阅"
|
||||
)
|
||||
if not result:
|
||||
logger.error(f'{title} 下载失败')
|
||||
continue
|
||||
else:
|
||||
if self._action == "download":
|
||||
if mediainfo.type == MediaType.TV:
|
||||
if no_exists:
|
||||
exist_info = no_exists.get(mediainfo.tmdb_id)
|
||||
season_info = exist_info.get(meta.begin_season or 1)
|
||||
if not season_info:
|
||||
logger.info(f'{mediainfo.title_year} {meta.season} 己存在')
|
||||
continue
|
||||
if (season_info.episodes
|
||||
and not set(meta.episode_list).issubset(set(season_info.episodes))):
|
||||
logger.info(f'{mediainfo.title_year} {meta.season_episode} 己存在')
|
||||
continue
|
||||
# 添加下载
|
||||
result = self.downloadchain.download_single(
|
||||
context=Context(
|
||||
meta_info=meta,
|
||||
media_info=mediainfo,
|
||||
torrent_info=torrentinfo,
|
||||
),
|
||||
save_path=self._save_path,
|
||||
username="RSS订阅"
|
||||
)
|
||||
if not result:
|
||||
logger.error(f'{title} 下载失败')
|
||||
continue
|
||||
else:
|
||||
# 检查是否在订阅中
|
||||
subflag = self.subscribechain.exists(mediainfo=mediainfo, meta=meta)
|
||||
if subflag:
|
||||
logger.info(f'{mediainfo.title_year} {meta.season} 正在订阅中')
|
||||
continue
|
||||
# 添加订阅
|
||||
self.subscribechain.add(title=mediainfo.title,
|
||||
year=mediainfo.year,
|
||||
mtype=mediainfo.type,
|
||||
tmdbid=mediainfo.tmdb_id,
|
||||
season=meta.begin_season,
|
||||
exist_ok=True,
|
||||
username="RSS订阅")
|
||||
# 检查是否在订阅中
|
||||
subflag = self.subscribechain.exists(mediainfo=mediainfo, meta=meta)
|
||||
if subflag:
|
||||
logger.info(f'{mediainfo.title_year} {meta.season} 正在订阅中')
|
||||
continue
|
||||
# 添加订阅
|
||||
self.subscribechain.add(title=mediainfo.title,
|
||||
year=mediainfo.year,
|
||||
mtype=mediainfo.type,
|
||||
tmdbid=mediainfo.tmdb_id,
|
||||
season=meta.begin_season,
|
||||
exist_ok=True,
|
||||
username="RSS订阅")
|
||||
# 存储历史记录
|
||||
history.append({
|
||||
"title": f"{mediainfo.title} {meta.season}",
|
||||
|
||||
@@ -10,7 +10,7 @@ class TrendingShow(_PluginBase):
|
||||
# 插件描述
|
||||
plugin_desc = "在仪表板中显示流行趋势海报轮播图。"
|
||||
# 插件图标
|
||||
plugin_icon = "Dsphoto_A.png"
|
||||
plugin_icon = "TrendingShow.jpg"
|
||||
# 插件版本
|
||||
plugin_version = "1.0"
|
||||
# 插件作者
|
||||
@@ -183,7 +183,7 @@ class TrendingShow(_PluginBase):
|
||||
'show-arrows': 'hover',
|
||||
'hide-delimiters': True,
|
||||
'cycle': True,
|
||||
'interval': 5000,
|
||||
'interval': 10000,
|
||||
'height': height
|
||||
},
|
||||
'content': [
|
||||
@@ -197,7 +197,7 @@ class TrendingShow(_PluginBase):
|
||||
{
|
||||
'component': 'VCardText',
|
||||
'props': {
|
||||
'class': 'w-full flex flex-col flex-wrap justify-end align-left text-white absolute bottom-0 cursor-pointer pa-4',
|
||||
'class': 'w-full flex flex-col flex-wrap justify-end align-left text-white absolute bottom-0 pa-4',
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
|
||||
@@ -77,7 +77,7 @@ class VCBAnimeMonitor(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "vcbmonitor.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.7.1"
|
||||
plugin_version = "1.8"
|
||||
# 插件作者
|
||||
plugin_author = "pixel@qingwa"
|
||||
# 作者主页
|
||||
@@ -106,6 +106,7 @@ class VCBAnimeMonitor(_PluginBase):
|
||||
_onlyonce = False
|
||||
_cron = None
|
||||
_size = 0
|
||||
_scrape = True
|
||||
# 模式 compatibility/fast
|
||||
_mode = "fast"
|
||||
# 转移方式
|
||||
@@ -142,6 +143,7 @@ class VCBAnimeMonitor(_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")
|
||||
self._switch_ova = config.get("ova")
|
||||
self._high_mode = config.get("high_mode")
|
||||
self._torrents_path = config.get("torrents_path") or ""
|
||||
@@ -286,6 +288,7 @@ class VCBAnimeMonitor(_PluginBase):
|
||||
"interval": self._interval,
|
||||
"cron": self._cron,
|
||||
"size": self._size,
|
||||
"scrape": self._scrape,
|
||||
"ova": self._switch_ova,
|
||||
"high_mode": self._high_mode,
|
||||
"torrents_path": self._torrents_path
|
||||
@@ -508,7 +511,7 @@ class VCBAnimeMonitor(_PluginBase):
|
||||
)
|
||||
|
||||
# 刮削单个文件
|
||||
if settings.SCRAP_METADATA:
|
||||
if self._scrape:
|
||||
self.chain.scrape_metadata(path=transferinfo.target_path,
|
||||
mediainfo=mediainfo,
|
||||
transfer_type=transfer_type)
|
||||
@@ -826,6 +829,22 @@ class VCBAnimeMonitor(_PluginBase):
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12,
|
||||
'md': 4
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VSwitch',
|
||||
'props': {
|
||||
'model': 'scrape',
|
||||
'label': '刮削元数据',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user