Created
June 5, 2019 14:15
-
-
Save kkuchta/817b2bc852152e5e770d5dd70f96abcf to your computer and use it in GitHub Desktop.
A quick tool for importing a Quiver notes library to Drafts 5
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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:
# Foo Bar
prepended to it.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.