forked from Class-Widgets/Class-Widgets
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathplugin.py
More file actions
161 lines (136 loc) · 7.08 KB
/
plugin.py
File metadata and controls
161 lines (136 loc) · 7.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import importlib
import json
import shutil
from typing import Any, Dict, List, Optional
from loguru import logger
import conf
from basic_dirs import CONFIG_HOME
class PluginLoader: # 插件加载器
def __init__(self, p_mgr: Optional[Any] = None) -> None:
self.plugins_settings: Dict[str, Any] = {}
self.plugins_name: List[str] = []
self.plugins_dict: Dict[str, Any] = {}
self.manager = p_mgr
def set_manager(self, p_mgr: Any) -> None:
self.manager = p_mgr
def load_plugins(self) -> List[str]:
plugin_config = conf.load_plugin_config()
safe_plugin_enabled = plugin_config.get('safe_plugin', False)
if 'temp_disabled_plugins' in plugin_config:
temp_disabled = plugin_config['temp_disabled_plugins']
if temp_disabled:
for plugin_name in temp_disabled:
if plugin_name not in plugin_config.get('enabled_plugins', []):
plugin_config['enabled_plugins'].append(plugin_name)
plugin_config['temp_disabled_plugins'] = []
conf.save_plugin_config(plugin_config)
for folder in conf.PLUGIN_HOME.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.PLUGIN_HOME.name
module_name = f"{relative_path}.{folder.name}"
try:
module = importlib.import_module(module_name)
if hasattr(module, 'Settings'): # 设置页
plugin_class = module.Settings # 获取 Plugin 类
# 实例化插件
self.plugins_settings[folder.name] = plugin_class(
str(conf.PLUGIN_HOME / folder.name)
)
if self.manager and hasattr(module, 'Plugin'): # 插件入口
plugin_class = 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)
if safe_plugin_enabled:
self._disable_plugin_safely(folder.name)
logger.warning(f"已临时禁用插件 {folder.name}")
continue
except Exception as e:
logger.error(f"加载插件 {folder.name} 时发生未知错误: {e}")
if safe_plugin_enabled:
self._disable_plugin_safely(folder.name)
logger.warning(f"已临时禁用插件 {folder.name}")
# 大部分情况一般不会影响运行
continue
return self.plugins_name
def _disable_plugin_safely(self, plugin_name: str) -> None:
"""安全禁用插件"""
plugin_config = conf.load_plugin_config()
if plugin_name in plugin_config.get('enabled_plugins', []):
plugin_config['enabled_plugins'].remove(plugin_name)
if 'temp_disabled_plugins' not in plugin_config:
plugin_config['temp_disabled_plugins'] = []
if plugin_name not in plugin_config['temp_disabled_plugins']:
plugin_config['temp_disabled_plugins'].append(plugin_name)
conf.save_plugin_config(plugin_config)
logger.info(f"插件 {plugin_name} 已被临时禁用")
def run_plugins(self) -> None:
for plugin in self.plugins_dict.values():
plugin.execute()
def update_plugins(self) -> None:
for plugin in self.plugins_dict.values():
if hasattr(plugin, 'update') and self.manager:
plugin.update(self.manager.get_app_contexts())
def delete_plugin(self, plugin_name: str) -> bool:
plugin_dir = conf.PLUGIN_HOME / 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 = CONFIG_HOME / 'widget.json'
if widget_config_path.exists():
with open(widget_config_path, 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("主配置文件 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()