插件开发指南
Ghost Downloader 支持通过插件扩展其功能。本指南将引导你完成插件的开发过程。
插件基础
所有插件都必须基于 app.common.plugin_base.PluginBase
抽象基类进行开发。
1. 创建插件文件
在 Ghost Downloader 程序目录下的 plugins/
文件夹中创建一个新的 Python 文件(.py
)。你也可以使用编译后的二进制文件(.pyd
for Windows, .so
for Linux/macOS)。
2. 定义插件类
在你的 Python 文件中,定义一个继承自 PluginBase
的类:
python
# plugins/my_awesome_plugin.py
from app.common.plugin_base import PluginBase
from app.common.signal_bus import signalBus # 用于信号通信 (可选)
from qfluentwidgets import Action, InfoBar, InfoBarPosition # 用于 UI 交互 (可选)
from PySide6.QtGui import QIcon # 用于图标 (可选)
class MyAwesomePlugin(PluginBase):
def __init__(self, mainWindow):
"""
插件初始化方法 (必须实现)
"""
super().__init__(mainWindow) # 调用基类初始化
# 定义插件元数据 (必须)
self.name: str = "My Awesome Plugin"
self.version: str = "0.1.0"
self.author: str = "Your Name"
self.icon: str = ":/icons/my_plugin_icon.png" # 使用 Qt 资源路径 (需自行编译资源或确保路径有效)
self.description: str = "这是一个示例插件,演示了基本功能。"
# self.mainWindow 是主窗口对象,可以通过它访问主程序的 UI 元素或方法
# 例如: self.mainWindow.titleLabel.setText("Plugin Loaded!")
# 注意:直接操作 UI 元素可能不是最佳实践,推荐使用信号槽或预留接口
# 可以在这里进行一些初始化设置
self.some_setting = True
def load(self):
"""
插件加载方法 (必须实现)
这是插件功能实现的核心入口。
"""
print(f"插件 '{self.name}' v{self.version} 已加载!")
# --- 示例:添加一个菜单项 ---
# 假设 mainWindow 有一个 menuBar 对象和一个 fileMenu 对象
try:
new_action = Action(QIcon(self.icon), "插件操作", self.mainWindow)
new_action.triggered.connect(self.on_plugin_action_triggered)
# 假设有一个 'toolsMenu'
self.mainWindow.toolsMenu.addAction(new_action)
print("示例菜单项已添加。")
except AttributeError as e:
print(f"无法添加菜单项,主窗口可能没有预期的菜单对象: {e}")
# --- 示例:连接到信号总线 ---
# 假设有一个任务完成信号
# signalBus.taskFinishedSig.connect(self.on_task_finished)
# --- 示例:调用主窗口方法 ---
# 假设 mainWindow 有一个 show_message 方法
# self.mainWindow.show_message("来自插件的消息!")
def on_plugin_action_triggered(self):
"""示例菜单项触发的槽函数"""
print("插件菜单项被点击了!")
InfoBar.success(
"插件提示",
f"'{self.name}' 的操作被触发!",
duration=3000,
parent=self.mainWindow,
position=InfoBarPosition.TOP
)
# def on_task_finished(self, task_info):
# """示例:处理任务完成信号的槽函数"""
# print(f"插件收到任务完成信号: {task_info}")
# 你可以在这里定义插件所需的其他方法
3. 实现 __init__
方法
- 必须 调用
super().__init__(mainWindow)
。 - 必须 定义
self.name
,self.version
,self.author
,self.icon
,self.description
这些元数据属性。icon
应指向一个有效的 Qt 资源路径或文件路径。 - 你可以通过
self.mainWindow
访问主窗口对象,以便后续与主程序交互。
4. 实现 load
方法
- 这是插件的核心逻辑所在。当 Ghost Downloader 加载插件时,会调用此方法。
- 你可以在这里:
- 连接到信号总线 (
app.common.signal_bus.signalBus
) 以响应程序事件或发出自定义信号。 - 向主界面添加菜单项、工具栏按钮等 UI 元素(需要主程序提供相应的接口或可访问的对象)。
- 注册新的协议处理器或下载逻辑。
- 执行任何插件启动时需要完成的任务。
- 连接到信号总线 (
插件加载机制
- Ghost Downloader 启动时会扫描
plugins/
目录下的.py
,.pyd
,.so
文件。 - 它会动态导入这些文件作为模块。
- 查找模块中所有继承自
PluginBase
的类。 - 实例化找到的插件类,并将主窗口对象
mainWindow
传递给构造函数__init__
。 - 调用插件实例的
load()
方法。 - 加载过程中发生的错误会被记录到日志中。
注意事项
- 稳定性: 插件代码的错误可能会影响主程序的稳定性。请确保代码健壮并进行充分测试。
- UI 交互: 直接操作主窗口的 UI 元素可能不是长久之计,因为主程序 UI 可能变化。优先使用信号槽机制或主程序明确提供的插件 API(如果存在)。
- 资源文件: 如果插件需要图标等资源,推荐使用 Qt 的资源系统 (
.qrc
文件编译为_rc.py
) 并通过资源路径引用(如:/icons/my_icon.png
)。 - 依赖: 如果插件有额外的 Python 库依赖,需要用户手动安装。考虑在插件文档中说明依赖项。
参考 api-reference.md
(如果存在) 获取更多关于可用的信号和主窗口接口的信息。