Converting SuperNote files to PDF

Posted on September 2, 2022

Writing is my primary mode of note taking and at the beginning of the pandemic, I switched from paper notebooks to digital notebooks. My primary note taking devices are SuperNote A6X, Boox Max3, and iPad Pro using Notability App (in that order, though I do prefer iPad for reviewing papers etc. because of the speed). I prefer the writing experience on Supernote, but I do miss one of the software features of Boox: In Boox, every time I save a note file, it is automatically converted to PDF and stored in a pdf directory which mirrors the layout of the notes directory. There is no such feature in SuperNote. Notes have to converted manually and get exported to a flat directory.

Now, the reason that I want automatic pdf conversion is that PDF is a universal format and can be read on any device. In contrast, all the digital notebook devices or apps use a propriety format, which cannot be read easily on other devices. That’s why I like the automatic conversion on Boox. That (along with DropSync to instantly sync the converted file) means that I always have access to the latest version of my notebooks everywhere. On SuperNote, I need to remember to manually convert the file. (And also manually since the device, but that’s another story).

I recently discovered a script called supernote-tool, which parses the SuperNote .note format and converts it to PDF. So, I wrote a simple Rakefile to convert all .note files to .pdf files.

I sync SuperNote files using Dropbox and Supernote creates a directory Dropbox/Supernote which has the following structure:

Dropbox/Supernote
├── Document
├── EXPORT
├── INBOX
├── MyStyle
├── Note
└── SCREENSHOT

By default, all the note files are in the Note sub-directory. I wanted to create a sibling directory called pdfs, which mirrors the layout of the Notes directory and converts each .note file to .pdf. I wanted to write this as a Makefile so that I can periodically run the conversion via cron, but writing complext makefiles is always wild goose chase on google. So, I decided to write it as a Rakefile, although I haven’t touched ruby in almost 15 years. Here is the file:


require 'fileutils'
require 'rake/clean'

SN = "$HOME/Software/supernote-tool/venv/bin/supernote-tool"

SRC_DIR = "Note"
PDF_DIR = "pdfs"

SRC = FileList["#{SRC_DIR}/**/*.note"]
PDF = SRC.pathmap("%{^#{SRC_DIR},#{PDF_DIR}}X.pdf")

directory PDF_DIR

task :pdf => PDF

rule '.pdf' => proc {|f| f.pathmap("%{^#{PDF_DIR},#{SRC_DIR}}X.note")} do |t|
    mkdir_p t.name.pathmap("%d")
    sh %Q{#{SN} convert -t pdf --pdf-type vector -a "#{t.source}" "#{t.name}"}
end

task :default => :pdf

CLEAN.include(PDF)

The tricky part of the writing this was to figure out how to make sure that the converted pdfs are saved in a parallel directory with the same directory structure as the notes directory. I was hoping that there was an easy way to do it using rules, but I could not figure it out. So, I followed a very rudimentary method.

First, collect the names of all .note files:


SRC = FileList["#{SRC_DIR}/**/*.note"]

and then change the root directory and the extension:


PDF = SRC.pathmap("%{^#{SRC_DIR},#{PDF_DIR}}X.pdf")

This looks like black magic, but it fairly simply once your read the documentation of pathmap.

Then, I specify a rule to generate the .pdf file. To do so, I need to specify that the corresponding .note file is a dependency of the .pdf file, I run the conversion if the .note file is newer than the .pdf file. Rake has this super cool feature that you don’t have to explicitly list all target names; it can regex against a specified string. See, for example, this blog post. However, this automatic dependency specification only works when the source and the destination are in the same directory. But I want the .note and .pdf files to be in parallel directories. Again, I found that the simplest way to do this was to invert the conversion used to generate the name of the .pdf file:


rule '.pdf' => proc {|f| f.pathmap("%{^#{PDF_DIR},#{SRC_DIR}}X.note")} do |t|
    mkdir_p t.name.pathmap("%d")
    sh %Q{#{SN} convert -t pdf --pdf-type vector -a "#{t.source}" "#{t.name}"}
end

And that’s it! I added a cron task so that this script is run every 6 hours.

There are a few things that I don’t like about this setup:

Nontheless, at present, this simple Rakefile scratches the itch.


This entry was posted in Eink and tagged supernote, supernote-tool, rake, cron, max3, a6x, boox.