非常に初期段階のAnkiのプラグイン作成テストをやっていく。
最も重要なことはAnkiはPythonで書かれているということだ。必然的に私もPythonを書くこととなる。
Pythonは苦手なので細かいところから見ていこうと思う。
もし需要がありそうであればシリーズが継続するかもしれない。
直接データベースにカードを挿入したい
Ankiのカード作成機能は十分な機能を備えているが、プログラムを使って半自動でカードを作って入れていくためには自前の開発が必要になる。
つまりAnkiのカード追加画面を起動せずとも、自前のUIからカードを半自動で生成してDBに登録するものを作りたい。
Ankiでは「アドオン」としてAnki本体のメニューから起動できる物がある。
例えばオーディオの再生に一時停止などをもたせたり、カードの一部を変化させるなど
起動しているAnkiの上で動作するものをアドオン
と呼ぶらしい。
今回私が作るものは、
Ankiを起動せずとも外部からカードを追加するプラグイン
である。少し混乱させたら申し訳ない。
どうやら2.1.20いろいろ刷新されている模様でドキュメントがわかりにくいところにあった。
以前はGitHubからコードを取ってきてそれを読み込んでプラグインを書いていたようだがPyPIなるものでパッケージをインストールさせようとしているので、コード本体をDLする必要がなくなったのだろうか?
Python初心者のためよくわからないが、なんかNode.jsのpackage.jsonっぽさを感じる。
めんどいので書いてある物を全部普通にインストールしてみる。
subprocess.check_call(["pip", "install", "mypy", "anki", "ankirspy", "aqt"])コマンドプロンプトには上をそのまま変換して
pip install mypy anki ankirspy aqt何の問題もなくインストール完了
とりあえずデータベースに直接カードを挿入していく場合は確かCollectionというAnkiのモジュール?から行う。(Pythonではモジュールと言っていいのだろうか?)
Ankiのライブラリそのものをpipでインストールしたので以前とは違いスクリプトはどこに置いてもいいはず。適当にデスクトップにつくったフォルダにファイルを作ってみる。
test.py
from anki import Collection
col = Collection("C:/Users/{ユーザ名}/AppData/Roaming/Anki2/ユーザー 1/collection.anki2"){ユーザ名}となっている箇所は御存知の通りwindows側のユーザ名で各自で違うので注意。
一方で最後のディレクトリの「ユーザ 1」はAnki側のデフォルトがこの名前なので複数のユーザーで同一のプログラムを使っていなければ概ね皆同じかと思う。変更している人もいるかもしれないので要注意。
またディレクトリはバックスラッシュではなくスラッシュである点/に注意。
collection.anki2というファイルを指定する。
python test.pyとりあえずエラーがでなければ成功
次の表示が出ている
reverting to stock json
よくわからないが解説にはcol.close()を行わないとDBへの変更は破棄されると書いてあるので、そのまま変更せず戻したよということだろうか。
とりあえず成功のようだ。
昔のコードを見ると書き込みを確定する時にはcol.addNote, col.saveを呼んでいるのでメソッドが変更されたのかもしれない。closeとsaveの違いは未検証。
Anki DBの仕組み内部でSQLiteを使っている。テーブルが複雑で何をどう書き込んだらいいか分からなくなりそうだが、そのあたりはミスがないようにAnki側にUIがある。
これを通して書き込めば良いのでユーザがSQLを意識する必要はない点が素晴らしい設計。
database is lockedに注意プログラムを書いている最中にdatabase is lockedというエラーをよく見かける。
これは単純にAnki本体が起動していてDBを使用禁止にしているためだ。
必ずAnki本体は終了して開発するように。テストでよく起動しっぱなしになっていることがある。
公式の説明は非常に簡素であるため古いメソッド名がそのまま使えるか試していく。
まずノートタイプを設定する。
これである。
カードを登録する場合はかならず必要。
表と裏だけの単純な暗記カードから、文章の空欄を埋める「穴埋め」タイプ、それ以外にもユーザーが独自にタイプを追加できるのがAnkiの特徴。
ちなみに英語リファレンスでもノートのことをnoteと表記するがプログラム上はmodelという単語を使うようなので混乱しないように。
先程のコードに次の行を追加してみよう。
anki_model_name = "すごいノート"
modelBasic = col.models.byName(anki_model_name) # ノートタイプの指定はこの2行
col.decks.current()['mid'] = modelBasic['id'] # ノートタイプの指定はこの2行2行目は今はこうするものだとおぼえておく。
これで実行すると
TypeError: 'NoneType' object is not subscriptableこのエラーになるはずだ。上記の画像から分かるように「すごいノート」というノートが存在しない。
では「すごいノート」を「基本」に変えて実行してみよう。
reverting to stock json今度はエラーなし。
「基本」というノートがAnki側のDBに存在することが確認された => 新規作成するカードにノートタイプが関連付けできた、と言える。
まだ何も書き込んでないが内部的にこれで書き込むカードのノートタイプが設定されたはずだ。
まずここまででわかったことは古いバージョンと同じメソッドが使えるだろうということが実証できた。
中途半端だがとりあえずカード前処理のいち部がこれでテストできた。
次からは実際に新規カードが登録できるかやってみたい。
まとめると
GitHubのAnkiをDLすることなくpipで直接Ankiのライブラリを取ってくることによりプラグイン開発が出来るようになっているCollectionというモジュールを使う