Kobito 内の記事の HTML をタグごとにフルダンプする


Kobito で書いている内容を、リッチテキストのまま他へコピーしたくなることがあるのですが、どうも Kobito のプレビューはフォーマット情報まではコピーしてくれないようですので、ブラウザで表示しようと思い、Kobito データを HTML ファイル群へダンプするスクリプトを書きました。

以下のように、~/kobito/ ディレクトリの下からタグで辿って行くような構造でダンプします。

* ~/kobito/
	* .stamp … 前回実行時のタイムスタンプ
	* .md/ … Markdown 形式のデータ
		* {zitem.zkey}.md
	* .html/ … HTML 形式のデータ
		* {zitem.zkey}.html
		* それと、Kobito の JS や CSS
	* _all/
		* 全 HTML へのリンク
	* {ztag.zname}/ … タグに属する HTML へのリンク
	* ...

タイムスタンプを記録していますので、`.html` 以下のファイルに関しては、更新があったものだけを再生成します。

タグ以下は、差分を考えるのが面倒だったので、テンポラリディレクトリに全生成してから、rsync(1) で差分をコピー・削除しています。

最初はタグディレクトリ下のリンクにはシンボリックリンクを用いていたのですが、それだと ~/kobito/.html/ へコピーした Kobito の CSS が見えないのと、Dropbox が実ファイルとして同期しやがるので、実 HTML ファイルにして、`meta` タグの `Refresh` か JavaScript の `location.replace()` で飛ばすようにしました。

[kobito_dump ～ GitHub Gist](https://gist.github.com/knaka/a35243302ca657a9331b)

~~~~bash:kobito_dump
#!/bin/bash
# -*- coding: utf-8 -*-

# db=~/Library/Kobito/Kobito.db # DB path for older version of Kobito
db=~/Library/Containers/com.qiita.Kobito//Data/Library/Kobito/Kobito.db
dir=~/kobito/

encode_filename() {
  name="$@"
  name="${name//%/%37}"
  name="${name//\//%47}"
  echo -n "$name"
}

# link_html() {
#   target="$1"
#   link="$2"
#   ln -sf "$target" "$link"
# }

link_html() {
  target="$1"
  link="$2"
  title="$3"
  cat <<EOF > "$link"
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<title>Link to "$title"</title>
<script type="text/javascript">
location.replace('$target');
</script>
<meta http-equiv="Refresh" content="0; URL=$target" />
</head>
<body>
<noscript>
<p><a href="$target">$title</a></p>
</noscript>
</body>
</html>
EOF
}

IFS=$'\t'

mddir="$dir"/.md
htmldir="$dir"/.html
mkdir -p $dir $mddir $htmldir
rsync -azr /Applications/Kobito.app/Contents/Resources/ "$htmldir"/
if test -r "$dir"/.stamp
then
  stamp=$(cat $dir/.stamp)
else
  stamp=0
fi
date -u "+%s" > "$dir"/.stamp.new

echo Generating MD and HTML files.
echo "SELECT zkey, zin_trash IS NOT NULL FROM zitem WHERE 
 strftime('%s', '2001-01-01') + zupdated_at > $stamp;" |
  sqlite3 -separator $'\t' $db |
  while read -r key in_trash
  do
    if test "$in_trash" = "1"
    then
      rm -f $mddir/$key.md $htmldir/$key.html
    else
      echo "SELECT zraw_body FROM zitem WHERE zkey = '$key';" |
        sqlite3 $db > $mddir/$key.md
      echo "SELECT zbody FROM zitem WHERE zkey = '$key';" |
        sqlite3 $db > $htmldir/$key.html
    fi
  done
echo Done.

echo Generating links to HTML files.
tmpdir=$(mktemp -d /tmp/XXXXXX)
mkdir -p $tmpdir/_all/
echo "SELECT ztag.zname, zitem.zkey, zitem.ztitle FROM zitem, z_1tags, ztag
 WHERE zitem.zin_trash IS NULL AND ztag.z_pk = z_1tags.z_2tags AND
 zitem.z_pk = z_1tags.z_1items;" |
  sqlite3 -separator $'\t' $db |
  while read -r tag key title
  do
    path_title=$(encode_filename "$title")
    link_html ../.html/$key.html "$tmpdir"/_all/"$path_title.html" "$title"
    path_tag=$(encode_filename "$tag")
    mkdir -p $tmpdir/"$path_tag"
    link_html ../.html/$key.html "$tmpdir"/"$path_tag"/"$path_title.html" "$title"
  done
echo Done.
echo Copying temporary files to target directory.
rsync -azr --delete --exclude '.*' $tmpdir/ "$dir"/
rm -fr $tmpdir
echo Done.

mv "$dir"/.stamp.new "$dir"/.stamp
~~~~