Communityコーディング&開発github.com

aknahin/koplugin-skill

KOReaderプラグイン(*.koplugin、Lua)の作成、レビュー、デバッグ、検証を行います。Kobo、Kindle、PocketBook、Android、およびデスクトップエミュレータ向けの電子書籍リーダープラグイン開発に対応します。

koplugin-skill とは?

このスキルは、KOReader向けプラグイン(koplugin)の開発を支援するための包括的なツールです。プラグインのスキャフォールディング(雛形生成)から、構造検証、静的解析(luacheck)までをカバーしています。対応プラットフォームはKobo、Kindle、PocketBook、Android、そしてデスクトップエミュレータです。ユーザーがKOReader、koplugin、_meta.lua、WidgetContainer、registerToMainMenu、Dispatcherアクション、UIManagerなどのキーワードに言及した場合、または電子書籍リーダー用のプラグイン機能追加を希望した場合に自動的に起動します。このスキルは、プラグインの雛形を生成する`new_plugin.py`スクリプトと、構造、メニュー設定、gettextの使用状況、LuaJITの構文などをチェックする`validate_plugin.py`検証スクリプトを提供します。開発者はこれらを使用することで、プラグインの基本的な品質を担保し、KOReaderのAPIやイベントシステムに従った正しい実装を行うことができます。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/aknahin/koplugin-skill/tree/HEAD/skills/koplugin-skill

Installed? Explore more コーディング&開発 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

KOReaderプラグイン開発

KOReaderのフロントエンドは、小さなウィジェットツールキット上で動作するプレーンなLua(LuaJIT)です。プラグインは <name>.koplugin/ という名前のディレクトリであり、main.lua(コード)と _meta.lua(表示情報)を含みます。ビルドステップは不要です。そのため、正しいプラグインを迅速に作成するには、以下に示す実績のある規約に従い、APIを推測する代わりにバンドルされたスクリプトで検証するのが最善の方法です。

公式ドキュメント:APIリファレンス(ソースから自動生成)およびKOReaderソースコード(plugins/ ディレクトリに約40の実プラグインがあります。plugins/hello.koplugin が最小構成です)。シグネチャが不明な場合は、モジュールのドキュメントページを確認するか、ソースを読んでください。KOReaderのAPIはリリース間で変更されるため、ドキュメントサイトが公式情報として優先されます。

ワークフロー

  1. スキャフォールディング(新規プラグイン):python3 <skill>/scripts/new_plugin.py <id> "<フルネーム>" [--dir <保存先>] コマンドで、メニューエントリ、Dispatcherアクション、設定の永続化、ライフサイクルフックがあらかじめ組み込まれたテンプレートから <id>.koplugin/ ディレクトリを作成します。ゼロから書き始めるのではなく、これを編集して開発を進めてください。
  2. 実装:このファイルに記載されているパターンを使用します。リファレンスファイルは必要なときだけ開いてください。
    • references/plugin-anatomy.md — ファイル構成、ローダールール、is_doc_only、初期化順序、メニューの sorting_hint 値
    • references/ui-widgets.md — InfoMessage、ConfirmBox、InputDialog、MultiInputDialog、Menu、ButtonDialog、SpinWidget、Notification の動作サンプル付き
    • references/events-and-lifecycle.md — onXxx ハンドラ、ブロードキャスト、スケジューリング、Dispatcher、リーダーとファイルマネージャーのコンテキスト
    • references/settings-and-storage.md — LuaSettings、G_reader_settings、ドキュメント単位の設定、DataStorage のパス
    • references/testing-and-verification.md — エミュレータ(./kodev run)、luacheck、busted テスト、実機へのインストールとログの読み取り
    • references/pitfalls.md — KOReaderをクラッシュさせたり、何も実行されない原因となるよくあるミス。実装を完了する前に一読してください。
  3. 検証(動作確認の前に必ず実行):python3 <skill>/scripts/validate_plugin.py <path/to/x.koplugin> コマンドを実行します。このスクリプトは、プラグインの構造、_meta.lua、メニューの配線、gettextの使用、LuaJITの構文(luajit -bl)、および(利用可能な場合)luacheck をチェックします。すべてのERRORを修正し、すべてのWARNを確認してください。その後、何が検証され、何が検証されなかったかを正直に報告してください。バリデーターは実行時の動作を証明できません。動作確認にはエミュレータまたは実機が必要です(テストのリファレンスを参照)。

最小限のプラグイン

-- _meta.lua
local _ = require("gettext")
return {
    fullname = _("My Plugin"),
    description = _([[プラグイン管理に表示される1文。]]),
}
-- main.lua
local Dispatcher = require("dispatcher")
local InfoMessage = require("ui/widget/infomessage")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local _ = require("gettext")

local MyPlugin = WidgetContainer:extend{
    name = "myplugin",        -- 一意のID、ディレクトリプレフィックスと一致
    is_doc_only = false,      -- true = 本が開かれているときのみロード
}

function MyPlugin:onDispatcherRegisterActions()
    Dispatcher:registerAction("myplugin_hello", {
        category = "none", event = "MyPluginHello",
        title = _("My Plugin: hello"), general = true,
    })
end

function MyPlugin:init()
    self:onDispatcherRegisterActions()
    self.ui.menu:registerToMainMenu(self)
end

function MyPlugin:addToMainMenu(menu_items)
    menu_items.myplugin = {
        text = _("My Plugin"),
        sorting_hint = "more_tools",
        callback = function() self:onMyPluginHello() end,
    }
end

function MyPlugin:onMyPluginHello()
    UIManager:show(InfoMessage:new{ text = _("Hello from my plugin") })
    return true  -- イベントを消費
end

return MyPlugin

重要なルール(とその理由)

  • ユーザーに表示されるすべての文字列を _() で囲む — KOReaderはgettextを通じて翻訳されます。囲まれていない文字列はローカライズされません。文字列の補間には T = require("ffi/util").template を使用してください(T(_("ページ %1"), n) のように。.. による連結は避けてください)。言語によって語順が異なるためです。
  • イベントは on<イベント名> という名前のメソッドです。イベントを消費した場合のみ true を返してください。そうしないと、他のウィジェット(KOReaderのコア部分を含む)がそのイベントを受信できなくなります。
  • UIスレッドをブロックしないでください。 ネットワーク呼び出し、大規模なファイルスキャン、os.execute はシングルスレッドの電子インクデバイスをフリーズさせます。長時間の処理には NetworkMgr:runWhenOnline、UIManager:scheduleIn、Trapper:wrap(サブプロセス+進捗表示)を使用してください。
  • データの永続化には LuaSettings を使用し、意図的にフラッシュしてください。 設定ファイルは DataStorage:getSettingsDir() に保存されます。変更後(または onFlushSettings 内で)必ず :flush() を呼び出してください。呼び出さないと、クラッシュやバッテリー切れでデータが失われます。
  • クリーンアップ:onCloseWidget/onCloseDocument 内で、タイマー(UIManager:unschedule(fn))や開いたウィジェットを必ず解放してください。スケジュールされたコールバックがリークすると、デバイスが頻繁に起動し、バッテリーを消耗します。
  • 電子インク対応UI:InfoMessage に timeout を設定して使用し、アニメーションは避け、リフレッシュは最小限にしてください(変更があったウィジェットにのみ UIManager:setDirty(widget, "ui") を呼び出します)。
  • logger を使用する(require("logger") し、logger.dbg/info/warn/err を使用)。print は使わないでください。loggerの出力はエミュレータでは標準出力に、実機では crash.log に出力されます。
  • オプショナルな依存関係はガードする(self.ui.statistics、self.ui.document、Device:hasFrontlight() など)。同じプラグインがファイルマネージャーや、その機能を持たないデバイスで読み込まれる可能性があります。

報告

作成または変更した内容、実行した検証コマンドとその結果、そして未検証の項目(例:「エミュレータで実行していません」)を明記してください。バリデーターまたはluacheckが利用できなかった場合は、問題なくパスしたように見せかけず、その旨を報告してください。

関連スキル