mirror of
https://github.com/d0zingcat/MoviePilot-Plugins.git
synced 2026-05-13 23:16:47 +00:00
feat(ConfigCenter): ensure runtime settings sync with env
This commit is contained in:
@@ -1,8 +1,5 @@
|
||||
import copy
|
||||
from typing import Any, List, Dict, Tuple
|
||||
|
||||
from dotenv import set_key
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.module import ModuleManager
|
||||
from app.log import logger
|
||||
@@ -32,7 +29,6 @@ class ConfigCenter(_PluginBase):
|
||||
# 私有属性
|
||||
_enabled = False
|
||||
_params = ""
|
||||
_writeenv = False
|
||||
settings_attributes = [
|
||||
"GITHUB_TOKEN", "API_TOKEN", "TMDB_API_DOMAIN", "TMDB_IMAGE_DOMAIN", "WALLPAPER",
|
||||
"RECOGNIZE_SOURCE", "SCRAP_FOLLOW_TMDB", "AUTO_DOWNLOAD_USER",
|
||||
@@ -46,62 +42,40 @@ class ConfigCenter(_PluginBase):
|
||||
if not config:
|
||||
return
|
||||
|
||||
self._enabled = config.get("enabled")
|
||||
self._writeenv = config.get("writeenv")
|
||||
if not self._enabled:
|
||||
return
|
||||
# 清理插件配置,从而实现默认使用.env中的数据源
|
||||
self._params = config.pop("params", "")
|
||||
if "undefined" in config:
|
||||
del config["undefined"]
|
||||
self.update_config(config={})
|
||||
|
||||
# 将自定义配置存储到 __ConfigCenter__
|
||||
self.update_config(plugin_id="__ConfigCenter__", config={"params": self._params})
|
||||
|
||||
logger.info(f"正在应用配置中心配置:{config}")
|
||||
for attribute in self.settings_attributes:
|
||||
setattr(settings, attribute, config.get(attribute) or getattr(settings, attribute))
|
||||
# 自定义配置,以换行分隔
|
||||
self._params = config.get("params") or ""
|
||||
for key, value in self.__parse_params(self._params).items():
|
||||
if hasattr(settings, key):
|
||||
setattr(settings, key, str(value))
|
||||
|
||||
# 追加自定义配置中的内容
|
||||
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().stop()
|
||||
ModuleManager().load_modules()
|
||||
ModuleManager().reload()
|
||||
|
||||
# 如果写入app.env文件,则关闭插件开关
|
||||
if self._writeenv:
|
||||
# 写入env文件
|
||||
self.update_env(config)
|
||||
# 自动关闭插件
|
||||
self._enabled = False
|
||||
logger.info("配置中心设置已写入app.env文件,插件关闭...")
|
||||
# 保存配置
|
||||
config.update({"enabled": False})
|
||||
self.update_config(config)
|
||||
|
||||
def update_env(self, config: dict):
|
||||
def __log_and_notify_error(self, message):
|
||||
"""
|
||||
更新设置到app.env
|
||||
记录错误日志并发送系统通知
|
||||
"""
|
||||
if not config:
|
||||
return
|
||||
|
||||
# 避免修改原值
|
||||
conf = copy.deepcopy(config)
|
||||
|
||||
# 自定义配置,以换行分隔
|
||||
config_params = self.__parse_params(conf.get("params"))
|
||||
conf.update(config_params)
|
||||
# 读写app.env
|
||||
env_path = settings.CONFIG_PATH / "app.env"
|
||||
for key, value in conf.items():
|
||||
if not key:
|
||||
continue
|
||||
# 如果参数不在支持列表中, 则跳过
|
||||
if key not in self.settings_attributes and key not in config_params:
|
||||
continue
|
||||
if value is None or str(value) == "None":
|
||||
value = ''
|
||||
else:
|
||||
value = str(value)
|
||||
set_key(env_path, key, value)
|
||||
logger.info("app.env文件写入完成")
|
||||
self.systemmessage.put("配置中心设置已写入app.env文件,插件关闭", title="配置中心")
|
||||
logger.error(message)
|
||||
self.systemmessage.put(message, title=self.plugin_name)
|
||||
|
||||
@staticmethod
|
||||
def __parse_params(param_str: str) -> dict:
|
||||
@@ -130,7 +104,7 @@ class ConfigCenter(_PluginBase):
|
||||
return result
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def get_command() -> List[Dict[str, Any]]:
|
||||
@@ -143,9 +117,13 @@ class ConfigCenter(_PluginBase):
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
"""
|
||||
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 = {
|
||||
"enabled": False,
|
||||
"params": "",
|
||||
"params": params_str
|
||||
}
|
||||
for attribute in self.settings_attributes:
|
||||
default_settings[attribute] = getattr(settings, attribute)
|
||||
@@ -156,43 +134,6 @@ class ConfigCenter(_PluginBase):
|
||||
{
|
||||
"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": "writeenv",
|
||||
"label": "写入app.env文件"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
@@ -204,7 +145,9 @@ class ConfigCenter(_PluginBase):
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "GITHUB_TOKEN",
|
||||
"label": "Github Token"
|
||||
"label": "GitHub Token",
|
||||
"hint": "GitHub Token,提高请求API限流阈值,格式: ghp_****",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -220,7 +163,9 @@ class ConfigCenter(_PluginBase):
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "API_TOKEN",
|
||||
"label": "API密钥"
|
||||
"label": "API密钥",
|
||||
"hint": "用于Jellyseerr/Overseerr、媒体服务器Webhook等配置以及部分支持API_TOKEN的API请求",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -236,7 +181,9 @@ class ConfigCenter(_PluginBase):
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "TMDB_API_DOMAIN",
|
||||
"label": "TMDB API地址"
|
||||
"label": "TMDB API地址",
|
||||
"hint": "TMDB API地址,无需修改,或配置为其他中转代理服务地址,确保连通性",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -252,7 +199,9 @@ class ConfigCenter(_PluginBase):
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "TMDB_IMAGE_DOMAIN",
|
||||
"label": "TheMovieDb图片服务器"
|
||||
"label": "TheMovieDb图片服务器",
|
||||
"hint": "TheMovieDb图片服务器,无需修改,或修改为其他可用地址如 static-mdb.v.geilijiasu.com",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -270,9 +219,17 @@ class ConfigCenter(_PluginBase):
|
||||
"model": "RECOGNIZE_SOURCE",
|
||||
"label": "媒体信息识别来源",
|
||||
"items": [
|
||||
{"title": "TheMovieDb", "value": "themoviedb"},
|
||||
{"title": "豆瓣", "value": "douban"}
|
||||
]
|
||||
{
|
||||
"title": "TheMovieDb",
|
||||
"value": "themoviedb"
|
||||
},
|
||||
{
|
||||
"title": "豆瓣",
|
||||
"value": "douban"
|
||||
}
|
||||
],
|
||||
"hint": "媒体信息识别来源",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -290,9 +247,17 @@ class ConfigCenter(_PluginBase):
|
||||
"model": "SCRAP_SOURCE",
|
||||
"label": "刮削元数据及图片使用的数据源",
|
||||
"items": [
|
||||
{"title": "TheMovieDb", "value": "themoviedb"},
|
||||
{"title": "豆瓣", "value": "douban"},
|
||||
]
|
||||
{
|
||||
"title": "TheMovieDb",
|
||||
"value": "themoviedb"
|
||||
},
|
||||
{
|
||||
"title": "豆瓣",
|
||||
"value": "douban"
|
||||
}
|
||||
],
|
||||
"hint": "刮削元数据及图片使用的数据源",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -309,7 +274,8 @@ class ConfigCenter(_PluginBase):
|
||||
"props": {
|
||||
"model": "META_CACHE_EXPIRE",
|
||||
"label": "元数据缓存时间(小时)",
|
||||
"placeholder": "单位:小时"
|
||||
"hint": "元数据缓存过期时间,0为系统默认",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -327,9 +293,17 @@ class ConfigCenter(_PluginBase):
|
||||
"model": "WALLPAPER",
|
||||
"label": "登录首页电影海报",
|
||||
"items": [
|
||||
{"title": "TheMovieDb电影海报", "value": "tmdb"},
|
||||
{"title": "Bing每日壁纸", "value": "bing"}
|
||||
]
|
||||
{
|
||||
"title": "TheMovieDb电影海报",
|
||||
"value": "tmdb"
|
||||
},
|
||||
{
|
||||
"title": "Bing每日壁纸",
|
||||
"value": "bing"
|
||||
}
|
||||
],
|
||||
"hint": "登录首页电影海报",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -337,8 +311,8 @@ class ConfigCenter(_PluginBase):
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
"component": "VRow",
|
||||
"content": [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
@@ -350,7 +324,9 @@ class ConfigCenter(_PluginBase):
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "OCR_HOST",
|
||||
"label": "验证码识别服务器"
|
||||
"label": "验证码识别服务器",
|
||||
"hint": "验证码识别服务器地址",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -366,8 +342,9 @@ class ConfigCenter(_PluginBase):
|
||||
"component": "VTextField",
|
||||
"props": {
|
||||
"model": "GITHUB_PROXY",
|
||||
"label": "Github加速服务器",
|
||||
"placeholder": "https://mirror.ghproxy.com/"
|
||||
"label": "GitHub加速服务器",
|
||||
"hint": "GitHub加速服务器,格式: https://mirror.ghproxy.com/",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -384,7 +361,8 @@ class ConfigCenter(_PluginBase):
|
||||
"props": {
|
||||
"model": "PIP_PROXY",
|
||||
"label": "PIP加速服务器",
|
||||
"placeholder": "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
"hint": "PIP加速服务器,格式: https://pypi.tuna.tsinghua.edu.cn/simple",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -401,7 +379,8 @@ class ConfigCenter(_PluginBase):
|
||||
"props": {
|
||||
"model": "MEDIASERVER_SYNC_INTERVAL",
|
||||
"label": "媒体服务器同步间隔(小时)",
|
||||
"placeholder": "单位:小时"
|
||||
"hint": "媒体服务器同步间隔",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -409,8 +388,8 @@ class ConfigCenter(_PluginBase):
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
"component": "VRow",
|
||||
"content": [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
@@ -423,7 +402,8 @@ class ConfigCenter(_PluginBase):
|
||||
"props": {
|
||||
"model": "DOH_DOMAINS",
|
||||
"label": "DOH解析的域名",
|
||||
"placeholder": "多个域名使用,分隔"
|
||||
"hint": "DOH解析的域名列表,多个域名使用逗号分隔",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -440,7 +420,8 @@ class ConfigCenter(_PluginBase):
|
||||
"props": {
|
||||
"model": "DOH_RESOLVERS",
|
||||
"label": "DOH解析服务器",
|
||||
"placeholder": "多个地址使用,分隔"
|
||||
"hint": "DOH解析服务器列表,多个服务器使用逗号分隔",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -448,19 +429,21 @@ class ConfigCenter(_PluginBase):
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
"component": "VRow",
|
||||
"content": [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"cols": 12
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextarea",
|
||||
"props": {
|
||||
"model": "MOVIE_RENAME_FORMAT",
|
||||
"label": "电影重命名格式"
|
||||
"label": "电影重命名格式",
|
||||
"hint": "电影重命名格式,使用Jinja2语法,每行一个配置项,参考:https://jinja.palletsprojects.com/en/3.0.x/templates/",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -468,19 +451,21 @@ class ConfigCenter(_PluginBase):
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
"component": "VRow",
|
||||
"content": [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"cols": 12
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"component": "VTextarea",
|
||||
"props": {
|
||||
"model": "TV_RENAME_FORMAT",
|
||||
"label": "电视剧重命名格式"
|
||||
"label": "电视剧重命名格式",
|
||||
"hint": "电视剧重命名格式,使用Jinja2语法,参考:https://jinja.palletsprojects.com/en/3.0.x/templates/",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -488,12 +473,12 @@ class ConfigCenter(_PluginBase):
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
"component": "VRow",
|
||||
"content": [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"cols": 12
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
@@ -501,7 +486,8 @@ class ConfigCenter(_PluginBase):
|
||||
"props": {
|
||||
"model": "PLUGIN_MARKET",
|
||||
"label": "插件市场",
|
||||
"placeholder": "多个地址使用,分隔"
|
||||
"hint": "插件市场仓库地址,多个地址使用逗号分隔,确保每个地址以/结尾",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -509,12 +495,12 @@ class ConfigCenter(_PluginBase):
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
"component": "VRow",
|
||||
"content": [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
"cols": 12,
|
||||
"cols": 12
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
@@ -522,7 +508,8 @@ class ConfigCenter(_PluginBase):
|
||||
"props": {
|
||||
"model": "params",
|
||||
"label": "自定义配置",
|
||||
"placeholder": "每行一个配置项,格式:配置项=值"
|
||||
"hint": "自定义配置,每行一个配置项,格式:配置项=值",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -530,8 +517,8 @@ class ConfigCenter(_PluginBase):
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
"component": "VRow",
|
||||
"content": [
|
||||
{
|
||||
"component": "VCol",
|
||||
"props": {
|
||||
@@ -543,7 +530,9 @@ class ConfigCenter(_PluginBase):
|
||||
"component": "VSwitch",
|
||||
"props": {
|
||||
"model": "DOWNLOAD_SUBTITLE",
|
||||
"label": "自动下载站点字幕"
|
||||
"label": "自动下载站点字幕",
|
||||
"hint": "自动下载站点字幕(如有)",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -559,7 +548,9 @@ class ConfigCenter(_PluginBase):
|
||||
"component": "VSwitch",
|
||||
"props": {
|
||||
"model": "SCRAP_FOLLOW_TMDB",
|
||||
"label": "新增入库跟随TMDB信息变化"
|
||||
"label": "新增入库跟随TMDB信息变化",
|
||||
"hint": "新增入库媒体是否跟随TMDB信息变化",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -575,7 +566,9 @@ class ConfigCenter(_PluginBase):
|
||||
"component": "VSwitch",
|
||||
"props": {
|
||||
"model": "FANART_ENABLE",
|
||||
"label": "使用Fanart图片数据源"
|
||||
"label": "使用Fanart图片数据源",
|
||||
"hint": "启用Fanart图片数据源",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -591,7 +584,9 @@ class ConfigCenter(_PluginBase):
|
||||
"component": "VSwitch",
|
||||
"props": {
|
||||
"model": "DOH_ENABLE",
|
||||
"label": "启用DNS over HTTPS"
|
||||
"label": "启用DNS over HTTPS",
|
||||
"hint": "是否启用DNS over HTTPS,启用后对特定域名使用DOH解析以避免DNS污染",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -607,7 +602,9 @@ class ConfigCenter(_PluginBase):
|
||||
"component": "VSwitch",
|
||||
"props": {
|
||||
"model": "SEARCH_MULTIPLE_NAME",
|
||||
"label": "资源搜索整合多名称搜索结果"
|
||||
"label": "资源搜索整合多名称搜索结果",
|
||||
"hint": "搜索多个名称时是否整合多名称的搜索结果,True/false",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -623,7 +620,9 @@ class ConfigCenter(_PluginBase):
|
||||
"component": "VSwitch",
|
||||
"props": {
|
||||
"model": "AUXILIARY_AUTH_ENABLE",
|
||||
"label": "启用用户辅助认证"
|
||||
"label": "启用用户辅助认证",
|
||||
"hint": "是否启用用户辅助认证,允许通过外部服务进行认证、单点登录以及自动创建用户",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -639,7 +638,9 @@ class ConfigCenter(_PluginBase):
|
||||
"component": "VSwitch",
|
||||
"props": {
|
||||
"model": "GLOBAL_IMAGE_CACHE",
|
||||
"label": "全局图片缓存"
|
||||
"label": "全局图片缓存",
|
||||
"hint": "是否启用全局图片缓存,将媒体图片缓存到本地",
|
||||
"persistent-hint": True
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -658,9 +659,9 @@ class ConfigCenter(_PluginBase):
|
||||
{
|
||||
'component': 'VAlert',
|
||||
'props': {
|
||||
'type': 'info',
|
||||
'type': 'warning',
|
||||
'variant': 'tonal',
|
||||
'text': '注意:开启写入app.env后将直接修改配置文件,否则只是运行时修改生效对应配置(插件关闭且重启后配置失效);有些自定义配置需要重启才能生效。'
|
||||
'text': '注意:部分配置项的更改可能需要重启服务才能生效,为确保配置一致性,已在环境变量中的相关配置项,请手动更新'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user