org-modeをGTDに使う方法 #2 Googleカレンダーへエスクポート

org-mode に含まれている agendaを抽出して、Googleカレンダーにエクスポートする方法を紹介する。なお、iCalendar形式のエクスポートはorg-modeのバージョンに依存して若干異なる。今回は、最新版のversion 6.33f を用いた。

手順の概要は次の通りである。

  1. orgファイルを iCalendar形式にエクスポートする。
  2. エクスポートされたファイルをGoogleカレンダー形式に変換する。
  3. 変換されたファイルをGoogleカレンダーにインポートする。
  4. 上記を自動化する。

以下に各手順について説明する。

orgファイルをiCalendar形式にエクスポートする。

Emacs で次のコマンドを実行すると、org-modeの内容がiCalendar形式のファイルにエクスポートされる(キーバインドC-c C-x c )。

M-x org-export-icalendar-combine-agenda-files 

エクスポート先はデフォルトでは~/org.ics である。エクスポート先を陽に指定することもできる。その場合は.emacs に次のように設定する。

(setq org-combined-agenda-icalendar-file "~/org/calendar/org.ics") 

どのイベントをエクスポートするかも議論があるところだろう。ここでは、次のように設定した。

(setq org-icalendar-include-todo nil)
(setq org-icalendar-use-deadline '(event-if-todo event-if-not-todo))
(setq org-icalendar-use-scheduled '(event-if-todo event-if-not-todo))

カレンダーをエクスポートするコマンドは、上記を含めて3つ存在する。選択肢として、

#0000FF;">C-c C-e i org-export-icalendar-this-file: 現在のファイルをiCalendar形式に変換し、元ファイルと同じディレクトリに保存する。
#0000FF;">C-c C-e I org-export-icalendar-all-agenda-files: C-c C-e i と同じ。ただし、org-agenda-filesで指定された全てのファイルを個別のiCalendar 形式のファイルに保存する。
#0000FF;">C-C C-e c org-export-icalendar-combine-agenda-files: C-c C-e I と同じ。ただし、ひとつのファイルにまとめて保存される。

MaciCalにインポートするならば、ここで生成されたファイルを用いれば良い。

エクスポートされたファイルをGoogleカレンダー形式に変換する。

GoogleカレンダーはiCalendar形式に完全に準拠しているわけではない。開始時刻と終了時刻が指定されたイベントでは、両時刻をJSTなどのローカルタイムで指定すると正しく動作しない。正しく動作させるためには、開始時刻と終了時刻をUTCで指定する必要がある。

そこで母国語(いや、第2外国語かな?)であるperlを用いて簡単な変換スクリプトを書いた。

#! /usr/bin/perl -w
# Usage : org2googleCalendar.pl org.ics
use Time::Local;
use File::Copy;
use strict;

my $TZOFFSET = 9;		# offset of timezone in hours

my $fin = $ARGV[0];
my $tmp = "/tmp/orgical-$$";		#  temporary file
open FIN, "$ARGV[0]" or die $!;
open FOUT, ">$tmp" or die $!;

while (my $line = <FIN>) {
    chop $line;
    if ( my ($tag, $d, $t) = ($line =~ /^(DTSTART|DTEND):(\d{8})T(\d{6})$/) ) {
	my ($year, $mon, $mday) = ($d =~ /^(\d{4})(\d{2})(\d{2})$/);
	my ($hour, $min, $sec)  = ($t =~ /^(\d{2})(\d{2})(\d{2})$/);
	my $time = timelocal( $sec, $min, $hour, $mday, $mon-1, $year);
	$time = $time - $TZOFFSET*60*60;
	($sec, $min, $hour, $mday, $mon, $year) = localtime($time);
	print FOUT $tag, ':', sprintf("%04d%02d%02d", $year+1900, $mon+1, $mday), "T", 
	sprintf("%02d%02d%02d", $hour, $min, $sec),"Z\n";
    } else {
	print FOUT $line, "\n" ;
    }
}
close FIN;
close FOUT;
move $tmp, $fin or die $!;

このスクリプトを org2googleCalendar.pl という名前にし、次のコマンドで変換する。

% org2googleCalendar.pl ~/org/calendar/org.ics

変換されたファイルをGoogleカレンダーにインポートする。

Googleカレンダーの [追加] → [カレンダーのインポート] でインポートする。OrgModeというカレンダーがインポートされる。

自動化する。

自動化の概要を下図に示す。

今回の課題は図中において、母艦、ウェブサーバ、Googleカレンダーが連携する経路である。
連携の概要を説明する。母艦はウェブサーバのディスクをNFSでマウントしてる。iCalendar形式のファイルをエクスポートするディレクトリ~/public_html/org/をウェブサーバ上につくり、このディレクトリを母艦からNFS越しに~/org/calendar/としてシンボリックリンクしている。これにより、母艦で~/org/calendar/にファイルを書き出すと、ウェブサーバ上の~/public_html/org/にファイルが作成される。このファイルのありか(URL)をGoogleカレンダーに登録すると、Googleカレンダーは登録したファイルをHTTP *2で定期的に覗き、Googleカレンダーが更新される。

ファイル名はなるべくヘンテコな名前をつけ、かつ定期的に変更することを勧める。GoogleカレンダーがiCalendarファイルをpullするときに認証を経ないからだ。とは言え、ここでは簡潔さを優先して、ファイル名をorg.icsとした。

ちなみに、図中、リモートマシンからインターネット越しにSSH(tramp) *1 で母艦にアクセスする方法は、前回のエントリーで紹介した。

.emacs の設定

(1) iCalendar形式にエクスポートして、(2) Googleカレンダーに合うように変換して、という作業を F12 キーひとつで行うことにする。そのためには、つぎのコードを.emacsに書けば良い。

(defun org-push-daily-my ()
  (interactive)
  (org-export-icalendar-combine-agenda-files)
  (call-process "org2googleCalendar.pl" nil nil nil
                (expand-file-name org-combined-agenda-icalendar-file)))
(define-key global-map [f12] 'org-push-daily-my)
ウェブサーバの設定

母艦からウェブサーバのディレクトリを見ると次のようになる。

$ ls -a ~/org/calendar/
.  ..  .htaccess  index.html  org.ics

(1) org.ics はエクスポートされたiCalendarファイルである。(2) index.htmlはディレクトリ内部のリストを隠すために置いた空ファイルである。(3) .htaccess文字コードセットを指定した。いわば文字化け対策である。ファイルの内容は次の通りである。

AddType text/calendar .ics
AddCharset utf-8 .ics

この.htaccessにより、HTTPヘッダ部に "Content-Type: text/calendar; charset=utf-8"が送信される。Charsetを指定しないとGoogleカレンダーが文字化けする。
ウェブサーバとして、MobileMeが提供するidiskのPublicフォルダを利用したいところだが、idiskでは.htaccessの設置に対応しておらず、文字化けの問題を回避できない。idiskを用いたうまい方法を模索中である。

Googleカレンダーの設定

[追加]→[urlで追加]で、iCalendarファイルのありかを示すURLを登録する。

次回

次回のエントリーではモバイル環境を紹介する。