Org-modeとGoogle calendar間で予定をやりとりするorg-gcal.elというのを作りました


久し振りにちゃんとしたelispを書いた気がするので、ちゃんと紹介しておこうと思います。リポジトリはこちらになります。

作ったきっかけ

予定を長いことGoogleカレンダーで管理しています。ブラウザ上の見た目もすっきりしていて、とても使いやすいのですがスケジュールの入力はマウスをカチカチさせることが多くストレスフルでした。

そこは手になじんだEmacsから入力した方が便利なはずです。@kiwanamiさんのkiwanami/emacs-calfw と連携して動くelispなどを書いたりして、どうにかこうにか入力してました。

calfwからGoogleカレンダーを編集するcalfw-gcal.elを書いてみた – sheephead

ところが、これもいろいろとボトルネックがありました。Googleカレンダーのデータをcalfwに取りこむのにcalfw-icalを使っていたのですが、取りこむ際にどうにもブロックしてしまいます。また、ローカルにキャッシュを持たない設計になっていたので、日々ブロックしておりました。

拙作calfw-gcal.elもいろいろ問題がありました。最初はgoogleclを使ってデータの送信をしていたのですが、Windows環境だと設定が結構面倒でした。なのでgdata-python-clientを直接触るように改変もしてみたのですが、Windows特有のPythonまわりのトラブルなどもあり、グダグダになっておりました。滅せよ Windows。

org-mode とスケジュールの連携も興味の対象でした。自分のところでは、タスクとスケジュールを分けて整理していて、しかもタスク管理はorg-modeでやっていました。そういったこともあって、スケジュールとタスクをorg-modeで統一して管理したいなあと思っておりました。

org-gcal.elでしたかったこと

もっとも重要視したのはサクサク動くことです。同じようなことを目的としているアプリにorg-caldavというのがありましたが、この条件を満たすものではありませんでした。

本質的な目的でないものとすれば、ここ数年で出てきた便利そうなライブラリを使ってみたいというのもありました。MELPAができたおかげでライブラリを導入するコストはかなり軽減されました。その影響か、MELPAでも便利そうなライブラリがかなり登録されています。

Org-modeは以前から開発は活発でしたが、最近の大きな変化とすれば昔から懸案だったOrgフォーマットへのアクセスAPIがかなり統一され、Orgアプリ開発者にとってとても良い環境になりつつあります。

と例のごとく前置きがだいぶ長くなってきたので、そろそろ使い方について書いておきます。

インストール

MELPAでお願いします。

設定

org-gcal.elではGoogleカレンダーとの通信にGoogleが提供してるAPIを使っていて、事前にプロジェクトの登録とOAuthによる認証をすませておく必要があります。 まずは、Google Developers Consoleでプロジェクトを作って、 client IDと client secretを取得してください。

Google+ APIの事例ですが以下の記事が参考になるかもしれません。

天使やカイザーと呼ばれて » OAuth2.0によるGoogle+ APIのアクセス方法

次に、Google カレンダーの設定ページでカレンダーIDを確認します。デフォルトではGmailのメールアドレスがカレンダーIDとなっています。後は設定ファイルに次のように書くとよいです。

(require 'org-gcal)
(setq 
 org-gcal-client-id "your-id-foo.apps.googleusercontent.com"
 org-gcal-client-secret "your-secret"
 ;;カレンダーIDをキー、スケジュールを取りこむOrgファイルをvalueとするalist
 ;;複数登録可
 org-gcal-file-alist '(("your-mail@gmail.com" .  "~/schedule.org")
                       ("another-mail@gmail.com" .  "~/task.org")))

使い方

準備しているコマンドは主に二つだけです。

org-gcal-fetch でGoogleカレンダーのスケジュールをOrgファイルに持ってきます。

org-gcal-post-at-point で現在のポイントにあるOrgエレメントをGoogleカレンダーに送信します。編集した既存のスケジュールを送信する場合も同様の操作となります。

トークンの更新は古くなったら自動的に更新されるようになっているのですが、たまに通信に失敗するなどしてトークンの更新がうまくいかなかったりします。 その際は org-gcal-refresh-token を実行してトークンを更新してみてください。

カスタマイズ

デフォルトでは当日から過去30日、未来60日の予定をfetchするようになっています。変更した場合は org-gcal-down-days org-gcal-up-days を適宜変えてください。

org-gcal-down-days を越えた過去のスケジュールは自動的にArchiveされるようになっています。 org-gcal-auto-archive をnilにしておくとArchiveされなくなります。

org-gcal.elによる通信成功の可否を通知する仕組みを実装しています。 デフォルトでは、ミニバッファに表示されるようになっていますが org-gcal-use-notifications をtにしておくとnotifications.elを介したデスクトップ通知、 org-gcal-use-gntp をtとすることでgntp.elによるデスクトップ通知に切り変わります。

gntp.elについては、いずれ詳しく紹介したいと思いますが、Growlが用いているデスクトップ通知用のプロトコルを使って通知するアプリです。自分のところでは、主にこれを使っています。

ただ、デスクトップ通知の機能については、alertを使った仕組みに切りかえることを検討しているところでいろいろと変わってくるかもしれません。

使ってみた印象

自分のところでは非常に軽快に動いています。要因としては、GoogleAPIを通じて最低限の情報しかやりとりしていないということと、deferred.elによるasyncがとても有効だったと感じました。

スケジュールの情報をローカルに保存することができるようになったのでcalfwとの連携も非常に快適になりました。この連携については、calfw-orgにちょこっとcontributeさせてもらったので、別の機会に紹介したいと思います。

ただ、アプリの登録やIDの取得がちょっと面倒に感じます。公開可能なclient IDと client secretがあれば、この手間はなくなるのでどなたかclient IDと client secretを提供していただけるとありがたいです。

作ってみた印象

久し振りに作ったので、時間はかかりましたが非常に快適に作ることができました。なんといっても@tkf さんのemacs-requestが非常に素晴らしかったです。deferredにも対応していてたいした苦労もせずasyncなアプリを作ることができました。

org-modeに標準で添付されるようになったOrg-elementもOrgファイルをパースするのにとても助かりました。

request.elについてはtkfさんがこれまた素晴しいドキュメントを作られているので、説明することもないですが、Org-elementについてはいずれ詳しく紹介する機会を作りたいと思います。

今後の予定など

まずは、いろいろな方に使っていただいてfeedbackを得たいと思っています。機能面ではスケジュールの削除、スケジュールの同期に相当する機能がありません。モチベーションが高いうちにどうにかしたいのですが、本業が年度末モードに入ってしまうと停滞してしまうかもしれませんがご容赦ください。