Last active
April 14, 2016 18:14
-
-
Save dantonnoriega/4060f994f81e064a821287b893be7a10 to your computer and use it in GitHub Desktop.
A ruby script to convert a Scrivener project (.scriv) into a single Markdown (.md). NOTE: This is my first experience with Ruby. Don't ask me anything too complicated because I just took the code, inferred the needed pieces, trimmed the fat, and adjust until I got the result!
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
#!/usr/local/bin/ruby | |
# SOURCE: scrivwatch.rb by Brett Terpstra, 2011, https://gist.github.com/ttscoff/1676667 | |
# REPURPOSED AND RENAMED BY: Danton Noriega, April 2016 | |
# Instructions: | |
# 1. place 'scriv2md.rd' in same directory as .scriv project | |
# 2. give permissions to 'scriv2md.rd': | |
# chmod u+x ./scriv2md.rd | |
# 3. use! | |
# ./scriv2md.rd /path/to/document.scriv | |
require 'fileutils' | |
require 'rexml/document' | |
require 'optparse' | |
def usage | |
puts "Usage: scriv2md.rb /path/to/document.scriv" | |
exit | |
end | |
if ARGV[0] =~ /\.scriv\/?$/ | |
path = File.expand_path(ARGV[0].gsub(/\/$/,'')) | |
else | |
usage | |
end | |
# FUNCTIONS | |
def get_children(ele,path,files,depth) | |
ele.elements.each('*/BinderItem') do |child| | |
# Ignore docs set to not include in compile | |
includetag = REXML::XPath.first( child, "MetaData/IncludeInCompile" ) | |
if !includetag.nil? && includetag.text == "Yes" | |
id = child.attributes["ID"] | |
# passing type, would eventually use to control header/title output | |
type = child.attributes["Type"] | |
title = child.elements.to_a[0].text | |
file = "#{path}/Files/Docs/#{id}.rtf" | |
filepath = File.exists?(file) ? file : false | |
files << { 'path' => filepath, 'title' => title, 'depth' => depth, 'type' => type } | |
end | |
get_children(child,path,files,depth+1) | |
end | |
end | |
# Take the path to the scrivener file and open the internal XML file. | |
def get_rtf_file_array(scrivpath) | |
scrivpath = File.expand_path(scrivpath) | |
scrivx = File.basename("#{scrivpath}", ".scriv") + ".scrivx" | |
scrivxpath = "#{scrivpath}/#{scrivx}" | |
# handle cases where the package has been renamed after creation | |
unless File.exists?(scrivxpath) | |
scrivxpath = %x{ls -1 #{scrivpath}/*.scrivx|head -n 1}.strip | |
end | |
files = [] | |
doc = REXML::Document.new File.new(scrivxpath) | |
doc.elements.each('ScrivenerProject/Binder/BinderItem') do |ele| | |
if ele.attributes['Type'] == "DraftFolder" | |
get_children(ele,scrivpath,files,1) | |
end | |
end | |
return files | |
end | |
# BEGIN CONVERSION | |
sw_name = File.basename(path,".scriv") | |
sw_note = "./#{sw_name}.md" | |
# Create cache | |
sw_cache_dir = File.expand_path("./#{sw_name}-cache") | |
Dir.mkdir(sw_cache_dir) unless File.exists?(sw_cache_dir) | |
sw_cache = File.expand_path("#{sw_cache_dir}") | |
# Clear cache | |
if File.exists?(sw_cache) | |
File.delete(*Dir["#{sw_cache}/*"]) if Dir.glob("#{sw_cache}/*").length > 0 | |
Dir.rmdir(sw_cache) | |
end | |
Dir.mkdir(sw_cache) | |
files = get_rtf_file_array(path) | |
# loop through files and create copies. store in cache. | |
cachefiles = [] | |
files.each{ |f| | |
if f['path'] | |
cachefile = sw_cache + "/" + File.basename(f['path'],'.rtf') + ".md" | |
note = f['path'] ? %x{/usr/bin/textutil -convert txt -stdout "#{f['path']}"} : '' | |
leader = "" | |
notetext = leader + note + "\n\n" | |
File.open(cachefile,"w"){|cf| cf.puts notetext } | |
cachefiles.push(cachefile) | |
end | |
} | |
# export text into .md file | |
File.open(sw_note,"w"){|f| f.puts cachefiles.map{|s| IO.read(s)} } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment