Skip to content

Instantly share code, notes, and snippets.

@kkuchta
Created June 5, 2019 14:15
Show Gist options
  • Save kkuchta/817b2bc852152e5e770d5dd70f96abcf to your computer and use it in GitHub Desktop.
Save kkuchta/817b2bc852152e5e770d5dd70f96abcf to your computer and use it in GitHub Desktop.
A quick tool for importing a Quiver notes library to Drafts 5
require 'erb'
class Note
def initialize(qvnote)
@root_dir = qvnote
end
def parse
cell_string = cells.map do |cell|
case cell['type']
when 'markdown'
cell['data']
when 'text'
cell['data']
when 'code'
'```\n' + cell['data'] + '\n```'
when 'latex'
# Don't really know what to do with this
cell['data']
when 'diagram'
# Don't really know what to do with this
cell['data']
else
raise "unknown cell type #{cell['type']}"
end
end.join("\n\n")
# Make the title a markdown heading, since Drafts doesn't support titles
'# ' + title + "\n\n" + cell_string
end
def title
metadata['title']
end
def tags
metadata['tags']
end
private
def cells
content['cells']
end
def metadata
@metadata ||= JSON.parse(File.read(File.join(@root_dir, 'meta.json')))
end
def content
@content ||= JSON.parse(File.read(File.join(@root_dir, 'content.json')))
end
end
class Notebook
def initialize(qvnotebook)
@root_dir = qvnotebook
end
def parsed_notes
notes.map do |note|
# Since drafts doesn't support folders, use the folder (notebook) name as
# a tag
{
text: note.parse,
tags: note.tags + [name]
}
end
end
def trash?
name == 'Trash'
end
private
def notes
Dir.glob('*.qvnote', 0, base: @root_dir).map do |note_dir|
Note.new(File.join(@root_dir, note_dir))
end
end
def name
metadata['name']
end
def metadata
@metadata ||= JSON.parse(File.read(File.join(@root_dir, 'meta.json')))
end
end
class Importer
def initialize(qvlibrary)
@root_dir = qvlibrary
end
def import_all
parsed_notes = notebooks.flat_map do |notebook|
notebook.parsed_notes
end
parsed_notes.each do |note|
note[:tags] << 'imported_from_quiver'
end
parsed_notes.each do |note|
save_to_drafts(note[:text], note[:tags])
end
end
private
def notebooks
Dir.glob('*.qvnotebook', 0, base: @root_dir).map do |notebook_dir|
Notebook.new(File.join(@root_dir, notebook_dir))
end.reject(&:trash?)
end
def save_to_drafts(text, tags)
`open '#{drafts_url(text, tags)}'`
end
def drafts_url(text, tags)
tags_query = tags.map { |tag| "tag=#{ERB::Util.url_encode(tag)}" }.join('&')
"drafts5://create?text=#{ERB::Util.url_encode(text)}&#{tags_query}"
end
end
unless qvlibrary_file = ARGV.pop
puts 'Usage: ruby importer.rb /some/path/Quiver.qvlibrary'
exit
end
Importer.new(qvlibrary_file).import_all
@kkuchta
Copy link
Author

kkuchta commented Jun 5, 2019

Run with ruby importer.rb /some/path/Quiver.qvlibrary. This'll insert all your non-trash Quiver.app notes into Drafts.app.

Note that this isn't a perfect import. Some things have to get translated:

  • Note titles are converted to markdown titles. So if your note is titled 'Foo Bar', the note body will have # Foo Bar prepended to it.
  • Quiver has notebooks (folders), which Drafts doesn't. Notebook titles, then, are just added as additional tags in drafts.
  • Quiver supports a bunch of types - markdown, text, etc. Drafts' api doesn't support setting the note type, so it'll just be whatever your default is.
  • Multiple cells in notes are just appended together.

Also, an 'imported_from_quiver' tag is added to each imported note so you can easily delete all the imported notes if something's mangled.

It took 46 seconds to run (on my newish MBP) for about 6k notes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment