2020-05-31

Ankiプラグインを作りたい#2「Pythonスクリプトを動かしてみる」

前回はAnkiのUIを起動するのに失敗したがDBが操作できれば良いので最低限のPythonでスクリプトをテストする。

Article Image

はじめに

非常に初期段階のAnkiのプラグイン作成テストをやっていく。

最も重要なことはAnkiPythonで書かれているということだ。必然的に私もPythonを書くこととなる。

Pythonは苦手なので細かいところから見ていこうと思う。

もし需要がありそうであればシリーズが継続するかもしれない。

やりたいこと

直接データベースにカードを挿入したい

Ankiのカード作成機能は十分な機能を備えているが、プログラムを使って半自動でカードを作って入れていくためには自前の開発が必要になる。

つまりAnkiのカード追加画面を起動せずとも、自前のUIからカードを半自動で生成してDBに登録するものを作りたい

アドオンとはちょっと違う?

Ankiでは「アドオン」としてAnki本体のメニューから起動できる物がある。

image-20200529161156257

例えばオーディオの再生に一時停止などをもたせたり、カードの一部を変化させるなど

起動しているAnkiの上で動作するものをアドオン

と呼ぶらしい。

今回私が作るものは、

Ankiを起動せずとも外部からカードを追加するプラグイン

である。少し混乱させたら申し訳ない。

公式サイト

どうやら2.1.20いろいろ刷新されている模様でドキュメントがわかりにくいところにあった。

Writing Anki Add-ons

インストール

以前はGitHubからコードを取ってきてそれを読み込んでプラグインを書いていたようだがPyPIなるものでパッケージをインストールさせようとしているので、コード本体をDLする必要がなくなったのだろうか?

Python初心者のためよくわからないが、なんかNode.jspackage.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を呼んでいるのでメソッドが変更されたのかもしれない。closesaveの違いは未検証。

Anki DBの仕組み

内部でSQLiteを使っている。テーブルが複雑で何をどう書き込んだらいいか分からなくなりそうだが、そのあたりはミスがないようにAnki側にUIがある。

これを通して書き込めば良いのでユーザがSQLを意識する必要はない点が素晴らしい設計。

database is lockedに注意

プログラムを書いている最中にdatabase is lockedというエラーをよく見かける。

これは単純にAnki本体が起動していてDBを使用禁止にしているためだ。

必ずAnki本体は終了して開発するように。テストでよく起動しっぱなしになっていることがある。

ノートタイプを設定

公式の説明は非常に簡素であるため古いメソッド名がそのまま使えるか試していく。

まずノートタイプを設定する。

ノートタイプとは

image-20200529221846910

これである。

カードを登録する場合はかならず必要。

表と裏だけの単純な暗記カードから、文章の空欄を埋める「穴埋め」タイプ、それ以外にもユーザーが独自にタイプを追加できるのが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に存在することが確認された => 新規作成するカードにノートタイプが関連付けできた、と言える。

これでノートの指定は完了

まだ何も書き込んでないが内部的にこれで書き込むカードのノートタイプが設定されたはずだ。

まずここまででわかったことは古いバージョンと同じメソッドが使えるだろうということが実証できた。

ここまで:カード登録の前処理まで

中途半端だがとりあえずカード前処理のいち部がこれでテストできた。

次からは実際に新規カードが登録できるかやってみたい。

まとめ

まとめると

  • GitHubAnkiをDLすることなくpipで直接Ankiのライブラリを取ってくることによりプラグイン開発が出来るようになっている
  • カードを登録するときはCollectionというモジュールを使う
  • 古いメソッドはそのまま使える(まだ検証不十分)


この記事のタグ

この記事をシェア


謎の技術研究部 (謎技研)