michimani.net

Todoist にタスクを追加するスクリプトを Python で書いてみた

2020-01-18

去年から Todoist でタスク管理をしているのですが、調べてみると Todoist でタスクやプロジェクトを扱うための API が用意されていることがわかりました。今回はその API を利用して Todoist にタスクを追加するスクリプトを Python で書いてみた話です。

目次

概要

Todoist のタスクは自分で作成したプロジェクトで分類することができます。どのプロジェクトにも属さないタスクは Inbox に入ります。
なので、今回のスクリプトでもプロジェクトを任意のパラメータとして指定できるようにします。

作ったもの

GitHub に置いています。

以下、簡単な解説です。

Todosit の Python モジュールを使う

Todoist API を使用するといっても、 Python のモジュールがあるのでそれを使います。
ちなみにスクリプトは Python 3.x (3.7.5) で実行するので、あらかじめ環境を作っておきます。

$ python3 -m venv .venv && source ./.venv/bin/activate

pip で Todoist のモジュールをインストールします。

$ pip install todoist-python

ドキュメントは下記ですが、見辛いです。(というかメンテナンスされてない??)

Todoist API 本体のドキュメントは下記です。

タスクを追加する

タスクを追加するスクリプトは下記のような感じです。

import argparse
import configparser
import os
import todoist

p = argparse.ArgumentParser()
p.add_argument('task_name', help='task name for new task')
p.add_argument('-p', '--project_id', default='',
               help='project ID for new task added')
args = p.parse_args()

c = configparser.ConfigParser()
c.read(os.path.dirname(os.path.abspath(__file__)) + '/../config.ini', 'UTF-8')
TODOIST_TOKEN = c.get('todoist', 'token')


def add_task(task_name, project_id=''):
    api = todoist.TodoistAPI(TODOIST_TOKEN)
    if project_id != '':
        api.add_item(task_name, project_id=project_id)
    else:
        api.add_item(task_name)

    api.commit()


if __name__ == '__main__':
    add_task(args.task_name, args.project_id)

ハイライトしている部分が todoist-python モジュールを使用している部分です。
todoist.TodoistAPI() の引数には Todoist App の access token を渡します。
access token は、個人で使うレベルであれば Todoist App を作成した際に生成される Test Token を使えば OK です。

OAuth 認証で取得する場合は下記のリポジトリを参考にしてください。

タスクの追加は TodoistAPI オブジェクトを生成して add_item() を呼びます。
task_name は必須で、 project_id は任意です。

このスクリプトは下記のように使います。

$ python add-task.py "Task Name" -p 12345678XX

-p はオプションで、指定した場合はプロジェクトに対してタスクが追加されます。省略した場合は Inbox にタスクが追加されます。

期限やリマインダーは追加せず、とりあえずタスクを追加するような形で作ってみました。

プロジェクト一覧を取得する

プロジェクトに対してタスクを追加する際には、project_id が必要になります。
Todoist の Web app だとプロジェクト名のリンクから project_id を確認することはできますが、面倒です。
なので、プロジェクト一覧も API で取得してみます。

プロジェクト一覧を取得するスクリプトは下記の通りです。

import argparse
import configparser
import json
import os
import shutil
import todoist

p = argparse.ArgumentParser()
p.add_argument('-f', '--full_sync', default='0',
               help='"1" for full sync')
args = p.parse_args()

c = configparser.ConfigParser()
c.read(os.path.dirname(os.path.abspath(__file__)) + '/../config.ini', 'UTF-8')
TODOIST_TOKEN = c.get('todoist', 'token')
CACHE_DIR = os.path.dirname(os.path.abspath(
    __file__)) + '/../caches/sync_cache/'
SYNC_CACHE_FILE = CACHE_DIR + TODOIST_TOKEN + '.json'
LIST_LINE_FORMAT = '{id: <15}: {name: <30}'


def list_projects():
    if args.full_sync == '1' and os.path.exists(CACHE_DIR):
        shutil.rmtree(CACHE_DIR)

    if os.path.exists(SYNC_CACHE_FILE):
        with open(SYNC_CACHE_FILE) as f:
            sync_data = json.load(f)
    else:
        api = todoist.TodoistAPI(TODOIST_TOKEN, cache=CACHE_DIR)
        sync_data = api.sync()

    projects = sync_data['projects']

    print('\n')
    print(LIST_LINE_FORMAT.format(id='PROJECT ID', name='PROJECT NAME'))
    print('{s:-<15}:{s:-<30}'.format(s=''))
    for project in projects:
        print(LIST_LINE_FORMAT.format(id=project['id'], name=project['name']))
    print('\n')


if __name__ == '__main__':
    list_projects()

プロジェクト一覧に限らず、 Todoist から情報を取得する際には sync() を使用します。
今回は TodoistAPI オブジェクトを生成する際に access token の他に cache というパラメータを追加しています。デフォルトでは ~/.todoist-sync/ となっているのですが、今回はこのリポジトリ内のディレクトリを指定しています。
sync() を実行すると、実行結果 (JSON) が cache で指定したディレクトリに保存されます。ファイル名は {access token}.json となります。

更新された情報を取得するにはキャッシュファイルを削除してから sync() を実行する必要があるので、スクリプト実行時のオプションで full_sync するかどうかを指定できるようにしています。

上記のスクリプトを実行すると、プロジェクトの ID と名前が出力されます。

$ python src/list-projects.py


PROJECT ID     : PROJECT NAME                  
---------------:------------------------------
12345678XX     : Inbox                         
12345678XX     : プロジェクト1                         
12345678XX     : プロジェクト2                           
12345678XX     : プロジェクト3                        

まとめ

Todoist API を利用して Todoist にタスクを追加するスクリプトを Python で書いてみた話でした。
ふとしたときにササっとタスクを追加しようと思うと、やはりターミナルから実行できたほうが便利なので、とりあえずタスク追加するだけであればこれくらい最低限の機能でいいかなーという感じです。

ただ、最近知ったんですが Slack に Todoist のアプリがあって、それを使えば Slack から同じようなことができるんですよね…。まあ、それはそれで。

todoist と Slack 連携できたのか...。https://t.co/GAqpFbSyIA

— よっしー@CBR853RR (@michimani210) January 17, 2020

comments powered by Disqus