mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-29 12:06:51 +08:00
117 lines
4.4 KiB
Python
117 lines
4.4 KiB
Python
"""插件目录条目的运行态元数据映射。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Callable
|
|
from typing import Any, Optional
|
|
|
|
from app.runtime.extensions.plugin.contracts import supports_plugin_hook
|
|
from app.schemas.plugin import Plugin
|
|
|
|
|
|
class PluginMetadataMapper:
|
|
"""把市场或本地仓条目映射为包含运行态状态的插件 DTO。"""
|
|
|
|
def __init__(
|
|
self,
|
|
*,
|
|
plugin_instance: Callable[[str], Optional[Any]],
|
|
plugin_class: Callable[[str], Optional[Any]],
|
|
annotate_system_version: Callable[[dict], dict],
|
|
is_package_compatible: Callable[[dict, str], bool],
|
|
auth_checker: Callable[[Plugin, dict], bool],
|
|
version_compare: Callable[[str, str, str], bool],
|
|
log: Any,
|
|
) -> None:
|
|
"""保存注册表、兼容判断和权限判断端口。"""
|
|
self._plugin_instance = plugin_instance
|
|
self._plugin_class = plugin_class
|
|
self._annotate_system_version = annotate_system_version
|
|
self._is_package_compatible = is_package_compatible
|
|
self._auth_checker = auth_checker
|
|
self._version_compare = version_compare
|
|
self._logger = log
|
|
|
|
def map(
|
|
self,
|
|
plugin_id: str,
|
|
plugin_info: dict,
|
|
market: str,
|
|
installed_plugins: list[str],
|
|
add_time: int,
|
|
package_version: Optional[str] = None,
|
|
) -> Optional[Plugin]:
|
|
"""映射一个插件索引条目,不兼容或无权限时返回空。"""
|
|
if not isinstance(plugin_info, dict):
|
|
return None
|
|
info = self._annotate_system_version(plugin_info.copy())
|
|
if not self._is_package_compatible(info, package_version or ""):
|
|
return None
|
|
|
|
instance = self._plugin_instance(plugin_id)
|
|
plugin_class = self._plugin_class(plugin_id)
|
|
plugin = Plugin(id=plugin_id)
|
|
plugin.installed = plugin_id in installed_plugins and plugin_class is not None
|
|
plugin.has_update = False
|
|
if plugin_class:
|
|
installed_version = getattr(plugin_class, "plugin_version", None)
|
|
online_version = info.get("version")
|
|
if installed_version and online_version:
|
|
plugin.has_update = self._version_compare(
|
|
installed_version,
|
|
"<",
|
|
online_version,
|
|
)
|
|
|
|
plugin.system_version = info.get("system_version")
|
|
if info.get("system_version_compatible") is False:
|
|
plugin.system_version_compatible = False
|
|
plugin.system_version_message = info.get("system_version_message")
|
|
|
|
plugin.state = self._state(plugin_id, instance)
|
|
plugin.has_page = bool(
|
|
instance and supports_plugin_hook(instance, "get_page")
|
|
)
|
|
if info.get("key"):
|
|
plugin.plugin_public_key = info["key"]
|
|
if not self._auth_checker(plugin, info):
|
|
return None
|
|
|
|
plugin.plugin_name = info.get("name")
|
|
plugin.plugin_desc = info.get("description")
|
|
plugin.plugin_version = info.get("version")
|
|
plugin.plugin_icon = info.get("icon")
|
|
plugin.plugin_label = self.normalize_label(info.get("labels"))
|
|
plugin.plugin_author = info.get("author")
|
|
plugin.history = info.get("history") or {}
|
|
plugin.release = bool(info.get("release"))
|
|
plugin.repo_url = market
|
|
plugin.is_local = False
|
|
plugin.add_time = add_time
|
|
return plugin
|
|
|
|
def _state(self, plugin_id: str, instance: Optional[Any]) -> bool:
|
|
"""安全读取插件运行状态,插件异常时降级为未启用。"""
|
|
if not instance or not hasattr(instance, "get_state"):
|
|
return False
|
|
try:
|
|
return bool(instance.get_state())
|
|
except Exception as error: # noqa: BLE001
|
|
self._logger.error(f"获取插件 {plugin_id} 状态出错:{error}")
|
|
return False
|
|
|
|
@staticmethod
|
|
def normalize_label(labels: Any) -> Optional[str]:
|
|
"""兼容市场标签的旧字符串和新列表格式。"""
|
|
if isinstance(labels, str):
|
|
label = labels.strip()
|
|
return label or None
|
|
if isinstance(labels, list):
|
|
normalized = [
|
|
str(item).strip()
|
|
for item in labels
|
|
if str(item).strip()
|
|
]
|
|
return " ".join(normalized) or None
|
|
return None
|