• UX
  • audio
  • data
  • code

Simplenote to Bear importer

With Bear 2 seemingly around the corner and the beta being great (though still very much a beta), I decided it was time to move from Simplenote.

Exporting from Simplenote gives you two things, neither of which is directly usable by Bear:

What I needed for Bear was a file for each note with correct creation and modification dates and tags at the end as hashtags. So I wrote a quick Python script that reads in the JSON file and — with some help from SetFile — outputs a file in the format I needed.

from subprocess import run
import os
import json
from datetime import datetime

# path to input JSON
in_path = os.path.join(os.environ['HOME'], 'Downloads/notes/source/notes.json')

# path to output directory. it must exist.
out_path = os.path.join(os.environ['HOME'], 'Downloads/for-bear')

# read the data
with open(in_path) as f:
    note_data = json.load(f)

datetime_format = '%m/%d/%Y %H:%M:%S.%f'
def create_note_file(datum):
    # the note text
    content = datum['content']

    # if there are tags, append them as space-separated hashtags at the end of the text
    if 'tags' in datum:
        tags_string = '\n\n'
        tags_string += ' '.join(['#' + tag for tag in datum['tags']])
        content += tags_string

    # convert times to local timezone (Simplenote is in UTC) and format for SetFile
    creation_date = datetime.fromisoformat(datum['creationDate']).astimezone()
    creation_date_str = creation_date.strftime(datetime_format)

    modification_date = datetime.fromisoformat(datum['lastModified']).astimezone()
    modification_date_str = modification_date.strftime(datetime_format)

    # write out the file
    outfile_path = os.path.join(out_path, datum['id'] + '.md')
    with open(outfile_path, 'w+') as outfile:
        outfile.write(content)

    # set the creation and modification dates
    run(['SetFile', '-d', creation_date_str, outfile_path])
    run(['SetFile', '-m', modification_date_str, outfile_path])

# iterate through the notes
for note in note_data['activeNotes']:
    create_note_file(note)

Note: Using datetime.fromisoformat() with the date format Simplenote uses requires Python 3.11+.

After running the script, import them into Bear with these settings:

Possible improvements

It would be nice to \ escape all incidental hashtags, but it wouldn’t be trivial. For example, you shouldn’t escape # followed by a non-space character inside a Markdown `#code block`.

Here’s a Gist.