Importing notes from Bear

Bear, my note-taking app of choice, stores its notes in a SQLite database at ~/Library/Group Containers/9K33E3U3T4.net.shinyfrog.bear/Application Data/database.sqlite. I use the following query to get the content out:

SELECT
  *,
  datetime(zmodificationdate, 'unixepoch', '31 years')
    AS zmodificationdate2
FROM
  zsfnote
WHERE
  ztrashed == 0 AND zarchived == 0

The zmodificationdate2 derived column takes care of the way timestamps are stored in Bear: these are Core Data timestamps, which are the number of seconds elapsed since January 1st, 2001.

Once I have the query, I can load the notes from the database:

notes = db[query].map do |row|
  {
    id: row[:ZUNIQUEIDENTIFIER],
    title: row[:ZTITLE],
    text: row[:ZTEXT],
    modification_date: row[:zmodificationdate2]
  }
end

I don’t use the note ID directly. The IDs of Bear notes are quite long (longer than UUIDs). I hash the UUIDs, then Avoid naughty words in hex digest strings by changing the set of characters, and finally take the first 15 characters, dash-separated in groups of 5 characters, as the new ID, e.g. 7fmkz-pkwxt-kcxvt, which I use in note URLs.

Importing images

Images live in ~/Library/Group Containers/9K33E3U3T4.net.shinyfrog.bear/Application Data/Local Files/Note Images/. I don’t copy all images all as-is though, but rather copy an image whenever it occurs in a published note.

Where an imagine appears in a note, the note content has [image:<PATH>], with <PATH> being the path to the image relative to the Note Images/ directory mentioned above. For example: To do: This is not correct as of Bear 2.0 anymore.

[image:C6BEE843-E18A-4C98-82F0-EFA6499274E2-2641-0000089C7C19B1C6/Screen Shot 2022-10-27 at 21.03.30.png]

With that relative path known, I copy the image into my site’s content/notes/images/ directory.

A Nanoc filter then replaces those [image:<PATH>] markup directives with HTML img elements. The filter looks like this:

    content.gsub(/\[image:([^\]]+)\]/) do |match|
      partial_path = Regexp.last_match[1]
      relative_path = '/notes/images/' + partial_path

      %[<figure><img src="#{relative_path}"></figure>]
    end

I have not figured out how to add alt text to the images, but perhaps that’s a high ask for a note-taking app.

References