update commit prev

This commit is contained in:
2026-04-26 16:49:23 -07:00
parent 39ee857559
commit bfd5c20dc3
25 changed files with 231 additions and 77 deletions
+82 -3
View File
@@ -93,7 +93,10 @@ def clear_config_cache() -> None:
def _log_config_load_summary(config: Dict[str, Any]) -> None:
try:
provs = list(config.get("provider", {}).keys()) if isinstance(config.get("provider"), dict) else []
plugin_block = config.get("plugin")
if not isinstance(plugin_block, dict):
plugin_block = config.get("provider")
provs = list(plugin_block.keys()) if isinstance(plugin_block, dict) else []
stores = list(config.get("store", {}).keys()) if isinstance(config.get("store"), dict) else []
mtime = None
try:
@@ -101,7 +104,7 @@ def _log_config_load_summary(config: Dict[str, Any]) -> None:
except Exception:
mtime = None
summary = (
f"Loaded config from {db.db_path.name}: providers={len(provs)} ({', '.join(provs[:10])}{'...' if len(provs)>10 else ''}), "
f"Loaded config from {db.db_path.name}: plugins={len(provs)} ({', '.join(provs[:10])}{'...' if len(provs)>10 else ''}), "
f"stores={len(stores)} ({', '.join(stores[:10])}{'...' if len(stores)>10 else ''}), mtime={mtime}"
)
log(summary)
@@ -325,6 +328,7 @@ def get_hydrus_url(config: Dict[str, Any], instance_name: str = "home") -> Optio
def get_provider_block(config: Dict[str, Any], name: str) -> Dict[str, Any]:
_normalize_plugin_config_aliases(config)
provider_cfg = config.get("provider")
if not isinstance(provider_cfg, dict):
return {}
@@ -518,7 +522,7 @@ def resolve_cookies_path(
except Exception as exc:
logger.debug("resolve_cookies_path: failed to read tool.ytdlp cookies: %s", exc, exc_info=True)
base_dir = script_dir or SCRIPT_DIR
base_dir = _resolve_app_root(script_dir)
for value in values:
if not value:
continue
@@ -528,6 +532,10 @@ def resolve_cookies_path(
if candidate.is_file():
return candidate
plugin_cookie = resolve_plugin_asset_path("ytdlp", "cookies.txt", script_dir=base_dir)
if plugin_cookie is not None:
return plugin_cookie
default_path = base_dir / "cookies.txt"
if default_path.is_file():
return default_path
@@ -547,6 +555,70 @@ def _normalize_provider_name(value: Any) -> Optional[str]:
candidate = str(value or "").strip().lower()
return candidate if candidate else None
def _resolve_app_root(script_dir: Optional[Path] = None) -> Path:
if script_dir is not None:
try:
candidate = expand_path(script_dir)
except Exception:
candidate = Path(script_dir)
return candidate if candidate.is_dir() else candidate.parent
return SCRIPT_DIR.parent
def resolve_plugin_asset_path(
plugin_name: str,
*relative_parts: str,
script_dir: Optional[Path] = None,
) -> Optional[Path]:
normalized = _normalize_provider_name(plugin_name)
if not normalized:
return None
plugin_dir = _resolve_app_root(script_dir) / "plugins" / normalized
if not plugin_dir.is_dir():
return None
for part in relative_parts:
text = str(part or "").strip().strip("/\\")
if not text:
continue
candidate = plugin_dir / text
if candidate.is_file():
return candidate
return None
def _normalize_plugin_config_aliases(config: Dict[str, Any]) -> None:
if not isinstance(config, dict):
return
plugin_block = config.get("plugin")
provider_block = config.get("provider")
normalized_provider: Dict[str, Any] = {}
if isinstance(provider_block, dict):
for key, value in provider_block.items():
normalized_key = _normalize_provider_name(key)
if normalized_key and normalized_key not in normalized_provider:
normalized_provider[normalized_key] = value
if isinstance(plugin_block, dict):
for key, value in plugin_block.items():
normalized_key = _normalize_provider_name(key)
if normalized_key and normalized_key not in normalized_provider:
normalized_provider[normalized_key] = value
if normalized_provider:
config["provider"] = normalized_provider
config["plugin"] = normalized_provider
else:
if isinstance(provider_block, dict):
config["plugin"] = provider_block
elif isinstance(plugin_block, dict):
config["provider"] = plugin_block
def _extract_api_key(value: Any) -> Optional[str]:
if isinstance(value, dict):
for key in ("api_key", "API_KEY", "apikey", "APIKEY"):
@@ -564,6 +636,8 @@ def _sync_alldebrid_api_key(config: Dict[str, Any]) -> None:
if not isinstance(config, dict):
return
_normalize_plugin_config_aliases(config)
providers = config.get("provider")
if not isinstance(providers, dict):
providers = {}
@@ -617,7 +691,10 @@ def _sync_alldebrid_api_key(config: Dict[str, Any]) -> None:
def _flatten_config_entries(config: Dict[str, Any]) -> Dict[Tuple[str, str, str, str], Any]:
entries: Dict[Tuple[str, str, str, str], Any] = {}
_normalize_plugin_config_aliases(config)
for key, value in config.items():
if key == 'plugin':
continue
if key in ('store', 'provider', 'tool') and isinstance(value, dict):
for subtype, instances in value.items():
if not isinstance(instances, dict):
@@ -655,6 +732,7 @@ def load_config(*, emit_summary: bool = True) -> Dict[str, Any]:
# Load strictly from database
db_config = get_config_all()
if db_config:
_normalize_plugin_config_aliases(db_config)
_sync_alldebrid_api_key(db_config)
_CONFIG_CACHE = db_config
_LAST_SAVED_CONFIG = deepcopy(db_config)
@@ -742,6 +820,7 @@ def _release_save_lock(lock_dir: Path) -> None:
def save_config(config: Dict[str, Any]) -> int:
global _CONFIG_CACHE, _LAST_SAVED_CONFIG
_normalize_plugin_config_aliases(config)
_sync_alldebrid_api_key(config)
# Acquire cross-process save lock to avoid concurrent saves from different
+27 -15
View File
@@ -61,11 +61,15 @@ def get_store_schema(store_type: str) -> List[ConfigField]:
return _call_schema(cls, f"store '{store_type}'")
def get_provider_schema(provider_name: str) -> List[ConfigField]:
plugin_class = get_plugin_class(str(provider_name or "").strip())
def get_plugin_schema(plugin_name: str) -> List[ConfigField]:
plugin_class = get_plugin_class(str(plugin_name or "").strip())
if plugin_class is None:
return []
return _call_schema(plugin_class, f"provider '{provider_name}'")
return _call_schema(plugin_class, f"plugin '{plugin_name}'")
def get_provider_schema(provider_name: str) -> List[ConfigField]:
return get_plugin_schema(provider_name)
def get_tool_schema(tool_name: str) -> List[ConfigField]:
@@ -85,8 +89,8 @@ def get_item_schema(item_type: str, item_name: str) -> List[ConfigField]:
normalized_name = str(item_name or "").strip()
if normalized_type.startswith("store-"):
return get_store_schema(normalized_type.replace("store-", "", 1))
if normalized_type == "provider":
return get_provider_schema(normalized_name)
if normalized_type in {"provider", "plugin"}:
return get_plugin_schema(normalized_name)
if normalized_type == "tool":
return get_tool_schema(normalized_name)
return []
@@ -126,25 +130,29 @@ def build_default_store_config(store_type: str, instance_name: str) -> Dict[str,
return config
def build_default_provider_config(provider_name: str) -> Dict[str, Any]:
def build_default_plugin_config(plugin_name: str) -> Dict[str, Any]:
config: Dict[str, Any] = {}
schema = get_provider_schema(provider_name)
schema = get_plugin_schema(plugin_name)
if schema:
for field in schema:
config[field["key"]] = field.get("default", "")
return config
plugin_class = get_plugin_class(str(provider_name or "").strip())
plugin_class = get_plugin_class(str(plugin_name or "").strip())
if plugin_class is None:
return config
try:
for required_key in plugin_class.required_config_keys():
config[str(required_key)] = ""
except Exception:
logger.exception("Failed to load legacy required config keys for provider '%s'", provider_name)
logger.exception("Failed to load legacy required config keys for plugin '%s'", plugin_name)
return config
def build_default_provider_config(provider_name: str) -> Dict[str, Any]:
return build_default_plugin_config(provider_name)
def build_default_tool_config(tool_name: str) -> Dict[str, Any]:
config: Dict[str, Any] = {}
for field in get_tool_schema(tool_name):
@@ -179,14 +187,14 @@ def get_required_config_keys(item_type: str, item_name: str) -> List[str]:
if cls is not None:
for required_key in _required_keys_for(cls):
_add_key(required_key)
elif normalized_type == "provider":
elif normalized_type in {"provider", "plugin"}:
plugin_class = get_plugin_class(normalized_name)
if plugin_class is not None:
try:
for required_key in plugin_class.required_config_keys():
_add_key(required_key)
except Exception:
logger.exception("Failed to load required config keys for provider '%s'", normalized_name)
logger.exception("Failed to load required config keys for plugin '%s'", normalized_name)
return required_keys
@@ -199,14 +207,18 @@ def get_configurable_store_types() -> List[str]:
return sorted(set(options))
def get_configurable_provider_types() -> List[str]:
def get_configurable_plugin_types() -> List[str]:
options: List[str] = []
for provider_name in list_plugins().keys():
if get_provider_schema(provider_name):
options.append(str(provider_name))
for plugin_name in list_plugins().keys():
if get_plugin_schema(plugin_name):
options.append(str(plugin_name))
return sorted(set(options))
def get_configurable_provider_types() -> List[str]:
return get_configurable_plugin_types()
def get_configurable_tool_types() -> List[str]:
options: List[str] = []
try: