暇人じゃない
——  Technology

Evernote, Notion, Scrapbox のノートを Claude Code で Obsidian に移行した

2023 年頃から、ノート管理に Obsidian を使っている。それまでは Evernote や Notion、Scrapbox を使っていたのだけど、そのノートを Obsidian に取り込めていなかった。 今回、Claude Code を使って Obsidian に移行した。

各ツールのデータをプレーンテキストに変換する

まずは各ツールのデータを Obsidian で扱えるようにプレーンテキストに変換した。

  • Evernote: evernote2md で変換 (以前書いた記事)
  • Notion: アーカイブをエクスポート
  • Scrapbox: アーカイブをエクスポート

Scrapbox 以外は Markdown フォーマット。Scrapbox のアーカイブは Scrapbox フォーマットになっていて、今振り返ると最初に Markdown に変換しておけばよかったと思う。

作業手順

大まかに以下の手順で移行した。

  1. マージ用の Obsidian Vault (Merge Vault) を作って、その中に Evernote, Notion, Scrapbox のノートを移行
    • フォルダ構造がツールによってバラバラでも「Obsidian のフォルダ構造に合わせてファイルを再整理して」とお願いすれば大体良い感じにやってくれる
  2. Merge Vault の中身を確認して、不要なノートを削除したり整理
  3. Merge Vault の中身をメインの Obsidian Vault に移行
    • 移行計画書を作成し、トップレベルのフォルダを 1 つずつ処理

細かいところは省略するが、基本的に Claude Code の Plan Mode で計画を立てながら、Claude Code に言われるがままに作業した。 いつでも元に戻せるようにバックアップは必ず取っておこう。

CLAUDE.md

以下のような CLAUDE.md を作って作業した。ハマったところは都度 CLAUDE.md を更新してもらった。

# 作業ルール

- バッチ処理を行う場合は Python スクリプトを使う (Bash を使わない)
  - 移行する場合は Dry-run でユーザーが移行元と移行先を確認してから実行するフローにする
- 画像などのファイルは `_attachments` フォルダ以下に保存
  - 例: `Journal/YYYY/YYYY-MM/YYYY-MM-DD.md` で参照されているファイルは `Journal/YYYY/YYYY-MM/_attachments/` 以下に保存
- 添付ファイル名と Markdown 本文中の参照を照合する場合は、Unicode 正規化の差異を吸収する
  - 照合の前にファイル名・本文の双方を NFC/NFD 両方に正規化してから突き合わせる

# 移行ルール

- 参照先の実体が見つからないリンク切れ画像 (移行元に存在しない添付など) は、埋め込みを削除して HTML コメントに置き換える
  - 例: `![[_attachments/xxxx.png]]``<!-- 画像欠落: 元 _attachments/xxxx.png -->`
- PDF がリンク形式になっている場合、画像と同様に埋め込み表示に変換して移行する
  - 例: `[](foo.pdf)``![](foo.pdf)`
- frontmatter 直後の本文先頭が H1 見出しで、その内容がファイル名または frontmatter の `title` と一致する場合は、タイトルと重複するため H1 行を削除する (直後の空行も詰める)
  - `_``/` などの表記差は無視して一致とみなす
  - 一致しない場合は削除しない
- Merge フォルダで、フォルダ名とその直下の `.md` ファイル名が一致し、かつフォルダの中身が同名ファイル 1 つの場合は、フォルダを削除してファイルをフラット化する
  - 例: `Foo/Foo.md``Foo.md` (`_attachments` があれば一緒に親階層へ移動)
  - 同名ファイルに加えて他のノートやサブフォルダを含む場合 (フォルダノート型) は対象外とし、そのまま残す
  - ファイル名一致の判定では `_``/` などの表記差は無視する

## 添付ファイルの変換ルール

- 画像の縮小・変換ルール
  - JPEG/PNG を WebP に変換する
  - 大きい画像は長辺 2048px を上限に縮小する (既に 2048px 以下のものはそのまま)
- PDF の圧縮ルール
  - 大きい PDF は Ghostscript で圧縮する
  - 画像は 150 DPI にダウンサンプルする
  - 再処理時は圧縮済み PDF を対象外にする。判定はファイルに `gs-compressed-150dpi` または `GPL Ghostscript` (gs の Producer) を含むかで行う
  - 対象は 1MB 超かつ未圧縮 (マーカー無し) の PDF のみ
  - ページ数を gs の `pdfpagecount` で元と一致確認する

## ノート構造

Obsidian の構造を正にする。構造が判断できない場合は、ユーザーに選択肢を確認すること。

- Notion の DB の索引ノート (DB のビュー/リンク集にあたるノート) は移行しない。
- 複数の旧ツールから同名プロジェクトを 1 フォルダに統合する場合、各ノートに ` (Evernote)` などの suffix を付けるのはファイル名が実際に衝突するノートだけにする。基本はツール名を付けず原名のまま残す。
  - 衝突判定は macOS の大文字小文字非区別 (case-insensitive) に合わせる (例: `foo.md``Foo.md` は衝突扱い)。

## データのフォルダ

旧ツールのデータは下記のフォルダに配置。

- Evernote: `/path/to/Evernote`
- Notion: `/path/to/Notion`
- Scrapbox: `/path/to/Scrapbox`

データを Obsidian に移行する前に、マージ用のフォルダ (`/path/to/Merge`) に移動してから確認する。

ポイント

  • 移行スクリプトは Python で書く
    • シェルスクリプトでも良いけど、Python のほうが精度が良い気がしている
  • 添付ファイルの置き場所を Obsidian の設定に合わせる
  • 添付ファイルのサイズを削減する方針を書く
    • 画像を WebP に変換して、PDF はダウンサンプリング。(ここには書いてないが、動画は H.265 に変換)
  • 各ツールのデータのパスを指定
    • プロンプトで毎回パスを指定する必要がない

約 6,200 件のノートと、約 500MB の添付ファイルが移行された。これから整理が必要だけど、昔の日記とかやっていたことを読めるのが嬉しい。(On This Day プラグインを使って古い日記を振り返っている)

マージしたノートを活用できる形に整理するのも今後やりたい。