BoostNoteからMarkdownを抽出する
タイトルのとおりです。 最近Typoraというマークダウンエディタを発見しまして、非常に使い勝手がいいので、今まで使っていたBoostNoteからそちらに移行しました。 その際に、BoosteNoteのデータを全部マークダウンとしてエクスポートしたいのですが、1個づつでしかできません。 本来BoostNoteからしかデータへはアクセスできず、ディスク上に保存されるファイルは乱数のような名前です。 中身もマークダウンではなくcsonと呼ばれるJSONとCoffeeScriptが合体したようなデータでした。
ということで、マークダウンを抽出するスクリプトを書きました。
使い方
コードはgithub上に置いてありますのでcloneしていただくか、コピペして依存モジュールを手動でインストールしてください。
git clone git@github.com:dorapon2000/boostnote2markdown.git pip install -r requirements.txt python boostnote_to_markdown.py
フォルダ選択のダイアログが開くので、BoostNoteのワーキングディレクトリを指定してください。ワーキングディレクトリ内にmarkdownというディレクトリができて、その中にフォルダ構造を維持したままマークダウンがエクスポートできています。
コード
github上にコードがあります。
BoostNoteは./boostenote.json
にフォルダ情報、./notes/*.cson
にノートが保存されています。*.cson
には親フォルダ名とデータがcson形式で保存されています。初めて聞いた形式だったのですが、以下のサイトに簡単な説明があります。
csonを読むモジュールはないかなと探したら、pycsonというドンピシャなものがあったのでこちらで読み取りました。使い方もjsonモジュールとほぼ同じで助かりました。
*.cson
からデータ部分だけ取り出したら、BoostNote上のフォルダ構造を再現しながらマークダウンファイルに変換するだけです。
*.cson
にかかれている親フォルダ情報(088f99dbeb2ee050cc8bみたいな)は記号なので、boostenote.json
から記号に対応するフォルダ名を取得します。
注意点
作成するマークダウンの名前はBoostNote上のタイトルとなりますが、特殊記号が使われている場合適当な文字に変換しています。
特殊文字というのは「 \/:,*?<>|」で、Windowsでファイル名に使えないものです。 私の場合、論文名をそのままタイトルにしたり日付を入れたものがあるので、「:」や「/」が引っかかりました。 記号は[colon]や[slash]というふうに置換して、とりあえずマークダウンは作成してもらうようにしています。 削除するなり適宜あとで直してください。
import os import re import json import cson import tkinter import tkinter.filedialog def convert_to_name(dir_key, conf): """Convert from directory key to directory name :param str dir_key: key in boostnote.json/folders/key :param dict conf: dictionary converted from boostnote.json :rtype: str :return: directory name """ return [meta['name'] for meta in conf['folders'] if meta['key'] == dir_key] def sanitize(str_): """Sanitize string for Windows target: \\/:,*?<>| :param str str_: string you want to sanitize :rtype: string :return: sanitized string """ if re.search('[\\/:,*?<>|]', str_) is None: return str_ str_ = str_.replace('\\', '[backslash]') str_ = str_.replace('/', '[spash]') str_ = str_.replace(':', '[colon]') str_ = str_.replace(',', '[hyphen]') str_ = str_.replace('*', '[star]') str_ = str_.replace('?', '[question]') str_ = str_.replace('<', '[less]') str_ = str_.replace('>', '[greater]') print(f'"{str_}" is sanitized') return str_ def extract_md_from_BoostNote(): """Extract Markdown from BoostNote """ cnt_success = 0 cnt_skip = 0 root = tkinter.Tk() root.withdraw() msg = 'Select your BoostNote working directory' boostnote = tkinter.filedialog.askdirectory(title=msg) conf_json = os.path.join(boostnote, 'boostnote.json') with open(conf_json) as f: conf = json.load(f) notes = os.path.join(boostnote, 'notes') for file in os.listdir(notes): with open(os.path.join(notes, file)) as f: note = cson.load(f) if note['type'] != 'MARKDOWN_NOTE': cnt_skip += 1 continue key = note['folder'] folder = convert_to_name(key, conf) title = note['title'] content = note['content'] if note['isTrashed']: folder = 'Trash' folder = sanitize(folder) title = sanitize(title) output_dir = os.path.join(boostnote, 'markdown', folder) os.makedirs(output_dir, exist_ok=True) output_file_name = title + '.md' output_file = os.path.join(output_dir, output_file_name) with open(output_file, 'w') as f: f.write(content) cnt_success += 1 print('=============================================') print('Converting BoostNote to Markdown is Success!!') print(f'success: \t{cnt_success}') print(f'skip: \t{cnt_skip}') if __name__ == '__main__': extract_md_from_BoostNote()