mirror of
https://github.com/d0zingcat/MoviePilot-Plugins.git
synced 2026-05-29 15:10:05 +00:00
Merge branch 'main' into qbcommand
This commit is contained in:
@@ -1,966 +0,0 @@
|
||||
from typing import Any, List, Dict, Tuple
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.module import ModuleManager
|
||||
from app.log import logger
|
||||
from app.plugins import _PluginBase
|
||||
|
||||
|
||||
class ConfigCenter(_PluginBase):
|
||||
# 插件名称
|
||||
plugin_name = "配置中心"
|
||||
# 插件描述
|
||||
plugin_desc = "快速调整部分系统设定。"
|
||||
# 插件图标
|
||||
plugin_icon = "setting.png"
|
||||
# 插件版本
|
||||
plugin_version = "3.2"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
author_url = "https://github.com/jxxghp"
|
||||
# 插件配置项ID前缀
|
||||
plugin_config_prefix = "configcenter_"
|
||||
# 加载顺序
|
||||
plugin_order = 0
|
||||
# 可使用的用户级别
|
||||
auth_level = 1
|
||||
|
||||
# 私有属性
|
||||
_enabled = False
|
||||
_params = ""
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
if not config:
|
||||
return
|
||||
|
||||
# 清理插件配置,从而实现默认使用.env中的数据源
|
||||
self._params = config.pop("params", "")
|
||||
if "undefined" in config:
|
||||
del config["undefined"]
|
||||
if "_tabs" in config:
|
||||
del config["_tabs"]
|
||||
self.update_config(config={})
|
||||
|
||||
# 将自定义配置存储到 __ConfigCenter__
|
||||
self.update_config(plugin_id="__ConfigCenter__", config={"params": self._params})
|
||||
|
||||
logger.info(f"正在应用配置中心配置:{config}")
|
||||
|
||||
# 追加自定义配置中的内容
|
||||
params = self.__parse_params(self._params) or {}
|
||||
config.update(**params)
|
||||
|
||||
# 批量更新配置,并获取更新结果
|
||||
update_results = settings.update_settings(config)
|
||||
|
||||
# 遍历更新结果
|
||||
for key, (success, message) in update_results.items():
|
||||
if not success:
|
||||
self.__log_and_notify_error(f"配置项 '{key}' 更新失败:{message}")
|
||||
elif message:
|
||||
self.__log_and_notify_error(f"配置项 '{key}' 更新时出现警告:{message}")
|
||||
|
||||
# 重新加载模块
|
||||
ModuleManager().reload()
|
||||
|
||||
def __log_and_notify_error(self, message):
|
||||
"""
|
||||
记录错误日志并发送系统通知
|
||||
"""
|
||||
logger.error(message)
|
||||
self.systemmessage.put(message, title=self.plugin_name)
|
||||
|
||||
@staticmethod
|
||||
def __parse_params(param_str: str) -> dict:
|
||||
"""
|
||||
解析自定义配置
|
||||
"""
|
||||
if not param_str:
|
||||
return {}
|
||||
result = {}
|
||||
params = param_str.split("\n")
|
||||
for param in params:
|
||||
if not param:
|
||||
continue
|
||||
if str(param).strip().startswith("#"):
|
||||
continue
|
||||
parts = param.split("=", 1)
|
||||
if len(parts) != 2:
|
||||
continue
|
||||
key = parts[0].strip()
|
||||
value = parts[1].strip()
|
||||
if not key:
|
||||
continue
|
||||
if not value:
|
||||
continue
|
||||
result[key] = value
|
||||
return result
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return True
|
||||
|
||||
@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]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
"""
|
||||
default_settings = {}
|
||||
settings_model = self.get_settings_model()
|
||||
keys = self.extract_keys(settings_model)
|
||||
for key in keys:
|
||||
if hasattr(settings, key):
|
||||
default_settings[key] = getattr(settings, key)
|
||||
|
||||
config = self.get_config(plugin_id="__ConfigCenter__") or {}
|
||||
params_str = config.get("params") or ""
|
||||
params = self.__parse_params(params_str) or {}
|
||||
updated_params = {key: getattr(settings, key) for key in params if hasattr(settings, key)}
|
||||
params_str = "\n".join(f"{key}={value}" for key, value in updated_params.items())
|
||||
default_settings["params"] = params_str
|
||||
|
||||
return [
|
||||
{
|
||||
"component": "VForm",
|
||||
"content": settings_model
|
||||
}
|
||||
], default_settings
|
||||
|
||||
def extract_keys(self, components: List[dict]) -> List[str]:
|
||||
"""
|
||||
递归提取所有组件中的model键
|
||||
"""
|
||||
models = []
|
||||
for component in components:
|
||||
# 检查当前组件的props中是否有model
|
||||
props = component.get("props", {})
|
||||
model = props.get("model")
|
||||
if model:
|
||||
models.append(model)
|
||||
|
||||
# 如果当前组件有嵌套的content,递归提取
|
||||
nested_content = component.get("content", [])
|
||||
if isinstance(nested_content, list):
|
||||
models.extend(self.extract_keys(nested_content))
|
||||
elif isinstance(nested_content, dict):
|
||||
models.extend(self.extract_keys([nested_content]))
|
||||
|
||||
return models
|
||||
|
||||
@staticmethod
|
||||
def get_settings_model() -> List[dict]:
|
||||
"""
|
||||
获取配置项模型
|
||||
"""
|
||||
return [
|
||||
{
|
||||
"component": "VRow",
|
||||
"content": [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VAlert",
|
||||
"props": {
|
||||
"type": "warning",
|
||||
"variant": "tonal",
|
||||
"text": "注意:部分配置项的更改可能需要重启服务才能生效,为确保配置一致性,已在环境变量中的相关配置项,请手动更新"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VTabs",
|
||||
"props": {
|
||||
"model": "_tabs",
|
||||
"height": 72,
|
||||
"fixed-tabs": True,
|
||||
"style": {
|
||||
"margin-top": "8px",
|
||||
"margin-bottom": "10px",
|
||||
}
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTab",
|
||||
"props": {
|
||||
"value": "basic_tab",
|
||||
"style": {
|
||||
"padding-top": "10px",
|
||||
"padding-bottom": "10px",
|
||||
"font-size": "16px"
|
||||
},
|
||||
},
|
||||
"text": "基础设置"
|
||||
},
|
||||
{
|
||||
"component": "VTab",
|
||||
"props": {
|
||||
"value": "network_tab",
|
||||
"style": {
|
||||
"padding-top": "10px",
|
||||
"padding-bottom": "10px",
|
||||
"font-size": "16px"
|
||||
},
|
||||
},
|
||||
"text": "网络设置"
|
||||
},
|
||||
{
|
||||
"component": "VTab",
|
||||
"props": {
|
||||
"value": "media_and_download_tab",
|
||||
"style": {
|
||||
"padding-top": "10px",
|
||||
"padding-bottom": "10px",
|
||||
"font-size": "16px"
|
||||
},
|
||||
},
|
||||
"text": "媒体与下载"
|
||||
},
|
||||
{
|
||||
"component": "VTab",
|
||||
"props": {
|
||||
"value": "search_and_transfer_tab",
|
||||
"style": {
|
||||
"padding-top": "10px",
|
||||
"padding-bottom": "10px",
|
||||
"font-size": "16px"
|
||||
},
|
||||
},
|
||||
"text": "搜索与整理"
|
||||
},
|
||||
{
|
||||
"component": "VTab",
|
||||
"props": {
|
||||
"value": "params_tab",
|
||||
"style": {
|
||||
"padding-top": "10px",
|
||||
"padding-bottom": "10px",
|
||||
"font-size": "16px"
|
||||
},
|
||||
},
|
||||
"text": "自定义配置"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VWindow",
|
||||
"props": {
|
||||
"model": "_tabs",
|
||||
},
|
||||
"content": [
|
||||
# 备份分类块
|
||||
# {
|
||||
# "component": "VWindowItem",
|
||||
# "props": {
|
||||
# "value": "client_setting",
|
||||
# "style": {
|
||||
# "padding-top": "20px",
|
||||
# "padding-bottom": "20px"
|
||||
# },
|
||||
# },
|
||||
# "content": [
|
||||
# {
|
||||
# "component": "VRow",
|
||||
# "props": {
|
||||
# "align": "center"
|
||||
# },
|
||||
# "content": []
|
||||
# }
|
||||
# ]
|
||||
# },
|
||||
# 基础
|
||||
{
|
||||
"component": "VWindowItem",
|
||||
"props": {
|
||||
"value": "basic_tab",
|
||||
"style": {
|
||||
"padding-top": "20px",
|
||||
"padding-bottom": "20px"
|
||||
},
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VRow",
|
||||
"props": {
|
||||
"align": "center"
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VSwitch",
|
||||
"props": {
|
||||
"model": "AUXILIARY_AUTH_ENABLE",
|
||||
"label": "启用用户辅助认证",
|
||||
"hint": "启用后允许通过外部服务进行认证、单点登录以及自动创建用户",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VSwitch",
|
||||
"props": {
|
||||
"model": "GLOBAL_IMAGE_CACHE",
|
||||
"label": "全局图片缓存",
|
||||
"hint": "是否启用全局图片缓存,将媒体图片缓存到本地",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6.
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VSelect",
|
||||
"props": {
|
||||
"model": "WALLPAPER",
|
||||
"label": "登录首页电影海报",
|
||||
"items": [
|
||||
{
|
||||
"title": "TheMovieDb电影海报",
|
||||
"value": "tmdb"
|
||||
},
|
||||
{
|
||||
"title": "Bing每日壁纸",
|
||||
"value": "bing"
|
||||
}
|
||||
],
|
||||
"hint": "登录首页电影海报",
|
||||
"persistent-hint": True,
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "API_TOKEN",
|
||||
"label": "API密钥",
|
||||
"hint": "用于Jellyseerr/Overseerr、媒体服务器Webhook等配置以及部分支持API_TOKEN的API请求",
|
||||
"persistent-hint": True,
|
||||
"clearable": True,
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextarea",
|
||||
"props": {
|
||||
"model": "PLUGIN_MARKET",
|
||||
"label": "插件市场",
|
||||
"hint": "插件市场仓库地址,多个地址使用逗号分隔,确保每个地址以/结尾",
|
||||
"persistent-hint": True,
|
||||
"clearable": True,
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
# 网络
|
||||
{
|
||||
"component": "VWindowItem",
|
||||
"props": {
|
||||
"value": "network_tab",
|
||||
"style": {
|
||||
"padding-top": "20px",
|
||||
"padding-bottom": "20px"
|
||||
},
|
||||
},
|
||||
"content": [
|
||||
# DOH
|
||||
{
|
||||
"component": "VRow",
|
||||
"props": {
|
||||
"align": "center",
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VSwitch",
|
||||
"props": {
|
||||
"model": "DOH_ENABLE",
|
||||
"label": "启用DNS over HTTPS",
|
||||
"hint": "启用后对特定域名使用DOH解析以避免DNS污染",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VAlert",
|
||||
"props": {
|
||||
"type": "info",
|
||||
"variant": "tonal",
|
||||
"style": "white-space: pre-line;",
|
||||
"text": "如果已经配置好 'PROXY_HOST' ,建议关闭 'DOH' ",
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "DOH_DOMAINS",
|
||||
"label": "DOH解析的域名",
|
||||
"hint": "DOH解析的域名列表,多个域名使用逗号分隔",
|
||||
"persistent-hint": True,
|
||||
"clearable": True,
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "DOH_RESOLVERS",
|
||||
"label": "DOH解析服务器",
|
||||
"hint": "DOH解析服务器列表,多个服务器使用逗号分隔",
|
||||
"persistent-hint": True,
|
||||
"clearable": True,
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "GITHUB_TOKEN",
|
||||
"label": "GitHub Token",
|
||||
"placeholder": "格式: ghp_**** 或 github_pat_****",
|
||||
"hint": "GitHub Token,提高请求API限流阈值",
|
||||
"persistent-hint": True,
|
||||
"clearable": True,
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "OCR_HOST",
|
||||
"label": "验证码识别服务器",
|
||||
"hint": "验证码识别服务器地址",
|
||||
"persistent-hint": True,
|
||||
"clearable": True,
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "GITHUB_PROXY",
|
||||
"label": "GitHub加速服务器",
|
||||
"placeholder": "格式: https://mirror.ghproxy.com/",
|
||||
"hint": "留空则不使用GitHub加速服务器,(注意末尾需要带/)",
|
||||
"persistent-hint": True,
|
||||
"clearable": True,
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "PIP_PROXY",
|
||||
"label": "PIP加速服务器",
|
||||
"hint": "留空则不使用PIP加速服务器",
|
||||
"placeholder": "格式: https://pypi.tuna.tsinghua.edu.cn/simple",
|
||||
"persistent-hint": True,
|
||||
"clearable": True,
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
# Tmdb相关
|
||||
{
|
||||
"component": "VRow",
|
||||
"props": {
|
||||
"align": "center"
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "TMDB_API_DOMAIN",
|
||||
"label": "TMDB API地址",
|
||||
"hint": "访问正常时无需更改;无法访问时替换为其他中转服务地址,确保连通性",
|
||||
"persistent-hint": True,
|
||||
"clearable": True,
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "TMDB_IMAGE_DOMAIN",
|
||||
"label": "TheMovieDb图片服务器",
|
||||
"placeholder": "例如:static-mdb.v.geilijiasu.com",
|
||||
"hint": "访问正常时无需更改;无法访问时可替换为其他可用地址,确保连通性",
|
||||
"persistent-hint": True,
|
||||
"clearable": True,
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
# 媒体与下载
|
||||
{
|
||||
"component": "VWindowItem",
|
||||
"props": {
|
||||
"value": "media_and_download_tab",
|
||||
"style": {
|
||||
"padding-top": "20px",
|
||||
"padding-bottom": "20px"
|
||||
},
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VRow",
|
||||
"props": {
|
||||
"align": "center",
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 9,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VSwitch",
|
||||
"props": {
|
||||
"model": "DOWNLOAD_SUBTITLE",
|
||||
"label": "自动下载站点字幕",
|
||||
"hint": "自动下载站点字幕(如有)",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 3,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "MEDIASERVER_SYNC_INTERVAL",
|
||||
"label": "媒体服务器同步间隔",
|
||||
"hint": "媒体服务器同步间隔",
|
||||
"persistent-hint": True,
|
||||
"prefix": "每",
|
||||
"suffix": "小时",
|
||||
"type": "number",
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 12,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "AUTO_DOWNLOAD_USER",
|
||||
"label": "交互搜索自动下载用户ID",
|
||||
"hint": "使用,分割,设置为 all 代表所有用户自动择优下载,未设置需要用户手动选择资源或者回复`0`才自动择优下载",
|
||||
"persistent-hint": True,
|
||||
"clearable": True,
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
# 搜索与整理
|
||||
{
|
||||
"component": "VWindowItem",
|
||||
"props": {
|
||||
"value": "search_and_transfer_tab",
|
||||
"style": {
|
||||
"padding-top": "20px",
|
||||
"padding-bottom": "20px"
|
||||
},
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VRow",
|
||||
"props": {
|
||||
"align": "center"
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VSwitch",
|
||||
"props": {
|
||||
"model": "SEARCH_MULTIPLE_NAME",
|
||||
"label": "资源搜索整合多名称结果",
|
||||
"hint": "搜索多个名称时是整合多名称的结果",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 3,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VSwitch",
|
||||
"props": {
|
||||
"model": "FANART_ENABLE",
|
||||
"label": "使用Fanart图片数据源",
|
||||
"hint": "启用Fanart图片数据源",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 3,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "META_CACHE_EXPIRE",
|
||||
"label": "元数据缓存时间",
|
||||
"hint": "0或负值时,使用系统默认缓存时间",
|
||||
"persistent-hint": True,
|
||||
"prefix": "每",
|
||||
"suffix": "小时",
|
||||
"type": "number",
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VRow",
|
||||
"props": {
|
||||
"align": "center"
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VSelect",
|
||||
"props": {
|
||||
"model": "RECOGNIZE_SOURCE",
|
||||
"label": "媒体信息识别来源",
|
||||
"items": [
|
||||
{
|
||||
"title": "TheMovieDb",
|
||||
"value": "themoviedb"
|
||||
},
|
||||
{
|
||||
"title": "豆瓣",
|
||||
"value": "douban"
|
||||
}
|
||||
],
|
||||
"hint": "媒体信息识别来源",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 6
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VSelect",
|
||||
"props": {
|
||||
"model": "SCRAP_SOURCE",
|
||||
"label": "刮削元数据及图片使用的数据源",
|
||||
"items": [
|
||||
{
|
||||
"title": "TheMovieDb",
|
||||
"value": "themoviedb"
|
||||
},
|
||||
{
|
||||
"title": "豆瓣",
|
||||
"value": "douban"
|
||||
}
|
||||
],
|
||||
"hint": "刮削元数据及图片使用的数据源",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextarea",
|
||||
"props": {
|
||||
"model": "MOVIE_RENAME_FORMAT",
|
||||
"label": "电影重命名格式",
|
||||
"hint": "电影重命名格式,使用Jinja2语法,每行一个配置项,参考:https://jinja.palletsprojects.com/en/3.0.x/templates/",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextarea",
|
||||
"props": {
|
||||
"model": "TV_RENAME_FORMAT",
|
||||
"label": "电视剧重命名格式",
|
||||
"hint": "电视剧重命名格式,使用Jinja2语法",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"md": 12,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VAlert",
|
||||
"props": {
|
||||
"type": "warning",
|
||||
"variant": "tonal",
|
||||
"style": "white-space: pre-line;",
|
||||
"text": "Jinja2语法参考:"
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "a",
|
||||
"props": {
|
||||
"href": "https://jinja.palletsprojects.com/en/3.0.x/templates/",
|
||||
"target": "_blank"
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "u",
|
||||
"text": "https://jinja.palletsprojects.com/en/3.0.x/templates/"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
# 自定义
|
||||
{
|
||||
"component": "VWindowItem",
|
||||
"props": {
|
||||
"value": "params_tab",
|
||||
"style": {
|
||||
"padding-top": "20px",
|
||||
"padding-bottom": "20px"
|
||||
},
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VRow",
|
||||
"props": {
|
||||
"align": "center",
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextarea",
|
||||
"props": {
|
||||
"model": "params",
|
||||
"label": "自定义配置",
|
||||
"hint": "自定义配置,每行一个配置项,格式:配置项=值",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
def get_page(self) -> List[dict]:
|
||||
pass
|
||||
|
||||
def stop_service(self):
|
||||
"""
|
||||
退出插件
|
||||
"""
|
||||
pass
|
||||
336
plugins.v2/historytov2/__init__.py
Normal file
336
plugins.v2/historytov2/__init__.py
Normal file
@@ -0,0 +1,336 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any, List, Dict, Tuple, Optional
|
||||
|
||||
from app.db import SessionFactory
|
||||
from app.db.models import TransferHistory
|
||||
from app.log import logger
|
||||
from app.plugins import _PluginBase
|
||||
from app.utils.http import RequestUtils
|
||||
|
||||
|
||||
class HistoryToV2(_PluginBase):
|
||||
# 插件名称
|
||||
plugin_name = "历史记录迁移"
|
||||
# 插件描述
|
||||
plugin_desc = "将MoviePilot V1版本的整理历史记录迁移至V2版本。"
|
||||
# 插件图标
|
||||
plugin_icon = "Moviepilot_A.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.1"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
author_url = "https://github.com/jxxghp"
|
||||
# 插件配置项ID前缀
|
||||
plugin_config_prefix = "historytov2_"
|
||||
# 加载顺序
|
||||
plugin_order = 99
|
||||
# 可使用的用户级别
|
||||
auth_level = 1
|
||||
|
||||
# 私有属性
|
||||
historyoper = None
|
||||
_enabled = False
|
||||
_host = None
|
||||
_username = None
|
||||
_password = None
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
self._host = config.get("host")
|
||||
self._username = config.get("username")
|
||||
self._password = config.get("password")
|
||||
|
||||
if self._enabled:
|
||||
if self._host and self._username and self._password:
|
||||
# 关闭开关
|
||||
self.__close_config()
|
||||
# 登录MP获取token
|
||||
token = self.__login_mp()
|
||||
if token:
|
||||
# 当前页码
|
||||
page = 1
|
||||
# 总记录数
|
||||
total = 0
|
||||
# 获取历史记录
|
||||
history = self.__get_history(token)
|
||||
while history:
|
||||
# 处理历史记录
|
||||
logger.info(f"开始处理第 {page} 页历史记录 ...")
|
||||
self.__insert_history(history)
|
||||
# 处理成功一批
|
||||
total += len(history)
|
||||
logger.info(f"第 {page} 页处理完成,共处理 {total} 条记录")
|
||||
# 获取下一页历史记录
|
||||
page += 1
|
||||
history = self.__get_history(token, page=page)
|
||||
# 处理完成
|
||||
logger.info(f"历史记录迁移完成,共迁移 {total} 条记录!")
|
||||
self.systemmessage.put(f"历史记录迁移完成,共迁移 {total} 条记录!", title="MoviePilot历史记录迁移")
|
||||
else:
|
||||
self.systemmessage.put(f"配置不完整,服务启动失败!", title="MoviePilot历史记录迁移")
|
||||
# 关闭开关
|
||||
self.__close_config()
|
||||
|
||||
def __close_config(self):
|
||||
"""
|
||||
关闭开关
|
||||
"""
|
||||
self._enabled = False
|
||||
self.update_config({
|
||||
"enabled": self._enabled,
|
||||
"host": self._host,
|
||||
"username": self._username,
|
||||
"password": self._password
|
||||
})
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled
|
||||
|
||||
@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]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
"""
|
||||
return [
|
||||
{
|
||||
'component': 'VForm',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12,
|
||||
'md': 4
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VSwitch',
|
||||
'props': {
|
||||
'model': 'enabled',
|
||||
'label': '启用插件',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12,
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VTextField',
|
||||
'props': {
|
||||
'model': 'host',
|
||||
'label': 'MoviePilot V1地址',
|
||||
'placeholder': 'http://localhost:3000',
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12,
|
||||
'md': 6
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VTextField',
|
||||
'props': {
|
||||
'model': 'username',
|
||||
'label': '登录用户名',
|
||||
'placeholder': 'admin'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12,
|
||||
'md': 6
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VTextField',
|
||||
'props': {
|
||||
'model': 'password',
|
||||
'label': '登录密码',
|
||||
'type': 'password',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12,
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VAlert',
|
||||
'props': {
|
||||
'type': 'info',
|
||||
'variant': 'tonal',
|
||||
'text': 'MoviePilot V1 需要是启动状态且能正常访问,V1版本和V2版本目录映射需要保持一致,迁移时间可能较长,完成后会收到系统通知。'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
], {
|
||||
"enabled": False,
|
||||
"host": None,
|
||||
"username": None,
|
||||
"password": None
|
||||
}
|
||||
|
||||
def get_page(self) -> List[dict]:
|
||||
pass
|
||||
|
||||
def stop_service(self):
|
||||
"""
|
||||
退出插件
|
||||
"""
|
||||
pass
|
||||
|
||||
def __login_mp(self) -> Optional[str]:
|
||||
"""
|
||||
登录MP获取token
|
||||
"""
|
||||
if not self._host or not self._username or not self._password:
|
||||
return None
|
||||
url = f"{self._host}/api/v1/login/access-token"
|
||||
headers = {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
}
|
||||
data = {
|
||||
"username": self._username,
|
||||
"password": self._password
|
||||
}
|
||||
logger.info(f"登录MoviePilot: {url}")
|
||||
# 发送POST请求
|
||||
response = RequestUtils(headers=headers).post_res(url, data=data)
|
||||
# 检查响应状态
|
||||
if response.status_code == 200:
|
||||
# 成功获取token
|
||||
token_data = response.json()
|
||||
logger.info(f"登录MoviePilot成功,获取token:{token_data['access_token']}", )
|
||||
return token_data["access_token"]
|
||||
else:
|
||||
# 处理失败响应
|
||||
logger.warn(f"登录MoviePilot失败: {response.json()}")
|
||||
self.systemmessage.put(f"登录MoviePilot失败,无法同步历史记录!", title="MoviePilot历史记录迁移")
|
||||
return None
|
||||
|
||||
def __get_history(self, token: str, page: int = 1, count: int = 30) -> Optional[List[dict]]:
|
||||
"""
|
||||
获取历史记录
|
||||
"""
|
||||
if not token:
|
||||
return []
|
||||
url = f"{self._host}/api/v1/history/transfer"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}"
|
||||
}
|
||||
params = {
|
||||
"page": page,
|
||||
"count": count
|
||||
}
|
||||
logger.info(f"查询转移历史记录: {url},params: {params}")
|
||||
# 发送GET请求
|
||||
response = RequestUtils(headers=headers).get_res(url, params=params)
|
||||
# 检查响应状态
|
||||
if response.status_code == 200:
|
||||
# 返回数据
|
||||
response_data = response.json()
|
||||
data = response_data.get("data")
|
||||
logger.info(f"查询转移历史记录成功,共 {len(data.get('list'))} 条记录")
|
||||
return data.get("list")
|
||||
else:
|
||||
# 处理失败响应
|
||||
logger.warn("查询转移历史记录失败:", response.json())
|
||||
self.systemmessage.put(f"查询转移历史记录失败,无法同步历史记录!", title="MoviePilot历史记录迁移")
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
def __insert_history(history: List[dict]):
|
||||
"""
|
||||
插入历史记录
|
||||
"""
|
||||
if not history:
|
||||
return
|
||||
with SessionFactory() as db:
|
||||
for item in history:
|
||||
if item.get("src"):
|
||||
transferhistory = TransferHistory.get_by_src(db, item.get("src"))
|
||||
if transferhistory:
|
||||
transferhistory.delete(db, transferhistory.id)
|
||||
try:
|
||||
TransferHistory(
|
||||
src=item.get("src"),
|
||||
src_storage="local",
|
||||
src_fileitem={
|
||||
"storage": "local",
|
||||
"type": "file",
|
||||
"path": item.get("src"),
|
||||
"name": Path(item.get("src")).name,
|
||||
"basename": Path(item.get("src")).stem,
|
||||
"extension": Path(item.get("src")).suffix[1:],
|
||||
},
|
||||
dest=item.get("dest"),
|
||||
dest_storage="local",
|
||||
dest_fileitem={
|
||||
"storage": "local",
|
||||
"type": "file",
|
||||
"path": item.get("dest"),
|
||||
"name": Path(item.get("dest")).name,
|
||||
"basename": Path(item.get("dest")).stem,
|
||||
"extension": Path(item.get("dest")).suffix[1:],
|
||||
},
|
||||
mode=item.get("mode"),
|
||||
type=item.get("type"),
|
||||
category=item.get("category"),
|
||||
title=item.get("title"),
|
||||
year=item.get("year"),
|
||||
tmdbid=item.get("tmdbid"),
|
||||
imdbid=item.get("imdbid"),
|
||||
tvdbid=item.get("tvdbid"),
|
||||
doubanid=item.get("doubanid"),
|
||||
seasons=item.get("seasons"),
|
||||
episodes=item.get("episodes"),
|
||||
image=item.get("image"),
|
||||
download_hash=item.get("download_hash"),
|
||||
status=item.get("status"),
|
||||
files=json.loads(item.get("files")) if item.get("files") else [],
|
||||
date=item.get("date"),
|
||||
errmsg=item.get("errmsg")
|
||||
).create(db)
|
||||
except Exception as e:
|
||||
logger.error(f"插入历史记录失败:{e}")
|
||||
continue
|
||||
@@ -33,7 +33,7 @@ class IYUUAutoSeed(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "IYUU.png"
|
||||
# 插件版本
|
||||
plugin_version = "2.0.1"
|
||||
plugin_version = "2.1"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
|
||||
@@ -11,7 +11,7 @@ class IyuuHelper(object):
|
||||
适配新版本IYUU开发版
|
||||
"""
|
||||
_version = "8.2.0"
|
||||
_api_base = "https://dev.iyuu.cn"
|
||||
_api_base = "https://2025.iyuu.cn"
|
||||
_sites = {}
|
||||
_token = None
|
||||
_sid_sha1 = None
|
||||
|
||||
300
plugins.v2/synccookiecloud/__init__.py
Normal file
300
plugins.v2/synccookiecloud/__init__.py
Normal file
@@ -0,0 +1,300 @@
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
from hashlib import md5
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import pytz
|
||||
|
||||
from app.core.config import settings
|
||||
from app.db.site_oper import SiteOper
|
||||
from app.plugins import _PluginBase
|
||||
from typing import Any, List, Dict, Tuple, Optional
|
||||
from app.log import logger
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
|
||||
from app.utils.crypto import CryptoJsUtils
|
||||
|
||||
|
||||
class SyncCookieCloud(_PluginBase):
|
||||
# 插件名称
|
||||
plugin_name = "同步CookieCloud"
|
||||
# 插件描述
|
||||
plugin_desc = "同步MoviePilot站点Cookie到本地CookieCloud。"
|
||||
# 插件图标
|
||||
plugin_icon = "Cookiecloud_A.png"
|
||||
# 插件版本
|
||||
plugin_version = "2.1"
|
||||
# 插件作者
|
||||
plugin_author = "thsrite"
|
||||
# 作者主页
|
||||
author_url = "https://github.com/thsrite"
|
||||
# 插件配置项ID前缀
|
||||
plugin_config_prefix = "synccookiecloud_"
|
||||
# 加载顺序
|
||||
plugin_order = 28
|
||||
# 可使用的用户级别
|
||||
auth_level = 1
|
||||
|
||||
# 私有属性
|
||||
_enabled: bool = False
|
||||
_onlyonce: bool = False
|
||||
_cron: str = ""
|
||||
siteoper = None
|
||||
_scheduler: Optional[BackgroundScheduler] = None
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self.siteoper = SiteOper()
|
||||
|
||||
# 停止现有任务
|
||||
self.stop_service()
|
||||
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
self._onlyonce = config.get("onlyonce")
|
||||
self._cron = config.get("cron")
|
||||
|
||||
if self._enabled or self._onlyonce:
|
||||
# 定时服务
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
|
||||
# 立即运行一次
|
||||
if self._onlyonce:
|
||||
logger.info(f"同步CookieCloud服务启动,立即运行一次")
|
||||
self._scheduler.add_job(self.__sync_to_cookiecloud, 'date',
|
||||
run_date=datetime.now(
|
||||
tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||
name="同步CookieCloud")
|
||||
# 关闭一次性开关
|
||||
self._onlyonce = False
|
||||
|
||||
# 保存配置
|
||||
self.__update_config()
|
||||
|
||||
# 周期运行
|
||||
if self._cron:
|
||||
try:
|
||||
self._scheduler.add_job(func=self.__sync_to_cookiecloud,
|
||||
trigger=CronTrigger.from_crontab(self._cron),
|
||||
name="同步CookieCloud")
|
||||
except Exception as err:
|
||||
logger.error(f"定时任务配置错误:{err}")
|
||||
# 推送实时消息
|
||||
self.systemmessage.put(f"执行周期配置错误:{err}")
|
||||
|
||||
# 启动任务
|
||||
if self._scheduler.get_jobs():
|
||||
self._scheduler.print_jobs()
|
||||
self._scheduler.start()
|
||||
|
||||
def __sync_to_cookiecloud(self):
|
||||
"""
|
||||
同步站点cookie到cookiecloud
|
||||
"""
|
||||
# 获取所有站点
|
||||
sites = self.siteoper.list_order_by_pri()
|
||||
if not sites:
|
||||
return
|
||||
|
||||
if not settings.COOKIECLOUD_ENABLE_LOCAL:
|
||||
logger.error('本地CookieCloud服务器未启用')
|
||||
return
|
||||
|
||||
cookies = {}
|
||||
for site in sites:
|
||||
domain = urlparse(site.url).netloc
|
||||
cookie = site.cookie
|
||||
|
||||
if not cookie:
|
||||
logger.error(f"站点 {domain} 无cookie,跳过处理...")
|
||||
continue
|
||||
|
||||
# 解析cookie
|
||||
site_cookies = []
|
||||
for ck in cookie.split(";"):
|
||||
kv = ck.split("=")
|
||||
if len(kv) < 2:
|
||||
continue
|
||||
site_cookies.append({
|
||||
"domain": domain,
|
||||
"name": ck.split("=")[0],
|
||||
"value": ck.split("=")[1]
|
||||
})
|
||||
# 存储cookies
|
||||
cookies[domain] = site_cookies
|
||||
if cookies:
|
||||
crypt_key = self._get_crypt_key()
|
||||
try:
|
||||
cookies = {'cookie_data': cookies}
|
||||
encrypted_data = CryptoJsUtils.encrypt(json.dumps(cookies).encode('utf-8'), crypt_key).decode('utf-8')
|
||||
except Exception as e:
|
||||
logger.error(f"CookieCloud加密失败,{e}")
|
||||
return
|
||||
ck = {'encrypted': encrypted_data}
|
||||
cookie_path = settings.COOKIE_PATH / f"{settings.COOKIECLOUD_KEY}.json"
|
||||
cookie_path.write_bytes(json.dumps(ck).encode('utf-8'))
|
||||
logger.info(f"同步站点cookie到本地CookieCloud成功")
|
||||
else:
|
||||
logger.error(f"同步站点cookie到本地CookieCloud失败,未获取到站点cookie")
|
||||
|
||||
def __decrypted(self, encrypt_data: dict):
|
||||
"""
|
||||
获取并解密本地CookieCloud数据
|
||||
"""
|
||||
encrypted = encrypt_data.get("encrypted")
|
||||
if not encrypted:
|
||||
return {}, "未获取到cookie密文"
|
||||
else:
|
||||
crypt_key = self._get_crypt_key()
|
||||
try:
|
||||
decrypted_data = CryptoJsUtils.decrypt(encrypted, crypt_key).decode('utf-8')
|
||||
result = json.loads(decrypted_data)
|
||||
except Exception as e:
|
||||
return {}, "cookie解密失败:" + str(e)
|
||||
|
||||
if not result:
|
||||
return {}, "cookie解密为空"
|
||||
|
||||
if result.get("cookie_data"):
|
||||
contents = result.get("cookie_data")
|
||||
else:
|
||||
contents = result
|
||||
return contents
|
||||
|
||||
@staticmethod
|
||||
def _get_crypt_key() -> bytes:
|
||||
"""
|
||||
使用UUID和密码生成CookieCloud的加解密密钥
|
||||
"""
|
||||
md5_generator = md5()
|
||||
md5_generator.update(
|
||||
(str(settings.COOKIECLOUD_KEY).strip() + '-' + str(settings.COOKIECLOUD_PASSWORD).strip()).encode('utf-8'))
|
||||
return (md5_generator.hexdigest()[:16]).encode('utf-8')
|
||||
|
||||
def __update_config(self):
|
||||
self.update_config({
|
||||
"enabled": self._enabled,
|
||||
"onlyonce": self._onlyonce,
|
||||
"cron": self._cron
|
||||
})
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled
|
||||
|
||||
@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]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
"""
|
||||
return [
|
||||
{
|
||||
'component': 'VForm',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12,
|
||||
'md': 6
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VSwitch',
|
||||
'props': {
|
||||
'model': 'enabled',
|
||||
'label': '启用插件',
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12,
|
||||
'md': 6
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VSwitch',
|
||||
'props': {
|
||||
'model': 'onlyonce',
|
||||
'label': '立即运行一次',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12,
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VTextField',
|
||||
'props': {
|
||||
'model': 'cron',
|
||||
'label': '执行周期',
|
||||
'placeholder': '5位cron表达式,留空自动'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12,
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VAlert',
|
||||
'props': {
|
||||
'type': 'info',
|
||||
'variant': 'tonal',
|
||||
'text': '需要MoviePilot设定-站点启用本地CookieCloud服务器。'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
], {
|
||||
"enabled": False,
|
||||
"onlyonce": False,
|
||||
"cron": "5 1 * * *",
|
||||
}
|
||||
|
||||
def get_page(self) -> List[dict]:
|
||||
pass
|
||||
|
||||
def stop_service(self):
|
||||
"""
|
||||
退出插件
|
||||
"""
|
||||
try:
|
||||
if self._scheduler:
|
||||
self._scheduler.remove_all_jobs()
|
||||
if self._scheduler.running:
|
||||
self._scheduler.shutdown()
|
||||
self._scheduler = None
|
||||
except Exception as e:
|
||||
logger.error("退出插件失败:%s" % str(e))
|
||||
@@ -26,7 +26,7 @@ class TorrentRemover(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "delete.jpg"
|
||||
# 插件版本
|
||||
plugin_version = "2.1"
|
||||
plugin_version = "2.1.1"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp"
|
||||
# 作者主页
|
||||
@@ -814,7 +814,7 @@ class TorrentRemover(_PluginBase):
|
||||
name = remove_torrent.get("name")
|
||||
size = remove_torrent.get("size")
|
||||
for torrent in torrents:
|
||||
if downloader == "qbittorrent":
|
||||
if downloader_config.type == "qbittorrent":
|
||||
plus_id = torrent.hash
|
||||
plus_name = torrent.name
|
||||
plus_size = torrent.size
|
||||
|
||||
Reference in New Issue
Block a user