Skip to content

插件开发指南

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 (如果存在) 获取更多关于可用的信号和主窗口接口的信息。