refactor(config): retire RuntimeSettingsCompat host usage

This commit is contained in:
jxxghp
2026-08-26 15:55:21 +08:00
parent cdab54254d
commit 9dbe424c3d
162 changed files with 1966 additions and 1745 deletions
+62 -63
View File
@@ -37,7 +37,7 @@ from app.runtime.dependencies import (
iter_runtime_requirement_strings,
runtime_excluded_dependency_pairs,
)
from app.runtime.settings import RuntimeSettingsCompat
from app.runtime.settings import get_runtime_setting
from app.adapters.system.package import (
PackageInstallRequest,
build_package_install_strategies,
@@ -64,9 +64,8 @@ from app.adapters.system.host import SystemUtils
from app.foundation.url import UrlUtils
from app.runtime.version import get_app_version
# 保留模块级可替换入口,代理默认读取组合根的最新 runtime 配置。
settings = RuntimeSettingsCompat()
PLUGIN_DIR = Path(settings.ROOT_PATH) / "app" / "plugins"
# 插件市场只通过 runtime 读取端口消费组合根的最新配置。
PLUGIN_DIR = Path(get_runtime_setting('ROOT_PATH')) / "app" / "plugins"
LOCAL_REPO_PREFIX = "local://"
PLUGIN_SYSTEM_VERSION_FIELD = "system_version"
PLUGIN_MARKET_WIKI_START = "<!-- plugin-market-repos:start -->"
@@ -317,7 +316,7 @@ class PluginHelper(metaclass=WeakSingleton):
return None
path = Path(values[0]).expanduser()
if not path.is_absolute():
path = settings.ROOT_PATH / path
path = get_runtime_setting('ROOT_PATH') / path
return path.resolve()
except Exception:
return None
@@ -355,9 +354,9 @@ class PluginHelper(metaclass=WeakSingleton):
未启用 VERSION_FLAG(v1)时返回空列表,表示仅使用 package.json 基础索引。
"""
flags: List[str] = []
if settings.VERSION_FLAG:
flags.append(settings.VERSION_FLAG)
flags.extend(VERSION_BACKWARD_COMPATIBLE_FLAGS.get(settings.VERSION_FLAG, []))
if get_runtime_setting('VERSION_FLAG'):
flags.append(get_runtime_setting('VERSION_FLAG'))
flags.extend(VERSION_BACKWARD_COMPATIBLE_FLAGS.get(get_runtime_setting('VERSION_FLAG'), []))
return flags
@classmethod
@@ -370,9 +369,9 @@ class PluginHelper(metaclass=WeakSingleton):
"""
if not isinstance(plugin_info, dict):
return False
if not settings.VERSION_FLAG:
if not get_runtime_setting('VERSION_FLAG'):
return True
current_flag = settings.VERSION_FLAG
current_flag = get_runtime_setting('VERSION_FLAG')
if plugin_info.get(current_flag) is False:
return False
if plugin_info.get(current_flag) is True:
@@ -398,7 +397,7 @@ class PluginHelper(metaclass=WeakSingleton):
"""
if not isinstance(plugin_info, dict):
return False
current_flag = settings.VERSION_FLAG
current_flag = get_runtime_setting('VERSION_FLAG')
if not current_flag:
return not package_version
if package_version == current_flag:
@@ -416,7 +415,7 @@ class PluginHelper(metaclass=WeakSingleton):
package_version: Optional[str],
) -> Tuple[str, ...]:
"""返回插件安装唯一的代际候选顺序,并去除重复的基础索引。"""
preferred_version = package_version or settings.VERSION_FLAG
preferred_version = package_version or get_runtime_setting('VERSION_FLAG')
candidates = [preferred_version]
candidates.extend(
VERSION_BACKWARD_COMPATIBLE_FLAGS.get(preferred_version, [])
@@ -491,16 +490,16 @@ class PluginHelper(metaclass=WeakSingleton):
"""
获取本地插件仓库目录列表
"""
if not settings.PLUGIN_LOCAL_REPO_PATHS:
if not get_runtime_setting('PLUGIN_LOCAL_REPO_PATHS'):
return []
paths = []
for item in settings.PLUGIN_LOCAL_REPO_PATHS.split(","):
for item in get_runtime_setting('PLUGIN_LOCAL_REPO_PATHS').split(","):
local_repo_path = item.strip()
if not local_repo_path:
continue
path = Path(local_repo_path).expanduser()
if not path.is_absolute():
path = settings.ROOT_PATH / path
path = get_runtime_setting('ROOT_PATH') / path
paths.append(path.resolve())
return paths
@@ -542,11 +541,11 @@ class PluginHelper(metaclass=WeakSingleton):
continue
package_candidates = []
if settings.VERSION_FLAG:
package_candidates.append((settings.VERSION_FLAG, self.__get_local_package(repo_path,
settings.VERSION_FLAG)))
if get_runtime_setting('VERSION_FLAG'):
package_candidates.append((get_runtime_setting('VERSION_FLAG'), self.__get_local_package(repo_path,
get_runtime_setting('VERSION_FLAG'))))
# 向后兼容:补充扫描更低版本的 package 文件,便于本地仓库复用历史版本插件。
for backward_flag in VERSION_BACKWARD_COMPATIBLE_FLAGS.get(settings.VERSION_FLAG, []):
for backward_flag in VERSION_BACKWARD_COMPATIBLE_FLAGS.get(get_runtime_setting('VERSION_FLAG'), []):
package_candidates.append((backward_flag, self.__get_local_package(repo_path, backward_flag)))
package_candidates.append(("", self.__get_local_package(repo_path)))
@@ -611,9 +610,9 @@ class PluginHelper(metaclass=WeakSingleton):
repo_paths = [repo_path.resolve()] if repo_path else self.get_local_repo_paths()
package_versions = [package_version] if package_version is not None else []
if package_version is None:
if settings.VERSION_FLAG:
package_versions.append(settings.VERSION_FLAG)
package_versions.extend(VERSION_BACKWARD_COMPATIBLE_FLAGS.get(settings.VERSION_FLAG, []))
if get_runtime_setting('VERSION_FLAG'):
package_versions.append(get_runtime_setting('VERSION_FLAG'))
package_versions.extend(VERSION_BACKWARD_COMPATIBLE_FLAGS.get(get_runtime_setting('VERSION_FLAG'), []))
package_versions.append("")
selected_candidate = None
for repo_order, local_repo_path in enumerate(self.get_local_repo_paths()):
@@ -650,7 +649,7 @@ class PluginHelper(metaclass=WeakSingleton):
if not is_compatible:
candidate["compatible"] = False
candidate["skip_reason"] = (
f"插件索引条目不兼容 {settings.VERSION_FLAG}"
f"插件索引条目不兼容 {get_runtime_setting('VERSION_FLAG')}"
)
self.annotate_plugin_system_version(candidate)
if strict_system_version and candidate.get("system_version_compatible") is False:
@@ -729,7 +728,7 @@ class PluginHelper(metaclass=WeakSingleton):
else "package.json"
)
package_url = cls.__append_cache_buster(f"{raw_url}{package_file}")
headers = settings.REPO_GITHUB_HEADERS(repo=f"{user}/{repo}")
headers = get_runtime_setting('REPO_GITHUB_HEADERS')(repo=f"{user}/{repo}")
return package_url, headers
@classmethod
@@ -829,7 +828,7 @@ class PluginHelper(metaclass=WeakSingleton):
return
user_repo = f"{user}/{repo}"
headers = settings.REPO_GITHUB_HEADERS(repo=user_repo)
headers = get_runtime_setting('REPO_GITHUB_HEADERS')(repo=user_repo)
for page in range(1, 11):
release_api = (
f"https://api.github.com/repos/{user_repo}/releases"
@@ -998,7 +997,7 @@ class PluginHelper(metaclass=WeakSingleton):
package_version: Optional[str] = None) -> Optional[str]:
"""
检查并获取指定插件的可用版本,支持多版本优先级加载和版本兼容性检测
1. 如果未指定版本,则使用系统配置的默认版本(通过 settings.VERSION_FLAG 设置)
1. 如果未指定版本,则使用系统配置的默认版本(通过 get_runtime_setting('VERSION_FLAG') 设置)
2. 优先检查指定版本的插件(如 `package.v2.json`
3. 检查更低版本的 package 文件,并应用版本兼容标志
4. 检查 `package.json` 文件,并应用共享实现兼容标志
@@ -1084,7 +1083,7 @@ class PluginHelper(metaclass=WeakSingleton):
user_repo = f"{user}/{repo}"
if not package_version:
package_version = settings.VERSION_FLAG
package_version = get_runtime_setting('VERSION_FLAG')
# 1. 优先检查指定版本的插件
package_version = self.get_plugin_package_version(pid, repo_url, package_version)
@@ -1232,7 +1231,7 @@ class PluginHelper(metaclass=WeakSingleton):
file_api += f"/{pid.lower()}"
res = self.__request_with_fallback(file_api,
headers=settings.REPO_GITHUB_HEADERS(repo=user_repo),
headers=get_runtime_setting('REPO_GITHUB_HEADERS')(repo=user_repo),
is_api=True,
timeout=30)
if res is None:
@@ -1273,7 +1272,7 @@ class PluginHelper(metaclass=WeakSingleton):
if item.get("download_url"):
logger.debug(f"正在下载文件:{item.get('path')}")
res = self.__request_with_fallback(item.get('download_url'),
headers=settings.REPO_GITHUB_HEADERS(repo=user_repo))
headers=get_runtime_setting('REPO_GITHUB_HEADERS')(repo=user_repo))
if not res:
return False, f"文件 {item.get('path')} 下载失败!"
elif res.status_code != 200:
@@ -1285,7 +1284,7 @@ class PluginHelper(metaclass=WeakSingleton):
relative_path = relative_path.replace(f"plugins.{package_version}", "plugins", 1)
# 创建插件文件夹并写入文件
file_path = Path(settings.ROOT_PATH) / "app" / relative_path
file_path = Path(get_runtime_setting('ROOT_PATH')) / "app" / relative_path
file_path.parent.mkdir(parents=True, exist_ok=True)
with open(file_path, "w", encoding="utf-8") as f:
f.write(res.text)
@@ -1327,7 +1326,7 @@ class PluginHelper(metaclass=WeakSingleton):
:return: 备份目录路径
"""
plugin_dir = PLUGIN_DIR / pid.lower()
backup_dir = Path(settings.TEMP_PATH) / "plugin_backup" / pid.lower()
backup_dir = Path(get_runtime_setting('TEMP_PATH')) / "plugin_backup" / pid.lower()
if plugin_dir.exists():
# 备份时清理已有的备份目录,防止残留文件影响
@@ -1381,7 +1380,7 @@ class PluginHelper(metaclass=WeakSingleton):
logger.warn(f"{pid} 插件目录不存在,跳过刷新插件备份")
return False
backup_root = settings.CONFIG_PATH / "plugins_backup"
backup_root = get_runtime_setting('CONFIG_PATH') / "plugins_backup"
backup_dir = backup_root / pid.lower()
staging_dir = backup_root / f".{pid.lower()}.tmp-{uuid.uuid4().hex}"
previous_dir = backup_root / f".{pid.lower()}.old-{uuid.uuid4().hex}"
@@ -1546,7 +1545,7 @@ class PluginHelper(metaclass=WeakSingleton):
if package_name in cls._protected_runtime_packages
}
project_file = settings.ROOT_PATH / "pyproject.toml"
project_file = get_runtime_setting('ROOT_PATH') / "pyproject.toml"
root_requirements = cls.__parse_project_requirement_roots(project_file)
if not root_requirements:
return protected_packages
@@ -1595,7 +1594,7 @@ class PluginHelper(metaclass=WeakSingleton):
def __get_strict_runtime_packages(cls) -> Set[str]:
"""返回核心包及当前 ABI profile 中不得被插件改写的根包。"""
packages = set(cls._protected_runtime_packages)
project_file = settings.ROOT_PATH / "pyproject.toml"
project_file = get_runtime_setting('ROOT_PATH') / "pyproject.toml"
try:
for raw_requirement in iter_runtime_profile_requirement_strings(project_file):
requirement = Requirement(raw_requirement)
@@ -1717,7 +1716,7 @@ class PluginHelper(metaclass=WeakSingleton):
"""
以主程序依赖的当前已安装版本生成临时约束文件,确保插件安装不会改写主程序依赖。
"""
temp_dir = Path(settings.TEMP_PATH) / "plugin_dependencies"
temp_dir = Path(get_runtime_setting('TEMP_PATH')) / "plugin_dependencies"
temp_dir.mkdir(parents=True, exist_ok=True)
with tempfile.NamedTemporaryFile(
mode="w",
@@ -1794,10 +1793,10 @@ class PluginHelper(metaclass=WeakSingleton):
python_bin=Path(sys.executable),
find_links_dirs=find_links_dirs or [],
constraints_file=constraints_file,
config_dir=settings.CONFIG_PATH,
package_cache_root=settings.PACKAGE_CACHE_PATH,
package_index_url=settings.PIP_PROXY or None,
proxy_url=settings.PROXY_HOST or None,
config_dir=get_runtime_setting('CONFIG_PATH'),
package_cache_root=get_runtime_setting('PACKAGE_CACHE_PATH'),
package_index_url=get_runtime_setting('PIP_PROXY') or None,
proxy_url=get_runtime_setting('PROXY_HOST') or None,
purpose=purpose,
)
@@ -1868,7 +1867,7 @@ class PluginHelper(metaclass=WeakSingleton):
return lines
excluded_pairs = runtime_excluded_dependency_pairs(
Path(settings.ROOT_PATH) / "pyproject.toml"
Path(get_runtime_setting('ROOT_PATH')) / "pyproject.toml"
)
package_errors = set()
for match in matches:
@@ -1930,12 +1929,12 @@ class PluginHelper(metaclass=WeakSingleton):
if repair_target and not repair_target.exists():
repair_target = None
if repair_target is None:
repair_target = settings.ROOT_PATH / "pyproject.toml"
repair_target = get_runtime_setting('ROOT_PATH') / "pyproject.toml"
repair_desc = "主程序 uv.lock"
if not repair_target.exists():
return False, f"恢复依赖文件不存在:{repair_target}"
if snapshot_file is None and not (settings.ROOT_PATH / "uv.lock").exists():
return False, f"恢复依赖文件不存在:{settings.ROOT_PATH / 'uv.lock'}"
if snapshot_file is None and not (get_runtime_setting('ROOT_PATH') / "uv.lock").exists():
return False, f"恢复依赖文件不存在:{get_runtime_setting('ROOT_PATH') / 'uv.lock'}"
last_error = ""
request = cls.__build_package_install_request(repair_target, purpose="runtime-repair")
@@ -2127,21 +2126,21 @@ class PluginHelper(metaclass=WeakSingleton):
) -> List[Tuple[str, str, dict]]:
"""构造同步与异步 GitHub 请求共用的镜像、代理和直连顺序。"""
strategies: List[Tuple[str, str, dict]] = []
if not is_api and settings.GITHUB_PROXY:
if not is_api and get_runtime_setting('GITHUB_PROXY'):
proxy_url = (
f"{UrlUtils.standardize_base_url(settings.GITHUB_PROXY)}{url}"
f"{UrlUtils.standardize_base_url(get_runtime_setting('GITHUB_PROXY'))}{url}"
)
strategies.append(
("镜像站", proxy_url, {"headers": headers, "timeout": timeout})
)
if settings.PROXY_HOST:
if get_runtime_setting('PROXY_HOST'):
strategies.append(
(
"代理",
url,
{
"headers": headers,
"proxies": settings.PROXY,
"proxies": get_runtime_setting('PROXY'),
"timeout": timeout,
},
)
@@ -2218,7 +2217,7 @@ class PluginHelper(metaclass=WeakSingleton):
compatible, message = self.check_plugin_system_version(candidate)
return None if compatible else message
package_version = self.get_plugin_package_version(pid, repo_url, settings.VERSION_FLAG)
package_version = self.get_plugin_package_version(pid, repo_url, get_runtime_setting('VERSION_FLAG'))
if package_version is None:
return None
meta = self.__get_plugin_meta(pid, repo_url, package_version)
@@ -2235,7 +2234,7 @@ class PluginHelper(metaclass=WeakSingleton):
if self.is_local_repo_url(repo_url):
return await asyncio.to_thread(self.get_plugin_system_version_check_message, pid, repo_url)
package_version = await self.async_get_plugin_package_version(pid, repo_url, settings.VERSION_FLAG)
package_version = await self.async_get_plugin_package_version(pid, repo_url, get_runtime_setting('VERSION_FLAG'))
if package_version is None:
return None
meta = await self.__async_get_plugin_meta(pid, repo_url, package_version)
@@ -2382,7 +2381,7 @@ class PluginHelper(metaclass=WeakSingleton):
release_api = f"https://api.github.com/repos/{user_repo}/releases/tags/{release_tag}"
rel_res = self.__request_with_fallback(
release_api,
headers=settings.REPO_GITHUB_HEADERS(repo=user_repo),
headers=get_runtime_setting('REPO_GITHUB_HEADERS')(repo=user_repo),
timeout=30,
is_api=True,
)
@@ -2405,7 +2404,7 @@ class PluginHelper(metaclass=WeakSingleton):
return False, f"解析 Release 信息失败:{e}"
# 使用资产的API端点下载,需要设置Accept头为application/octet-stream
headers = settings.REPO_GITHUB_HEADERS(repo=user_repo).copy()
headers = get_runtime_setting('REPO_GITHUB_HEADERS')(repo=user_repo).copy()
headers["Accept"] = "application/octet-stream"
res = self.__request_with_fallback(download_url, headers=headers, is_api=True)
if res is None or res.status_code != 200:
@@ -2416,7 +2415,7 @@ class PluginHelper(metaclass=WeakSingleton):
infos = zf.infolist()
if not infos:
return False, "压缩包内容为空"
dest_base = Path(settings.ROOT_PATH) / "app" / "plugins" / pid.lower()
dest_base = Path(get_runtime_setting('ROOT_PATH')) / "app" / "plugins" / pid.lower()
targets = self.__iter_release_zip_targets(zf, dest_base)
wrote_any = False
for info, dest_path, is_dir in targets:
@@ -2721,7 +2720,7 @@ class PluginHelper(metaclass=WeakSingleton):
file_api += f"/{pid.lower()}"
res = await self.__async_request_with_fallback(file_api,
headers=settings.REPO_GITHUB_HEADERS(repo=user_repo),
headers=get_runtime_setting('REPO_GITHUB_HEADERS')(repo=user_repo),
is_api=True,
timeout=30)
if res is None:
@@ -2762,7 +2761,7 @@ class PluginHelper(metaclass=WeakSingleton):
if item.get("download_url"):
logger.debug(f"正在下载文件:{item.get('path')}")
res = await self.__async_request_with_fallback(item.get('download_url'),
headers=settings.REPO_GITHUB_HEADERS(repo=user_repo))
headers=get_runtime_setting('REPO_GITHUB_HEADERS')(repo=user_repo))
if not res:
return False, f"文件 {item.get('path')} 下载失败!"
elif res.status_code != 200:
@@ -2774,7 +2773,7 @@ class PluginHelper(metaclass=WeakSingleton):
relative_path = relative_path.replace(f"plugins.{package_version}", "plugins", 1)
# 创建插件文件夹并写入文件
file_path = AsyncPath(settings.ROOT_PATH) / "app" / relative_path
file_path = AsyncPath(get_runtime_setting('ROOT_PATH')) / "app" / relative_path
await file_path.parent.mkdir(parents=True, exist_ok=True)
async with aiofiles.open(file_path, "w", encoding="utf-8") as f:
await f.write(res.text)
@@ -2825,13 +2824,13 @@ class PluginHelper(metaclass=WeakSingleton):
if repair_target and not await _await_thread_operation(repair_target.exists):
repair_target = None
if repair_target is None:
repair_target = settings.ROOT_PATH / "pyproject.toml"
repair_target = get_runtime_setting('ROOT_PATH') / "pyproject.toml"
repair_desc = "主程序 uv.lock"
if not await _await_thread_operation(repair_target.exists):
return False, f"恢复依赖文件不存在:{repair_target}"
lock_file = settings.ROOT_PATH / "uv.lock"
lock_file = get_runtime_setting('ROOT_PATH') / "uv.lock"
if snapshot_file is None and not await _await_thread_operation(lock_file.exists):
return False, f"恢复依赖文件不存在:{settings.ROOT_PATH / 'uv.lock'}"
return False, f"恢复依赖文件不存在:{get_runtime_setting('ROOT_PATH') / 'uv.lock'}"
request = cls.__build_package_install_request(
repair_target,
@@ -3076,7 +3075,7 @@ class PluginHelper(metaclass=WeakSingleton):
:return: 备份目录路径
"""
plugin_dir = AsyncPath(PLUGIN_DIR) / pid.lower()
backup_dir = AsyncPath(settings.TEMP_PATH) / "plugin_backup" / pid.lower()
backup_dir = AsyncPath(get_runtime_setting('TEMP_PATH')) / "plugin_backup" / pid.lower()
if await plugin_dir.exists():
try:
@@ -3234,7 +3233,7 @@ class PluginHelper(metaclass=WeakSingleton):
user_repo = f"{user}/{repo}"
if not package_version:
package_version = settings.VERSION_FLAG
package_version = get_runtime_setting('VERSION_FLAG')
# 1. 优先检查指定版本的插件
package_version = await self.async_get_plugin_package_version(pid, repo_url, package_version)
@@ -3396,7 +3395,7 @@ class PluginHelper(metaclass=WeakSingleton):
release_api = f"https://api.github.com/repos/{user_repo}/releases/tags/{release_tag}"
rel_res = await self.__async_request_with_fallback(
release_api,
headers=settings.REPO_GITHUB_HEADERS(repo=user_repo),
headers=get_runtime_setting('REPO_GITHUB_HEADERS')(repo=user_repo),
timeout=30,
is_api=True,
)
@@ -3419,7 +3418,7 @@ class PluginHelper(metaclass=WeakSingleton):
return False, f"解析 Release 信息失败:{e}"
# 使用资产的API端点下载,需要设置Accept头为application/octet-stream
headers = settings.REPO_GITHUB_HEADERS(repo=user_repo).copy()
headers = get_runtime_setting('REPO_GITHUB_HEADERS')(repo=user_repo).copy()
headers["Accept"] = "application/octet-stream"
res = await self.__async_request_with_fallback(download_url,
headers=headers,
@@ -3432,7 +3431,7 @@ class PluginHelper(metaclass=WeakSingleton):
infos = zf.infolist()
if not infos:
return False, "压缩包内容为空"
dest_base = Path(settings.ROOT_PATH) / "app" / "plugins" / pid.lower()
dest_base = Path(get_runtime_setting('ROOT_PATH')) / "app" / "plugins" / pid.lower()
targets = self.__iter_release_zip_targets(zf, dest_base)
wrote_any = False
for info, dest_path, is_dir in targets:
+1 -1
View File
@@ -13,7 +13,7 @@ class OcrHelper:
def __init__(self, ocr_base_url: Optional[str] = None) -> None:
"""初始化 OCR 服务地址,优先使用组合根设置快照。"""
if ocr_base_url is None:
ocr_base_url = get_runtime_setting("OCR_HOST")
ocr_base_url = get_runtime_setting('OCR_HOST')
self._ocr_b64_url = f"{str(ocr_base_url).rstrip('/')}/captcha/base64"
def get_captcha_text(
+67 -68
View File
@@ -7,7 +7,7 @@ from urllib.parse import parse_qs, quote, urlparse, urlsplit
from app.runtime.cache import cached
from app.runtime.config import global_vars
from app.runtime.settings import RuntimeSettingsCompat
from app.runtime.settings import get_runtime_setting
from app.runtime.tasks import get_task_registry
from app.domain.context import MediaInfo, MusicInfo
from app.domain.meta.metabase import MetaBase
@@ -26,8 +26,7 @@ from app.adapters.system.host import SystemUtils
from app.runtime.version import get_app_version, get_frontend_version
# 保留旧插件可覆盖的模块级入口,默认通过 runtime 代理动态读取配置。
settings = RuntimeSettingsCompat()
# 中心服务适配器只通过 runtime 读取端口消费组合根的最新配置。
_server_report_service: Any = None
@@ -102,7 +101,7 @@ class MoviePilotServerHelper:
"""
判断请求地址是否指向配置中的 MoviePilot 服务端
"""
server_host = (settings.MP_SERVER_HOST or "").strip().rstrip("/")
server_host = (get_runtime_setting('MP_SERVER_HOST') or "").strip().rstrip("/")
if not server_host or not url:
return False
@@ -144,7 +143,7 @@ class MoviePilotServerHelper:
user_uid = cls.get_user_uid()
if user_uid:
request_headers[cls.USER_UID_HEADER] = user_uid
request_headers["User-Agent"] = settings.USER_AGENT
request_headers["User-Agent"] = get_runtime_setting('USER_AGENT')
return request_headers
@classmethod
@@ -162,10 +161,10 @@ class MoviePilotServerHelper:
"""
获取当前 GitHub 用户名
"""
if cls._github_user is None and settings.GITHUB_HEADERS:
if cls._github_user is None and get_runtime_setting('GITHUB_HEADERS'):
res = RequestUtils(
headers=settings.GITHUB_HEADERS,
proxies=settings.PROXY,
headers=get_runtime_setting('GITHUB_HEADERS'),
proxies=get_runtime_setting('PROXY'),
timeout=15,
).get_res("https://api.github.com/user")
if res:
@@ -178,10 +177,10 @@ class MoviePilotServerHelper:
"""
异步获取当前 GitHub 用户名
"""
if cls._github_user is None and settings.GITHUB_HEADERS:
if cls._github_user is None and get_runtime_setting('GITHUB_HEADERS'):
res = await AsyncRequestUtils(
headers=settings.GITHUB_HEADERS,
proxies=settings.PROXY,
headers=get_runtime_setting('GITHUB_HEADERS'),
proxies=get_runtime_setting('PROXY'),
timeout=15,
).get_res("https://api.github.com/user")
if res:
@@ -278,7 +277,7 @@ class MoviePilotServerHelper:
"user_uid": cls.get_user_uid(),
"backend_version": get_app_version(),
"frontend_version": get_frontend_version(),
"version_flag": settings.VERSION_FLAG,
"version_flag": get_runtime_setting('VERSION_FLAG'),
"platform": f"{platform.system()} {platform.release()}".strip(),
"arch": SystemUtils.cpu_arch(),
}
@@ -288,7 +287,7 @@ class MoviePilotServerHelper:
"""
上报当前安装实例的版本统计
"""
if not settings.USAGE_STATISTIC_SHARE:
if not get_runtime_setting('USAGE_STATISTIC_SHARE'):
return False
payload = cls.build_usage_payload()
if not payload.get("user_uid"):
@@ -305,7 +304,7 @@ class MoviePilotServerHelper:
"""
异步上报当前安装实例的版本统计
"""
if not settings.USAGE_STATISTIC_SHARE:
if not get_runtime_setting('USAGE_STATISTIC_SHARE'):
return False
payload = cls.build_usage_payload()
if not payload.get("user_uid"):
@@ -322,7 +321,7 @@ class MoviePilotServerHelper:
"""
异步获取安装版本统计报表
"""
if not settings.USAGE_STATISTIC_SHARE:
if not get_runtime_setting('USAGE_STATISTIC_SHARE'):
return {}
try:
res = await cls.async_usage_statistic()
@@ -338,7 +337,7 @@ class MoviePilotServerHelper:
初始化订阅统计上报状态
"""
cls._report_service().init_report(
enabled=settings.SUBSCRIBE_STATISTIC_SHARE,
enabled=get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'),
state_key=SystemConfigKey.SubscribeReport,
reporter=cls.sub_report,
)
@@ -347,7 +346,7 @@ class MoviePilotServerHelper:
async def async_init_subscribe_report(cls) -> None:
"""异步初始化订阅统计标记。"""
await cls._report_service().async_init_report(
enabled=settings.SUBSCRIBE_STATISTIC_SHARE,
enabled=get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'),
state_key=SystemConfigKey.SubscribeReport,
reporter=cls.async_sub_report,
)
@@ -358,7 +357,7 @@ class MoviePilotServerHelper:
初始化插件安装统计上报状态
"""
cls._report_service().init_report(
enabled=settings.PLUGIN_STATISTIC_SHARE,
enabled=get_runtime_setting('PLUGIN_STATISTIC_SHARE'),
state_key=SystemConfigKey.PluginInstallReport,
reporter=cls.install_plugin_report,
)
@@ -367,7 +366,7 @@ class MoviePilotServerHelper:
async def async_init_plugin_report(cls) -> None:
"""异步初始化插件统计标记。"""
await cls._report_service().async_init_report(
enabled=settings.PLUGIN_STATISTIC_SHARE,
enabled=get_runtime_setting('PLUGIN_STATISTIC_SHARE'),
state_key=SystemConfigKey.PluginInstallReport,
reporter=cls.async_install_plugin_report,
)
@@ -514,7 +513,7 @@ class MoviePilotServerHelper:
"""
获取插件安装统计
"""
if not settings.PLUGIN_STATISTIC_SHARE:
if not get_runtime_setting('PLUGIN_STATISTIC_SHARE'):
return {}
res = cls.plugin_statistic()
if res is not None and res.status_code == 200:
@@ -526,7 +525,7 @@ class MoviePilotServerHelper:
"""
异步获取插件安装统计
"""
if not settings.PLUGIN_STATISTIC_SHARE:
if not get_runtime_setting('PLUGIN_STATISTIC_SHARE'):
return {}
res = await cls.async_plugin_statistic()
if res is not None and res.status_code == 200:
@@ -590,7 +589,7 @@ class MoviePilotServerHelper:
"""
上报单个插件安装统计
"""
if not settings.PLUGIN_STATISTIC_SHARE:
if not get_runtime_setting('PLUGIN_STATISTIC_SHARE'):
return False
if not plugin_id:
return False
@@ -605,7 +604,7 @@ class MoviePilotServerHelper:
"""
异步上报单个插件安装统计
"""
if not settings.PLUGIN_STATISTIC_SHARE:
if not get_runtime_setting('PLUGIN_STATISTIC_SHARE'):
return False
if not plugin_id:
return False
@@ -621,7 +620,7 @@ class MoviePilotServerHelper:
批量上报存量插件安装统计
"""
return cls._report_service().report_plugins(
enabled=settings.PLUGIN_STATISTIC_SHARE,
enabled=get_runtime_setting('PLUGIN_STATISTIC_SHARE'),
items=items,
)
@@ -631,7 +630,7 @@ class MoviePilotServerHelper:
异步批量上报存量插件安装统计
"""
return await cls._report_service().async_report_plugins(
enabled=settings.PLUGIN_STATISTIC_SHARE,
enabled=get_runtime_setting('PLUGIN_STATISTIC_SHARE'),
items=items,
)
@@ -820,7 +819,7 @@ class MoviePilotServerHelper:
"""
获取订阅统计数据
"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return []
params = cls._build_subscribe_query_params(
page=page,
@@ -848,7 +847,7 @@ class MoviePilotServerHelper:
"""
异步获取订阅统计数据
"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return []
params = cls._build_subscribe_query_params(
page=page,
@@ -866,7 +865,7 @@ class MoviePilotServerHelper:
"""
新增订阅统计
"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return False
payload = cls._build_subscribe_statistic_payload(sub)
if not payload:
@@ -879,7 +878,7 @@ class MoviePilotServerHelper:
"""
异步新增订阅统计
"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return False
payload = cls._build_subscribe_statistic_payload(sub)
if not payload:
@@ -890,14 +889,14 @@ class MoviePilotServerHelper:
@classmethod
def sub_reg_durable(cls, sub: dict) -> bool:
"""同步上报新增统计;明确禁用时视为无需投递。"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return True
return cls.sub_reg(sub)
@classmethod
async def async_sub_reg_durable(cls, sub: dict) -> bool:
"""异步上报新增统计;明确禁用时视为无需投递。"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return True
return await cls.async_sub_reg(sub)
@@ -906,7 +905,7 @@ class MoviePilotServerHelper:
"""
完成订阅统计
"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return False
payload = cls._build_subscribe_statistic_payload(sub)
if not payload:
@@ -917,7 +916,7 @@ class MoviePilotServerHelper:
@classmethod
async def async_sub_done(cls, sub: dict) -> bool:
"""异步完成订阅统计,并仅在服务端确认成功时返回 True。"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return False
payload = cls._build_subscribe_statistic_payload(sub)
if not payload:
@@ -928,14 +927,14 @@ class MoviePilotServerHelper:
@classmethod
def sub_done_durable(cls, sub: dict) -> bool:
"""同步上报完成统计;明确禁用时视为无需投递。"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return True
return cls.sub_done(sub)
@classmethod
async def async_sub_done_durable(cls, sub: dict) -> bool:
"""异步上报完成统计;明确禁用时视为无需投递。"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return True
return await cls.async_sub_done(sub)
@@ -989,14 +988,14 @@ class MoviePilotServerHelper:
上报存量订阅统计
"""
return cls._report_service().report_subscribes(
enabled=settings.SUBSCRIBE_STATISTIC_SHARE,
enabled=get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'),
)
@classmethod
async def async_sub_report(cls) -> bool:
"""异步上报存量订阅统计。"""
return await cls._report_service().async_report_subscribes(
enabled=settings.SUBSCRIBE_STATISTIC_SHARE,
enabled=get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'),
)
@classmethod
@@ -1011,7 +1010,7 @@ class MoviePilotServerHelper:
分享订阅
"""
return cls._sharing_service().share_subscribe(
enabled=settings.SUBSCRIBE_STATISTIC_SHARE,
enabled=get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'),
subscribe_id=subscribe_id,
share_title=share_title,
share_comment=share_comment,
@@ -1030,7 +1029,7 @@ class MoviePilotServerHelper:
异步分享订阅
"""
return await cls._sharing_service().async_share_subscribe(
enabled=settings.SUBSCRIBE_STATISTIC_SHARE,
enabled=get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'),
subscribe_id=subscribe_id,
share_title=share_title,
share_comment=share_comment,
@@ -1056,7 +1055,7 @@ class MoviePilotServerHelper:
"""
删除订阅分享
"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return False, "当前没有开启订阅数据共享功能"
return cls._handle_response(
cls.subscribe_share_delete(share_id, cls.get_user_uuid()),
@@ -1068,7 +1067,7 @@ class MoviePilotServerHelper:
"""
异步删除订阅分享
"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return False, "当前没有开启订阅数据共享功能"
return cls._handle_response(
await cls.async_subscribe_share_delete(share_id, cls.get_user_uuid()),
@@ -1080,7 +1079,7 @@ class MoviePilotServerHelper:
"""
复用订阅分享
"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return False, "当前没有开启订阅数据共享功能"
return cls._handle_response(cls.subscribe_fork(share_id))
@@ -1089,7 +1088,7 @@ class MoviePilotServerHelper:
"""
异步复用订阅分享
"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return False, "当前没有开启订阅数据共享功能"
return cls._handle_response(await cls.async_subscribe_fork(share_id))
@@ -1108,7 +1107,7 @@ class MoviePilotServerHelper:
"""
获取订阅分享数据
"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return []
params = cls._build_subscribe_query_params(
page=page,
@@ -1136,7 +1135,7 @@ class MoviePilotServerHelper:
"""
异步获取订阅分享数据
"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return []
params = cls._build_subscribe_query_params(
page=page,
@@ -1155,7 +1154,7 @@ class MoviePilotServerHelper:
"""
获取订阅分享统计数据
"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return []
return cls._handle_list_response(cls.subscribe_share_statistics())
@@ -1165,7 +1164,7 @@ class MoviePilotServerHelper:
"""
异步获取订阅分享统计数据
"""
if not settings.SUBSCRIBE_STATISTIC_SHARE:
if not get_runtime_setting('SUBSCRIBE_STATISTIC_SHARE'):
return []
return cls._handle_list_response(await cls.async_subscribe_share_statistics())
@@ -1252,7 +1251,7 @@ class MoviePilotServerHelper:
分享工作流
"""
return cls._sharing_service().share_workflow(
enabled=settings.WORKFLOW_STATISTIC_SHARE,
enabled=get_runtime_setting('WORKFLOW_STATISTIC_SHARE'),
workflow_id=workflow_id,
share_title=share_title,
share_comment=share_comment,
@@ -1271,7 +1270,7 @@ class MoviePilotServerHelper:
异步分享工作流
"""
return await cls._sharing_service().async_share_workflow(
enabled=settings.WORKFLOW_STATISTIC_SHARE,
enabled=get_runtime_setting('WORKFLOW_STATISTIC_SHARE'),
workflow_id=workflow_id,
share_title=share_title,
share_comment=share_comment,
@@ -1283,7 +1282,7 @@ class MoviePilotServerHelper:
"""
删除工作流分享
"""
if not settings.WORKFLOW_STATISTIC_SHARE:
if not get_runtime_setting('WORKFLOW_STATISTIC_SHARE'):
return False, "当前没有开启工作流数据共享功能"
return cls._handle_response(
cls.workflow_share_delete(share_id, cls.get_user_uuid()),
@@ -1295,7 +1294,7 @@ class MoviePilotServerHelper:
"""
异步删除工作流分享
"""
if not settings.WORKFLOW_STATISTIC_SHARE:
if not get_runtime_setting('WORKFLOW_STATISTIC_SHARE'):
return False, "当前没有开启工作流数据共享功能"
return cls._handle_response(
await cls.async_workflow_share_delete(share_id, cls.get_user_uuid()),
@@ -1307,7 +1306,7 @@ class MoviePilotServerHelper:
"""
复用工作流分享
"""
if not settings.WORKFLOW_STATISTIC_SHARE:
if not get_runtime_setting('WORKFLOW_STATISTIC_SHARE'):
return False, "当前没有开启工作流数据共享功能"
return cls._handle_response(cls.workflow_fork(share_id))
@@ -1316,7 +1315,7 @@ class MoviePilotServerHelper:
"""
异步复用工作流分享
"""
if not settings.WORKFLOW_STATISTIC_SHARE:
if not get_runtime_setting('WORKFLOW_STATISTIC_SHARE'):
return False, "当前没有开启工作流数据共享功能"
return cls._handle_response(await cls.async_workflow_fork(share_id))
@@ -1331,7 +1330,7 @@ class MoviePilotServerHelper:
"""
获取工作流分享数据
"""
if not settings.WORKFLOW_STATISTIC_SHARE:
if not get_runtime_setting('WORKFLOW_STATISTIC_SHARE'):
return []
return cls._handle_list_response(cls.workflow_shares({
"name": name,
@@ -1350,7 +1349,7 @@ class MoviePilotServerHelper:
"""
异步获取工作流分享数据
"""
if not settings.WORKFLOW_STATISTIC_SHARE:
if not get_runtime_setting('WORKFLOW_STATISTIC_SHARE'):
return []
return cls._handle_list_response(await cls.async_workflow_shares({
"name": name,
@@ -1370,10 +1369,10 @@ class MoviePilotServerHelper:
"""
获取共享识别服务端地址
"""
custom_api = (settings.MEDIA_RECOGNIZE_SHARE_API or "").strip()
custom_api = (get_runtime_setting('MEDIA_RECOGNIZE_SHARE_API') or "").strip()
if custom_api:
return custom_api.rstrip("/")
server_host = (settings.MP_SERVER_HOST or "").strip().rstrip("/")
server_host = (get_runtime_setting('MP_SERVER_HOST') or "").strip().rstrip("/")
if not server_host:
return None
return f"{server_host}{cls._RECOGNIZE_SHARE_PATH}"
@@ -1429,7 +1428,7 @@ class MoviePilotServerHelper:
"""
查询共享识别结果
"""
if not settings.MEDIA_RECOGNIZE_SHARE:
if not get_runtime_setting('MEDIA_RECOGNIZE_SHARE'):
return None
params = cls._build_recognize_query_params(
meta=meta,
@@ -1453,7 +1452,7 @@ class MoviePilotServerHelper:
"""
异步查询共享识别结果
"""
if not settings.MEDIA_RECOGNIZE_SHARE:
if not get_runtime_setting('MEDIA_RECOGNIZE_SHARE'):
return None
params = cls._build_recognize_query_params(
meta=meta,
@@ -1476,7 +1475,7 @@ class MoviePilotServerHelper:
"""
上报共享识别结果电影电视剧音乐共用
"""
if not settings.MEDIA_RECOGNIZE_SHARE:
if not get_runtime_setting('MEDIA_RECOGNIZE_SHARE'):
return False
payload = cls._build_recognize_report_payload(
meta=meta,
@@ -1498,7 +1497,7 @@ class MoviePilotServerHelper:
"""
异步上报共享识别结果电影电视剧音乐共用
"""
if not settings.MEDIA_RECOGNIZE_SHARE:
if not get_runtime_setting('MEDIA_RECOGNIZE_SHARE'):
return False
payload = cls._build_recognize_report_payload(
meta=meta,
@@ -1855,7 +1854,7 @@ class MoviePilotServerHelper:
"""
根据服务端基础地址和路径生成完整 URL
"""
return f"{settings.MP_SERVER_HOST.rstrip('/')}{path}"
return f"{get_runtime_setting('MP_SERVER_HOST').rstrip('/')}{path}"
@classmethod
def _get(
@@ -1869,7 +1868,7 @@ class MoviePilotServerHelper:
发送服务端 GET 请求默认携带安装用户 ID
"""
return RequestUtils(
proxies=settings.PROXY,
proxies=get_runtime_setting('PROXY'),
timeout=timeout,
headers=cls.build_headers(url) if include_user_uid else {},
).get_res(url, params=params)
@@ -1886,7 +1885,7 @@ class MoviePilotServerHelper:
异步发送服务端 GET 请求默认携带安装用户 ID
"""
return await AsyncRequestUtils(
proxies=settings.PROXY,
proxies=get_runtime_setting('PROXY'),
timeout=timeout,
headers=cls.build_headers(url) if include_user_uid else {},
).get_res(url, params=params)
@@ -1897,7 +1896,7 @@ class MoviePilotServerHelper:
发送携带安装用户 ID 的服务端 JSON POST 请求
"""
return RequestUtils(
proxies=settings.PROXY,
proxies=get_runtime_setting('PROXY'),
timeout=timeout,
headers=cls.build_headers(url, content_type="application/json"),
).post(url, json=payload)
@@ -1908,7 +1907,7 @@ class MoviePilotServerHelper:
异步发送携带安装用户 ID 的服务端 JSON POST 请求
"""
return await AsyncRequestUtils(
proxies=settings.PROXY,
proxies=get_runtime_setting('PROXY'),
timeout=timeout,
headers=cls.build_headers(url, content_type="application/json"),
).post(url, json=payload)
@@ -1919,7 +1918,7 @@ class MoviePilotServerHelper:
发送携带安装用户 ID 的服务端 DELETE 请求
"""
return RequestUtils(
proxies=settings.PROXY,
proxies=get_runtime_setting('PROXY'),
timeout=timeout,
headers=cls.build_headers(url),
).delete_res(url, params=params)
@@ -1930,7 +1929,7 @@ class MoviePilotServerHelper:
异步发送携带安装用户 ID 的服务端 DELETE 请求
"""
return await AsyncRequestUtils(
proxies=settings.PROXY,
proxies=get_runtime_setting('PROXY'),
timeout=timeout,
headers=cls.build_headers(url),
).delete_res(url, params=params)