Boostnote から Joplin に移行する

Markdown ノートアプリを Boostnote から Joplin に移行を試みました。
基本的には、

1. Boostnote のストレージの上で右クリックして「ストレージの書き出し」 - 「Export as markdown(.md)」で、マークダウン形式でエクスポートする（ストレージごとに行う）
1. Joplin で「ファイル」-「インポート」-「MD - markdown（ディレクトリ）」でインポート（1. でエクスポートしたストレージごとに行う）

という簡単な手順で移行できるのですが、一つ問題があって、作成日はエクスポートした日時（ファイルの作成日）に、更新日はインポートした日時になってしまいます。
普段、Boostnote では更新日降順に並べて最近変更したページを上に寄せて探していたので、これだと困ってしまいます。

また、一部のページは作成日を当てにしてるところもあったので、まれにですが困る場面も出てきそうです（ソフトの購入を記録したページで「このソフトいつ買ったんだっけ？」と確認したいときなど）。

というわけで、Boostnote のオリジナルのファイルのメタ情報から作成日と更新日を取得してエクスポートファイルの作成日、更新日を設定するプログラムを作ってみました（が、更新日はインポート日が設定されてしまうため、意味なかった）。

使う場合は、 `$boostnoteOriginalDir` と `$boostnoteExportDir` はご自身の環境に合わせて変更する必要があります。

なお、作成日を設定するのに `sestfile` という MacOS のコマンドを使っているため、 **Mac でしか動作しません。** Windows など他のOSで使う場合は、 setfile, touch のコマンドを変更してください。

また、このプログラムで変更できないファイルも発生しえます。
Boostnote でエクスポートすると {タイトル}.md というファイル名になるんですが、同じタイトルのページが複数あると タイトル（１）.md みたいなファイル名になってしまい、元の Boostnote 側のファイルが探せなくなってしまうためです。

```php: setCreatedAt.php
<?php

// ご自身の Boostnote のディレクトリと、エクスポートした先のディレクトリを設定してください
$boostnoteOriginalDir = "/Users/testuser/Dropbox/boostnote";
$boostnoteExportDir = "/Users/testuser/Dropbox/boostnote_export_202301";

// boostnote のストレージ一覧を取得
$storages = glob($boostnoteOriginalDir."/*", GLOB_ONLYDIR);

foreach ($storages as $storage) {
    // boostnote のストレージ配下のディレクトリ一覧を配列にする。
    $dirnames = [];
    $dirjson = json_decode(file_get_contents($storage . '/boostnote.json'), true);
    foreach ($dirjson['folders'] as $folder) {
        $dirnames[$folder['key']] = $folder['name'];
    }

    // boostnote のストレージ配下のページ一覧を取得
    $csonfiles = glob($storage . "/notes/*.cson");
    foreach ($csonfiles as $file) {
        $body = file_get_contents($file);

        // boostnote cson ファイル内のメタ情報を取得
        $folderMatches  = [];
        $createdAt = [];
        $updatedAt = [];
        $titleMatches = [];
        preg_match('/folder: "(.*)"/', $body, $folderMatches);
        preg_match('/createdAt: "(.*)"/', $body, $createdAt);
        preg_match('/updatedAt: "(.*)"/', $body, $updatedAt);
        preg_match('/title: "(.*)"/', $body, $titleMatches);

        if (! count($titleMatches)) {
            echo "no title: " . $file;
        }
        if (! count($updatedAt)) {
            echo "no updated at: ". $file;
        }

        // boostnote からエクスポートしたファイルに設定する日付やパスを作る
        $folderkey = $folderMatches[1];
        // オリジナルファイルのファイル作成日
        $createdAtBoostnote = explode("T", $createdAt[1]);
        $createdYmd = explode('-', $createdAtBoostnote[0]);
        $createdAtJoplin = sprintf('%s/%s/%s %s', $createdYmd[1], $createdYmd[2], $createdYmd[0], substr($createdAtBoostnote[1], 0, 5));

        // オリジナルファイルのファイル更新日……Joplin でインポートした日付がセットされるので無駄
        $updatedAtBoostnote = explode("T", $updatedAt[1]);
        $updatedYmd = explode('-', $updatedAtBoostnote[0]);
        $updatedAtJoplin = sprintf('%s%s%s%s', $updatedYmd[0], $updatedYmd[1], $updatedYmd[2], str_replace(':', '', substr($updatedAtBoostnote[1], 0, 5)));

        // boostnote からエクスポートしたときファイル名に、 / : が使われていると _ に変換されるので、その対応
        $joplinFilename = str_replace(['/', ':'], '_', $titleMatches[1]) . '.md';

        // boostnote からエクスポートしたファイルのパス
        $joplinFilepath = $boostnoteExportDir . '/'.basename($storage) .'/'. $dirnames[$folderkey] . '/'. $joplinFilename;

        if (! file_exists($joplinFilepath)) {
            echo 'no output file: ' . $joplinFilepath;
        }

        // ファイル作成日を設定
        system('setfile -d "'. $createdAtJoplin .'" "'. $joplinFilepath .'"');
        // ファイル更新日を設定……Joplin でインポートした日付がセットされるので無駄
        system('touch -t '. $updatedAtJoplin .' "'. $joplinFilepath .'"');
    }
}

```