125 lines
5.2 KiB
Python
125 lines
5.2 KiB
Python
import importlib
|
|
import json
|
|
from pathlib import Path
|
|
import shutil
|
|
|
|
from loguru import logger
|
|
|
|
import conf
|
|
|
|
|
|
class PluginLoader: # 插件加载器
|
|
def __init__(self, p_mgr=None):
|
|
self.plugins_settings = {}
|
|
self.plugins_name = []
|
|
self.plugins_dict = {}
|
|
self.manager = p_mgr
|
|
|
|
def set_manager(self, p_mgr):
|
|
self.manager = p_mgr
|
|
|
|
def load_plugins(self):
|
|
for folder in Path(conf.PLUGINS_DIR).iterdir():
|
|
if folder.is_dir() and (folder / 'plugin.json').exists():
|
|
self.plugins_name.append(folder.name) # 检测所有插件
|
|
|
|
if folder.name not in conf.load_plugin_config()['enabled_plugins']:
|
|
continue
|
|
relative_path = conf.PLUGINS_DIR.name
|
|
module_name = f"{relative_path}.{folder.name}"
|
|
try:
|
|
module = importlib.import_module(module_name)
|
|
|
|
if hasattr(module, 'Settings'): # 设置页
|
|
plugin_class = getattr(module, "Settings") # 获取 Plugin 类
|
|
# 实例化插件
|
|
self.plugins_settings[folder.name] = plugin_class(f'{conf.PLUGINS_DIR}/{folder.name}')
|
|
|
|
if self.manager and hasattr(module, 'Plugin'): # 插件入口
|
|
plugin_class = getattr(module, "Plugin") # 获取 Plugin 类
|
|
# 实例化插件
|
|
self.plugins_dict[folder.name] = plugin_class(
|
|
self.manager.get_app_contexts(folder.name), self.manager.method
|
|
)
|
|
|
|
logger.success(f"加载插件成功:{module_name}")
|
|
except (ImportError, FileNotFoundError) as e:
|
|
logger.warning(f"加载插件 {folder.name} 失败: {e}. 可能缺少文件或依赖项。将禁用此插件。")
|
|
plugin_config = conf.load_plugin_config()
|
|
if folder.name in plugin_config['enabled_plugins']:
|
|
plugin_config['enabled_plugins'].remove(folder.name)
|
|
conf.save_plugin_config(plugin_config)
|
|
if folder.name in self.plugins_name:
|
|
self.plugins_name.remove(folder.name)
|
|
continue
|
|
except Exception as e:
|
|
logger.error(f"加载插件 {folder.name} 时发生未知错误: {e}")
|
|
# 大部分情况一般不会影响运行
|
|
continue
|
|
return self.plugins_name
|
|
|
|
def run_plugins(self):
|
|
for plugin in self.plugins_dict.values():
|
|
plugin.execute()
|
|
|
|
def update_plugins(self):
|
|
for plugin in self.plugins_dict.values():
|
|
if hasattr(plugin, 'update'):
|
|
plugin.update(self.manager.get_app_contexts())
|
|
|
|
def delete_plugin(self, plugin_name):
|
|
plugin_dir = Path(conf.PLUGINS_DIR) / plugin_name
|
|
if not plugin_dir.is_dir():
|
|
logger.warning(f"插件目录 {plugin_dir} 不存在,无法删除。")
|
|
return False
|
|
widgets_to_remove = []
|
|
if widgets_to_remove:
|
|
try:
|
|
widget_config_path = Path(conf.base_directory) / 'config' / 'widget.json'
|
|
if widget_config_path.exists():
|
|
with open(widget_config_path, 'r', encoding='utf-8') as f:
|
|
widget_config = json.load(f)
|
|
|
|
original_widgets = widget_config.get('widgets', [])
|
|
# 过滤掉要移除的组件
|
|
widget_config['widgets'] = [w for w in original_widgets if w not in widgets_to_remove]
|
|
|
|
with open(widget_config_path, 'w', encoding='utf-8') as f:
|
|
json.dump(widget_config, f, ensure_ascii=False, indent=4)
|
|
logger.info(f"已从 config/widget.json 中移除插件 {plugin_name} 的关联组件: {widgets_to_remove}")
|
|
else:
|
|
logger.warning(f"主配置文件 config/widget.json 不存在,无法移除插件组件。")
|
|
except Exception as e:
|
|
logger.error(f"更新 config/widget.json 失败: {e}")
|
|
|
|
if plugin_name in self.plugins_dict:
|
|
del self.plugins_dict[plugin_name]
|
|
logger.info(f"已移除正在运行的插件实例: {plugin_name}")
|
|
if plugin_name in self.plugins_settings:
|
|
del self.plugins_settings[plugin_name]
|
|
logger.info(f"已移除插件设置实例: {plugin_name}")
|
|
|
|
plugin_config = conf.load_plugin_config()
|
|
if plugin_name in plugin_config.get('enabled_plugins', []):
|
|
plugin_config['enabled_plugins'].remove(plugin_name)
|
|
conf.save_plugin_config(plugin_config)
|
|
logger.info(f"已从启用插件列表中移除: {plugin_name}")
|
|
|
|
if plugin_name in self.plugins_name:
|
|
self.plugins_name.remove(plugin_name)
|
|
|
|
try:
|
|
shutil.rmtree(plugin_dir)
|
|
logger.success(f"插件 {plugin_name} 已成功删除。")
|
|
return True
|
|
except Exception as e:
|
|
logger.error(f"删除插件目录 {plugin_dir} 失败: {e}")
|
|
return False
|
|
|
|
p_loader = PluginLoader()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
p_loader.load_plugins()
|
|
p_loader.run_plugins()
|