読者です 読者をやめる 読者になる 読者になる

詩と創作・思索のひろば

ドキドキギュンギュンダイアリーです!!!

blogsync ではてなブログのエントリをローカルと同期する

http://hatenablog.com/images/theme/og-image-1500.gif

こんにちは、はてなチーフアプリケーションエンジニアの id:motemen です。今日ははてなエンジニアアドベントカレンダー2014 の 22 日目として、はてなブログのエントリをローカルと同期するツール blogsync を紹介します。昨日は id:tarao による gulpで依存関係を考慮した自動コンパイル でした。

はてなブログは CMS としても非常に便利に使えるウェブサービスで、実際Mackerel のヘルプもはてなブログで運用しています。ドキュメントのようなコンテンツはいろいろな人が触り、頻繁に書き換えるので変更履歴を残したいところ、また慣れたエディタで編集したいものですが、はてなブログ単体にそういう機能は当然ありません。そこで個人的に はてなブログ AtomPub を用いて、はてなブログのエントリをローカルのファイルシステムに保存するツールを Go で書いて、使ってみています。いったんファイルに保存してしまえば、Git なり Dropbox なりで編集履歴を残しておくのは容易です。

インストール方法

go get github.com/motemen/blogsync

使い方

設定

まず初めに設定ファイルを書きます。ホームディレクトリ以下の .config/blogsync/config.yaml に、以下のような YAML を置いてください。

motemen.hatenablog.com:
  username: motemen
  password: <API KEY>
default:
  local_root: /Users/motemen/Dropbox/Blog

各項目の意味は次のとおり:

  • キー(例: motemen.hatenablog.com): ブログのドメイン。はてなブログのダッシュボードからブログの設定画面などを開いたとき、URL に含まれる文字列です。技術的には AtomPub API における「ブログID」になります。
    • "default" という名前のキーは特別で、すべてのブログの項目のデフォルト値として扱われます。
  • <blog>.username: そのブログに投稿するはてなユーザの ID。
  • <blog>.password: そのブログに投稿するための API キー。
  • <blog>.local_root: ブログのエントリを格納するパスのルート。

エントリをダウンロードする(blogsync pull

設定が完了したら、以下のコマンドを実行すると当該のブログに投稿しているエントリがその URL ローカルに保存されます。

% blogsync pull <blog>

この際保存されるファイルのパスは、エントリの URL ベースにしたものとなります。blogsync pull motemen.hatenablog.com した結果だとこんな感じになります(分かりやすいように少し省略しています):

/Users/motemen/Dropbox/Blog/motemen.hatenablog.com/
└── entry
    ├── 2014
    │   ├── 05
    │   │   ├── 12
    │   │   │   └── gulp,_TypeScript,_Browserify_で_Chrome_拡張を書く.md
    │   │   └── 14
    │   │       └── datetime-sh.md
    │   ├── 06
    │   │   ├── 01
    │   │   │   └── introducing-ghq.md
    │   │   ├── 03
    │   │   │   └── git-hub-sync-repo-info.md
…

以降は blogsync pull すると、ブログエントリとローカルのファイルをつき合わせ、新しいエントリのみダウンロードされるようになります。

ファイルのフォーマット

エントリのファイルはエントリのメタデータではじまり、空行ののち本文が続く、というフォーマットです:

- Title:   まだmechanizeで消耗してるの? WebDriverで銀行をスクレイピング(ProtractorとWebdriverIOを例に)
- Date:    2014-10-01T08:30:00+09:00
- URL:     http://motemen.hatenablog.com/entry/2014/10/01/scrape-by-protractor-webdriverio
- EditURL: https://blog.hatena.ne.jp/motemen/motemen.hatenablog.com/atom/entry/8454420450066634133

今日はスクレイピングの話をします。…

今のところメタデータの内容は以下の5つ。(ハイフンではじめているのは、Markdown として解釈したとき見栄えがよいようにです)

  • Title: エントリのタイトル。
  • Date: ブログに表示されるエントリの投稿日時。2006-01-02T15:04:05-07:00 といったフォーマットを期待しています。
  • URL: エントリの URL。これは自動的に与えられ、書き換えても効果はありません。
  • EditURL: エントリを一意に区別する URL。名前のとおり、AtomPub の編集用の URL です。
  • Draft: この値が "yes" のとき、下書きとして扱われます。

メタデータをまったく指定しない場合、1行目から本文がはじまるものとみなされます。

エントリを更新する(blogsync push

ひとたびエントリをダウンロードしたら、そのファイルを編集することで記事を更新できます。

% blogsync push <path/to/file>

このエントリの下書きを書いている今なら、こんな感じですね:

% blogsync push ~/Dropbox/blog/motemen.hatenablog.com/entry/2014/12/22/blogsync.md
       GET ---> https://blog.hatena.ne.jp/motemen/motemen.hatenablog.com/atom/entry/8454420450077731341
       200 <--- https://blog.hatena.ne.jp/motemen/motemen.hatenablog.com/atom/entry/8454420450077731341
       PUT ---> https://blog.hatena.ne.jp/motemen/motemen.hatenablog.com/atom/entry/8454420450077731341
       200 <--- https://blog.hatena.ne.jp/motemen/motemen.hatenablog.com/atom/entry/8454420450077731341
     store /Users/motemen/Dropbox/blog/motemen.hatenablog.com/entry/2014/12/22/blogsync.md

ファイルがリモートの記事よりも新しくない場合は、更新リクエストは行われません。

エントリを投稿する(blogsync post

まだはてなブログ側に存在しない記事を投稿する場合は、投稿用のコマンドで記事を投稿します。

% blogsync post <blog> < <path/to/file>

blogsync post は標準入力からエントリの内容を受けとって投稿し、投稿されたエントリに対応するファイルをダウンロードします。その後は新しく作成されたファイルを編集し、push することでエントリの編集を続けられます。

このコマンドでは --title=<TITLE>--draft という引数によって記事タイトルや下書き状態の指定を行えるのでこんな風に雑に、ターミナルから書き始めることもできます…

% blogsync post --draft --title=blogsync motemen.hatenablog.com
さてかきはじめるか…
^D

おわりに

すでに便利な blogsync ですが、常用するにはまだ足りていない点がいくつかあります。

  • 記事 URL を任意に指定できない
  • 予約投稿できない

などなど。もし興味を持った方は、リポジトリを覗いてみてください。

blogsync の開発にあたっては、別チームでありながらはてなブログチームに投げたプルリクエストが小気味よくマージされてリリースされる様子を眺めることができました。はてなでは日々リリースされるプロダクトが大好きなエンジニアを募集しています。

明日のアドベントカレンダーは id:y_uuki です。