diff --git a/plugins.v2/configcenter/__init__.py b/plugins.v2/configcenter/__init__.py index f6ddf87..350d3e6 100644 --- a/plugins.v2/configcenter/__init__.py +++ b/plugins.v2/configcenter/__init__.py @@ -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': '注意:部分配置项的更改可能需要重启服务才能生效,为确保配置一致性,已在环境变量中的相关配置项,请手动更新' } } ]