Kobitoのサポートが終了してしまったので、Quiverに移行するスクリプトを書いた

はじめに

すでにご存じの方も多いかもしれませんが、Qiita投稿にも使えるMarkdownエディタのKobitoが突然サポートを終了しました。

Kobito for Mac / Windowsの提供及びユーザーサポートを終了します - Qiita Blog

個人的にはKobitoのヘビーユーザーだったので、この発表は大変驚いただけでなく、慌てて次の移行先を探すはめになりました。

いろいろ検討した結果、僕はQuiverというツールに移行することに決めました。

この記事ではKobitoからQuiverに移行するために作成したRubyスクリプトを紹介します。

イントロダクション

僕のKobitoの利用目的

僕は以下のような目的でKobitoを利用していました。

  • Qiitaに投稿する記事の執筆、および投稿
  • 外部に公開しない個人的な技術メモや備忘録の保存

前者のQiitaの投稿については最悪Webから実行すればいいのですが、後者の個人的な技術メモや備忘録はローカルで必要なときにさっと書いて、さっと検索できる快適な操作性がほしいです。

毎回Webにアクセスして限定共有の記事を開いて・・・というのはかなり不便なので、この方法はできるだけ避けたいと思いました。

Quiverについて

Twitterで「Kobitoのいい移行先を知りませんか?」と質問してみたところ、@tamadonさんがQuiverの存在を教えてくれました(参考)。

調べてみたらKobitoとほぼ同じ使い方ができ、僕のニーズにかなり合っていたので、新しい移行先としてQuiverを使うことにしました。

screenshot1.png

ちなみにQuiverの価格は$9.99です。ただし、無料試用版も用意されていて、有料版との違いは画面の右下にFree Trialのラベルが表示される点だけのようです(参考)。

Screen Shot 2017-12-31 at 7.28.28.png

移行スクリプトの概要

今回作成した移行スクリプトは以下のような処理を実行します。

  • Kobitoから全記事をMarkdown形式(mdファイル)でエクスポートする。
  • Quiverにインポートした記事に対して、適切なタイトルとタグを更新する。

mdファイルからQuiverへの一括インポートはQuiverからGUI操作で実行します。
また、オリジナルのKobitoデータベースやQuiverのjsonファイルを誤って破壊しないよう、いったん手元のディレクトリにコピーしてから処理をするようにしています。

ソースコード

移行スクリプト(Ruby製)はGitHubに置いているので、ここから取得してください。

https://github.com/JunichiIto/kobito-to-quiver

免責事項

このスクリプトを使って何らかの損害が発生しても、作者は責任を負いません。

制限事項

Qiita::Team用のKobitoデータの移行はこのスクリプトの動作対象外です。(作者がQiita::Teamを利用していないため)

セットアップ

このスクリプトはRuby 2.4系で動作確認しています。
スクリプトをダウンロードしたらbundle installを実行して、必要なgemをインストールしてください。

# Ruby 2.4 or higher
$ ruby -v
ruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-darwin17]

$ bundle install

移行スクリプトの使い方

このスクリプトの使い方は以下のとおりです(コマンド一発で全部完了!・・・ではなく、何回かに分けてコマンドを実行する必要があります)。

Kobitoのdbファイルをdbディレクトリにコピーする

$ cp ~/Library/Containers/com.qiita.Kobito/Data/Library/Kobito/Kobito.db ./db

KobitoのデータをMarkdownとしてエクスポートする

以下のコマンドを実行するとoutputディレクトリに記事がMarkdownファイルとしてエクスポートされる。

$ bundle exec rake export

なお、記事にtempというタグが付いていると出力をスキップするようにしている。

/lib/kobito_exporter.rb
def output_files(items)
  init_dir
  items.each do |pk, item|
    puts "#{pk} / #{item.title}"
    # 出力をスキップ
    next if item.temp?
    path = File.join(OUTPUT_DIR, "#{pk}.md")
    File.write(path, item.body)
  end
end

また、KobitoからQiitaに送信した記事はファイルの冒頭にQiitaへのリンクを付与している。

QuiverにMarkdownファイルをインポートする

Quiverを起動 > File > Import > Markdown で、上で出力したMarkdownをインポートする。

screen shot 2017-12-30 at 20 31 34

この時点ではタイトルは数字で、タグはインポートされない。

Quiverのqvnotebookディレクトリをコピーする

上でインポートしたNotebookを確認する。(以下の例で言うと、"FAEFB235"で始まる作成日時が一番若いqvnotebookディレクトリがそれ)

$ ls -lt ~/Library/Containers/com.happenapps.Quiver/Data/Library/Application\ Support/Quiver/Quiver.qvlibrary/ | grep .qvnotebook
drwxr-xr-x@ 787 jit  staff  25184 Dec 30 20:31 FAEFB235-9A6F-4771-AF03-6685EEC2212E.qvnotebook
drwxr-xr-x@   3 jit  staff     96 Dec 30 18:57 Trash.qvnotebook
drwxr-xr-x@ 787 jit  staff  25184 Dec 30 18:55 B6A3F526-F4F6-4D18-9D76-F7D122BD1C1E.qvnotebook
drwxr-xr-x@   3 jit  staff     96 Dec 30 06:03 Inbox.qvnotebook
drwxr-xr-x@  15 jit  staff    480 Dec 30 05:59 Tutorial.qvnotebook

qvnotebookディレクトリにコピーする。

$ cp -r ~/Library/Containers/com.happenapps.Quiver/Data/Library/Application\ Support/Quiver/Quiver.qvlibrary/(対象のqvnotebook).qvnotebook ./qvnotebook

qvnotebook内のファイルをアップデートする

以下のコマンドを実行すると、各記事のタイトルとタグが更新される。

$ bundle exec rake update_qvnotebook

なお、Qiitaに投稿したことのある記事はqiita-publishedのタグも付与されます。

/lib/quiver_updator.rb
def update_meta_json(dir)
  update_json(dir, 'meta.json') do |json_data, item|
    json_data['title'] = item.title
    json_data['created_at'] = item.created_at.to_i
    json_data['updated_at'] = item.updated_at.to_i
    json_data['tags'] = item.tags
    # Qiitaに投稿されていれば"qiita-published"のタグも付ける
    if item.qiita_published?
      json_data['tags'] << 'qiita-published'
    end
  end
end

qvnotebookディレクトリを元に戻す

念のためQuiverを終了させる。

続いて、先ほどのqvnotebookディレクトリを元に戻す。

$ cp -rf ./qvnotebook/(対象のqvnotebook).qvnotebook ~/Library/Containers/com.happenapps.Quiver/Data/Library/Application\ Support/Quiver/Quiver.qvlibrary/

移行が成功したことを確認する

Quiverを起動し、インポートした記事のタイトルやタグが更新されていることを確認する。(以下のスクリーンショットではインポート時に作成されたNotebook名をKobitoに変えています)

screen shot 2017-12-30 at 18 58 08

余談:Kobitoサポート終了に関する不満

ここからは完全に余談になりますが、今回のKobitoのサポート終了は、Kobito&Qiitaのヘビーユーザーの1人として非常に不満を覚えるものでした。

周知のしかたが弱い

Kobitoのサポート終了は12月の上旬にアナウンスされていたのですが、僕はつい最近(12月の終わり)までまったく気づいていませんでした(QiitaもKobitoもほぼ毎日のように使っているというのに!)。

毎週送られてくるランキングメールに載っていたのは2017年12月6日送信分の1回だけです。しかも僕はいつもぱっとランキングを見に行くので、この記述にまったく気づいていませんでした。

Screen Shot 2017-12-30 at 21.43.33.png

僕みたいに気づかない人もいるので、1回だけでなく、もっと何週間にも渡って告知すべきだったのではないでしょうか?

そもそも、ランキングメールの一部として告知しておしまい、ではなく、Qiitaユーザー全員(またはKobitoユーザーだけを抽出できるならKobitoユーザーのみ)に「【重要】Kobitoサポート終了のお知らせ」のような独立した通知メールを送信すべきだったと思います。

メールだけではなく、Qiitaサイトにもどこか目立つ場所にKobitoサポート終了のお知らせを載せておくべきだったとも思います。

僕はKobitoもQiitaもかなり頻繁に使っているヘビーユーザーですが、今回のお知らせにはまったく気づきませんでした。

ちなみに僕が気づいたのは、はてなブックマーク経由です(なんで公式サイトじゃなく、こんな感じの悪い記事経由でサポート終了に気づかなあかんねん・・・)。

告知から終了までが短すぎる

以下のサポート終了の告知は2017年12月4日に公開されています。

Kobito for Mac / Windowsの提供及びユーザーサポートを終了します - Qiita Blog

告知ページでは次のようなスケジュールが載っています。

  • 2017/12/8:Kobito for MacのMac App Storeでの新規ダウンロードの終了
  • 2017/12/27:Kobito for Mac, Windows提供サイトの閉鎖
  • 2017/12/27:ユーザーサポートの終了

しかし、サポート終了までの期間があまりにも短いのではないでしょうか?
告知からサポート終了までわずか20日ちょっとしかありません。
個人的な感覚では最低でも半年ぐらいの猶予があっても良いと思います。

そもそも僕がサポート終了に気づいたのは12月29日です。
そうです、気づいたときにはすでにサポートが終わっていたのです!
App Storeにアクセスしても、もうKobitoアプリの再ダウンロードもできない状況でした。

ある日突然、サポートの終了に気づいたときの僕の気持ちたるや・・・!!💢

エクスポートや移行手段が提供されていない

さらに、告知ページのどこを見てもデータのエクスポートや移行手段に関する言及がありません。

僕はもともとKobitoのデータがSQLiteで管理されていたのを知っていたので、最悪DBからSQLでデータが引き抜けることは知っていましたが(そしてKobitoユーザーならITリテラシーはそれなりに高いでしょうが)、それでも全員が全員、そういった操作ができるわけではないと思います。

僕みたいにKobitoに「秘伝のタレ」的なデータを保存している場合は、最悪二度と取り出せないデータになってしまいかねません。

ユーザーサポートを終了する前に、運営側はデータのエクスポートや移行手段に関する情報提供をすべきだった、と強く感じます。

まとめ

というわけで、この記事ではKobitoからQuiverに移行するスクリプトの紹介と、最後にKobitoサポート終了に関する不満点を述べました。

まあ、こういった終了のしかたを見る限り、今回のサポート終了には何か「やんごとなき理由」が背景にあったと考えるのが自然かもしれません。
ですが、今現在公式に出ている情報だけでは、そうした理由があったのかなかったのかすらハッキリしません。

今回のサポート終了の件に関しては、正直「Incrementsさん、この先も大丈夫?」とQiitaの将来に不安を覚えたのも事実です。
この先、Incrementsさんがこのような僕の不安を払拭してくれることを願います。

158contribution

移行先、Quiverにされたのですね!
2年前くらいから使っていて結構気に入っています。

そして僕の記事へのリンクありがとうございます:relaxed:
過去記事のいいねがいきなり増えたと思ったらこの記事起因だったのか...