最近、Todoistを使ってTodoを管理するようになったけど、いつ何を終えたかの記録が欲しい時がある。IFTTTとかZapierを使えばそれなりにはできなくもないけど、ちょっとなんかアレ(日時時間の表示とか)。。
ということで、Todoist APIとEvernote API使って自分の使いやすいようになんとかしてみる。
Todoistに関しては、Webhooksを使って完了したタスクを取得するようにする。
基本構成
作りたいアプリケーションとしては、Todoistでタスクが完了したらそれをEvernoteのノートに書き込む。このノートの単位としては1日単位で作成する。
なので、Todoist側は完了したタスクをひたすら流すだけで、Evernote側はその日のノートがあれば完了したタスクを追加で書き込んで、もしなければ新規にノートを作成して完了したタスクを書き込むということをするだけ。
こう書くだけだとめっちゃ簡単そう。(実際やると色々ハマります。。)
イメージはこんな感じでTodoistでチェックしたタスクがEvernoteのその日のノートに溜まっていく感じ(このノートは実際に自動で作ったやつ)。
Todoist
Webhookを使うためにはまずTodoist App Management
で登録する必要があるので、登録する。ここのページからCreate a new app
でアプリ名とURLを入れたらオッケー。
無事にアプリが作成できると、Webhooksのもう少し詳しい設定ができるので、callback URLとどういうEventがきた時に動作するかを設定する。自分の場合はタスクが完了した時なので、item:completed
にチェックを入れる。
他にも情報的には、暗号化に使うClient secret
ののKeyなどもあるけど割愛する。
これでTodoist自体の設定はできたのでcallback用のプログラムを実装する。
LINE botを作る訳ではないが、PythonでWebhook周りを実装するのを調べていると「Python + HerokuでLINE BOTを作ってみた」というのがあったのでこれを参考にしながら。
from flask import Flask, request
@app.route("/callback", methods=['POST'])
def callback():
body = request.get_json()
content = body["event_data"]["content"] # Taskの名前
楽ちん。
Todoistでタスクが完了したら、こっちにPOSTが投げられてきて動作して、こんな感じのが得られる。
{"event_name":"item:completed","initiator":{"is_premium":true,"image_id":"a0f7b9baf8f9a2d7266d4eb293e4ef26","id":16237325,"full_name":"hogehoge","email":"hogehoge@fugafuga.com"},"version":"8","user_id":123456,"event_data":{"is_deleted":0,"assigned_by_uid":null,"labels":[],"sync_id":123456,"section_id":null,"in_history":1,"child_order":7,"date_added":"2020-05-09T08:55:36Z","checked":1,"id":123456,"content":"Webhook test","date_completed":"2020-05-09T13:11:20Z","added_by_uid":123456,"user_id":123456,"url":"https://todoist.com/showTask?sync_id=123456&id=123456","due":null,"priority":1,"parent_id":null,"responsible_uid":null,"project_id":123456,"collapsed":0}}
必要に応じて必要な情報を取り出すので良して色々実装可能。
タスクがTodoistのどのプロジェクトのものか知りたければ、REST APIと組み合わせてやればオッケー。
import uuid, requests, json
project_id = body["event_data"]["project_id"]
response = requests.get("https://api.todoist.com/rest/v1/projects/%s" % project_id, headers={"Authorization": "Bearer %s" % API_TOKEN}).json()
project_name = response["name"]
REST APIとかはここ参照。
Todoist側はこんな感じで完了。
自分が作ったやつは一応LINE botのSignatureValidatorを参考にして、本当にTodoistからのものかどうかは確認するようにしている。
Evernote
Developer用のsandboxでテスト
開発用のsandoxがあるのでまずはこっちでアカウント作る。アカウントにサインインした状態でこのURLにアクセスするとDeveloper Tokenが得られるのでこれを使って開発していく。
pipでインストールできるevernoteのライブラリはPython2にしか対応していないというヤバい感じなので、GitHubで公開されているPython3のβ版を使う。
基本構成に書いたように、基本的にはノートがあるかチェック、新規書き込み、追加書き込みができればオッケー。
ノートがあるかのチェックに関しては、公式のドキュメントやブログ記事を参考に実装する。
import evernote.edam.notestore.ttypes as NoteStore
note_filter = NoteStore.NoteFilter()
note_filter.words = ''
note_filter.ascending = False # 降順
note_filter.notebookGuid = "xxxxxx" # notebookのguid
notes_metadata_result_spec = NoteStore.NotesMetadataResultSpec()
notes_metadata_list = note_store.findNotesMetadata(note_filter, 0, 10, notes_metadata_result_spec)
title = "Title"
for note_guid in notes_metadata_list.notes:
note = note_store.getNote(note_guid.guid, True, False, False, False)
if note.title == title:
上書き()
else:
新規作成()
こんな感じでひとまずはなんとかなる。note_filter.notebookGuid
に関しては予め調べる必要があるので注意。あとnote_filter.words
の部分に関してはここのを色々試したけど結局上手くできなかった。原因は気になるが今回の用途的には実質最新のものだけで十分なので、上にあるように何も入れずに検索するのでよしとした。
ノートがある場合とない場合の処理は下の感じ。完了したタスクを書き込みたいタイトルのノートがあれば上書きしbreakする。既定の数見てなければ最後に新規にノートを作成するという感じ。ノートの中身の抜き出しは正規表現でやってしまった。なんかもっといい方法ありそうだけど。。
import re
title = "TITLE"
note_header = '<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">'
content_start = '<en-note>'
content_end = '</en-note>'
# '<en-note>'と'</en-note>'に囲まれている部分を後方参照で取り出すのに使う
content_ext_p = re.compile("%s(.*?)%s" % (content_start, content_end))
has_note = False # 同じタイトルのノートがあるかのフラグ
for note_guid in notes_metadata_list.notes:
note = note_store.getNote(note_guid.guid, True, False, False, False)
if note.title == title:
m = content_ext_p.search(note.content)
if m:
content = m.group(1)
content += "<div>本文</div>"
note.content = note_header
note.content += content_start
note.content += content
note.content += content_end
note_store.updateNote(note)
has_note = True
break
# ノートがない場合
if not has_note:
note = Types.Note()
note.title = title
note.content = note_header
note.content += content_start
note.content += "<div>本文</div>"
note.content += content_end
note.notebookGuid = "xxxxxx" notebookのguid
note_store.createNote(note)
これでsandbox上でEvernoteに書き込むところも動くことが確認できた。
Evernote API
APIを使うにはAPI Keyが必要なのでまずはその登録をする。
開発者用のページ?にいくと、右上の方にGET AN API KEY
というのがあるのでそこ行く。そうすると下記のようなフォームがあるので適当に埋めて送信。
そうすると一瞬で登録できて下記のようにConsumer Key
とConsumer Secret
が発行されるがまだ使えない。
sandboxで開発が終われば、https://dev.evernote.com/support/ にアクセスして、API Keyのアクティベートする。
こんな感じの画面になるので、上のAPI Keyを発行する時に入れたApplicationの名前や発行されたKeyを入力していく。アクティベート完了のメールが来たら使えるらしい。
TodoistとEvernoteの連携
Todoistの部分とEvernoteの部分ができているのであとはつなげるだけ。Todoistで完了したら、その中身を解析してそれをEvernoteに書き込む。楽ちん。
再掲だけどできるとこんな感じで自動で溜めていけるようになる。(完)
コメント (1)