告别重复劳动:Anki插件开发指南帮你解锁记忆工具无限可能

告别重复劳动:Anki插件开发指南帮你解锁记忆工具无限可能

【免费下载链接】anki Anki's shared backend and web components, and the Qt frontend 【免费下载链接】anki 项目地址: https://gitcode.com/GitHub_Trending/an/anki

Anki作为一款强大的记忆卡片工具,其真正魅力在于通过插件(Add-on)扩展核心功能。无论是自定义学习流程、添加媒体处理能力,还是集成第三方服务,插件都能让Anki完全适配你的学习需求。本文将从环境搭建到实战开发,带你掌握Anki插件开发的完整流程。

开发准备与环境配置

Anki插件本质上是遵循特定结构的Python包,需要了解其核心目录结构与加载机制。官方贡献指南docs/contributing.md中详细说明了代码规范,其中特别强调了钩子(Hook)系统的使用规范——这是插件与Anki核心功能交互的主要方式。

基础开发环境

  1. 必备工具

    • Python 3.9+(Anki核心运行环境)
    • Anki 2.1.50+(插件开发目标版本)
    • 代码编辑器(VS Code推荐安装Python插件)
  2. 目录结构 插件需放置在Anki的插件文件夹中,典型结构如下:

    my-addon/
    ├── __init__.py       # 插件入口文件
    ├── manifest.json     # 插件元数据(名称、版本、兼容性等)
    ├── config.json       # 默认配置
    ├── config.md         # 配置说明文档
    └── user_files/       # 用户数据存储目录(可选)
    
  3. manifest.json规范 元数据文件需符合JSON Schema验证要求,核心字段包括:

    {
      "package": "my-addon-id",  // 唯一标识符
      "name": "我的第一个插件",
      "min_point_version": 2150, // 最低兼容版本
      "mod": 1620000000          // 最后修改时间戳
    }
    

    完整规范可参考qt/aqt/addons.py中的_manifest_schema定义。

核心技术:钩子系统与事件处理

Anki通过钩子(Hook)机制允许插件介入应用生命周期。钩子分为两类:事件钩子(如卡片渲染前触发)和过滤钩子(如修改卡片内容)。官方在docs/contributing.md中定义了钩子命名规范,例如editor_did_update_tags表示编辑器标签更新后触发。

钩子注册与使用

__init__.py中通过addHook函数注册钩子处理函数:

from anki.hooks import addHook
from aqt import mw  # 主窗口实例

def on_note_saved(note):
    """当笔记保存时执行"""
    print(f"笔记'{note.id}'已保存")

# 注册钩子:note_saved是笔记保存后的标准钩子
addHook("note_saved", on_note_saved)

常用钩子列表可在pylib/anki/hooks.py中查看,包含从卡片渲染到同步完成的各类事件。

猴子补丁(谨慎使用)

对于没有钩子的场景,可使用wrap函数修改现有方法(需谨慎,可能随Anki版本变化失效):

from anki.hooks import wrap
from aqt.browser import Browser

def on_browser_setup(browser: Browser):
    """扩展浏览器上下文菜单"""
    browser.form.menuEdit.addAction("我的操作", lambda: print("点击了自定义菜单"))

# 包装Browser类的setupMenus方法
Browser.setupMenus = wrap(Browser.setupMenus, on_browser_setup)

插件开发实战:进度条增强工具

以下通过开发一个"学习进度统计"插件,演示完整开发流程。该插件将在Deck Browser页面显示每日学习进度条。

1. 目录结构设计

progress-tracker/
├── __init__.py        # 主逻辑
├── manifest.json      # 元数据
├── config.json        # 配置项(目标每日卡片数)
└── user_files/        # 存储历史数据

2. 核心功能实现

# __init__.py
from anki.hooks import addHook
from aqt.deckbrowser import DeckBrowser
from aqt.utils import qconnect
from PyQt6.QtWidgets import QProgressBar
import json
import os
from datetime import datetime

# 加载配置
def load_config():
    config_path = os.path.join(os.path.dirname(__file__), "config.json")
    with open(config_path, "r") as f:
        return json.load(f)

config = load_config()
TARGET_CARDS = config.get("target_daily_cards", 20)

# 初始化进度条
def init_progress_bar(browser: DeckBrowser):
    # 创建进度条控件
    progress_bar = QProgressBar()
    progress_bar.setRange(0, TARGET_CARDS)
    
    # 获取今日学习数(实际实现需查询数据库)
    today = datetime.now().strftime("%Y-%m-%d")
    cards_done = 5  # 简化示例,实际应从col.stats()获取
    
    progress_bar.setValue(cards_done)
    browser.form.verticalLayout.addWidget(progress_bar)

# 注册DeckBrowser加载完成后的钩子
addHook("deck_browser_did_init", init_progress_bar)

3. 配置界面开发

通过Anki的配置API可轻松添加设置界面。在__init__.py中添加:

from aqt.addons import AddonManager

def on_config_changed(new_config):
    """配置更新时触发"""
    global TARGET_CARDS
    TARGET_CARDS = new_config.get("target_daily_cards", 20)

# 注册配置更新钩子
AddonManager.setConfigUpdatedAction(__name__, on_config_changed)

创建config.json默认配置:

{
  "target_daily_cards": 20
}

调试与发布

调试技巧

  1. 日志输出:使用aqt.utils.tooltip()显示调试信息,或通过qt/aqt/log.py中的日志系统输出到文件
  2. 错误捕获:Anki会自动捕获插件异常并显示在启动错误对话框中,详细日志可在Tools > Add-ons > View Log查看
  3. 热重载:修改代码后在插件管理器中禁用再启用插件,无需重启Anki

打包与发布

  1. 将插件目录压缩为ZIP文件,确保根目录包含__init__.pymanifest.json
  2. 测试兼容性:通过修改manifest.json中的min_point_versionmax_point_version指定支持版本范围
  3. 发布渠道:可上传至AnkiWeb或分享ZIP文件,安装时通过Tools > Add-ons > Install from file导入

高级主题与最佳实践

数据存储方案

  • 配置数据:使用mw.addonManager.writeConfig(__name__, config)(见qt/aqt/addons.py
  • 用户数据:推荐存储在插件目录下的user_files文件夹,Anki更新插件时会自动备份该目录(qt/aqt/addons.py

性能优化

  • 避免在高频钩子(如card_will_render)中执行耗时操作
  • 使用aqt.taskman.TaskManager进行异步处理:
    from aqt.taskman import run_in_background
    
    def long_running_task():
        # 耗时操作
        return result
    
    def on_complete(result):
        print(f"任务结果: {result}")
    
    run_in_background(long_running_task, on_complete)
    

兼容性维护

  • 定期检查docs/changelog.md了解API变更
  • 使用anki.utils.version模块判断Anki版本:
    from anki.utils import int_version
    
    if int_version() >= 2300:
        # 新API实现
    else:
        # 兼容旧版本代码
    

资源与学习路径

  • 官方文档docs/contributing.md提供核心开发指南
  • 钩子参考:pylib/anki/hooks_gen.py(自动生成的钩子定义)
  • 示例插件:AnkiWeb上的热门插件源码(如Image Occlusion Enhanced
  • 社区支持:访问Anki论坛的"Add-ons"板块获取帮助

通过本文介绍的知识,你已具备开发Anki插件的核心能力。无论是简单的功能增强还是复杂的学习工具,Anki的插件系统都能满足你的需求。开始动手改造你的记忆助手吧!

【免费下载链接】anki Anki's shared backend and web components, and the Qt frontend 【免费下载链接】anki 项目地址: https://gitcode.com/GitHub_Trending/an/anki

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值