lib/review/epubmaker.rb in review-1.2.0 vs lib/review/epubmaker.rb in review-1.3.0
- old
+ new
@@ -18,10 +18,11 @@
include REXML
def initialize
@epub = nil
@tochtmltxt = "toc-html.txt"
+ @buildlogtxt = "build-log.txt"
end
def log(s)
puts s unless @params["debug"].nil?
end
@@ -34,15 +35,17 @@
end
def produce(yamlfile, bookname=nil)
load_yaml(yamlfile)
bookname = @params["bookname"] if bookname.nil?
+ booktmpname = "#{bookname}-epub"
+
log("Loaded yaml file (#{yamlfile}). I will produce #{bookname}.epub.")
File.unlink("#{bookname}.epub") if File.exist?("#{bookname}.epub")
- FileUtils.rm_rf(bookname) if @params["debug"] && File.exist?(bookname)
-
+ FileUtils.rm_rf(booktmpname) if @params["debug"] && File.exist?(booktmpname)
+
Dir.mktmpdir(bookname, Dir.pwd) do |basetmpdir|
log("Created first temporary directory as #{basetmpdir}.")
log("Call hook_beforeprocess. (#{@params["hook_beforeprocess"]})")
call_hook(@params["hook_beforeprocess"], basetmpdir)
@@ -61,53 +64,109 @@
log("Call hook_afterbackmatter. (#{@params["hook_afterbackmatter"]})")
call_hook(@params["hook_afterbackmatter"], basetmpdir)
push_contents(basetmpdir)
- copy_images(@params["imagedir"], "#{basetmpdir}/images")
- copy_images("covers", "#{basetmpdir}/images")
- copy_images("adv", "#{basetmpdir}/images")
- copy_images(@params["fontdir"], "#{basetmpdir}/fonts", @params["font_ext"])
+ if !@params["verify_target_images"].nil?
+ verify_target_images(basetmpdir)
+ copy_images(@params["imagedir"], basetmpdir)
+ else
+ copy_images(@params["imagedir"], "#{basetmpdir}/images")
+ end
+
+ copy_resources("covers", "#{basetmpdir}/images")
+ copy_resources("adv", "#{basetmpdir}/images")
+ copy_resources(@params["fontdir"], "#{basetmpdir}/fonts", @params["font_ext"])
+
log("Call hook_aftercopyimage. (#{@params["hook_aftercopyimage"]})")
call_hook(@params["hook_aftercopyimage"], basetmpdir)
@epub.import_imageinfo("#{basetmpdir}/images", basetmpdir)
@epub.import_imageinfo("#{basetmpdir}/fonts", basetmpdir, @params["font_ext"])
- epubtmpdir = @params["debug"].nil? ? nil : "#{Dir.pwd}/#{bookname}"
- Dir.mkdir(bookname) unless @params["debug"].nil?
+ epubtmpdir = @params["debug"].nil? ? nil : "#{Dir.pwd}/#{booktmpname}"
+ Dir.mkdir(booktmpname) unless @params["debug"].nil?
log("Call ePUB producer.")
@epub.produce("#{bookname}.epub", basetmpdir, epubtmpdir)
log("Finished.")
end
end
def call_hook(filename, *params)
if !filename.nil? && File.exist?(filename) && FileTest.executable?(filename)
- system(filename, *params)
+ if ENV["REVIEW_SAFE_MODE"].to_i & 1 > 0
+ warn "hook is prohibited in safe mode. ignored."
+ else
+ system(filename, *params)
+ end
end
end
- def copy_images(imagedir, destdir, allow_exts=nil)
- return nil unless File.exist?(imagedir)
+ def verify_target_images(basetmpdir)
+ @epub.contents.each do |content|
+ if content.media == "application/xhtml+xml"
+
+ File.open("#{basetmpdir}/#{content.file}") do |f|
+ Document.new(File.new(f)).each_element("//img") do |e|
+ @params["force_include_images"].push(e.attributes["src"])
+ if e.attributes["src"] =~ /svg\Z/i
+ content.properties.push("svg")
+ end
+ end
+ end
+ elsif content.media == "text/css"
+ File.open("#{basetmpdir}/#{content.file}") do |f|
+ f.each_line do |l|
+ l.scan(/url\((.+?)\)/) do |m|
+ @params["force_include_images"].push($1.strip)
+ end
+ end
+ end
+ end
+ end
+ @params["force_include_images"] = @params["force_include_images"].sort.uniq
+ end
+
+ def copy_images(resdir, destdir, allow_exts=nil)
+ return nil unless File.exist?(resdir)
allow_exts = @params["image_ext"] if allow_exts.nil?
FileUtils.mkdir_p(destdir) unless FileTest.directory?(destdir)
- recursive_copy_images(imagedir, destdir, allow_exts)
+ if !@params["verify_target_images"].nil?
+ @params["force_include_images"].each do |file|
+ unless File.exist?(file)
+ warn "#{file} is not found, skip." if file !~ /\Ahttp[s]?:/
+ next
+ end
+ basedir = File.dirname(file)
+ FileUtils.mkdir_p("#{destdir}/#{basedir}") unless FileTest.directory?("#{destdir}/#{basedir}")
+ log("Copy #{file} to the temporary directory.")
+ FileUtils.cp(file, "#{destdir}/#{basedir}")
+ end
+ else
+ recursive_copy_files(resdir, destdir, allow_exts)
+ end
end
- def recursive_copy_images(imagedir, destdir, allow_exts)
- Dir.open(imagedir) do |dir|
+ def copy_resources(resdir, destdir, allow_exts=nil)
+ return nil unless File.exist?(resdir)
+ allow_exts = @params["image_ext"] if allow_exts.nil?
+ FileUtils.mkdir_p(destdir) unless FileTest.directory?(destdir)
+ recursive_copy_files(resdir, destdir, allow_exts)
+ end
+
+ def recursive_copy_files(resdir, destdir, allow_exts)
+ Dir.open(resdir) do |dir|
dir.each do |fname|
next if fname =~ /\A\./
- if FileTest.directory?("#{imagedir}/#{fname}")
- recursive_copy_images("#{imagedir}/#{fname}", "#{destdir}/#{fname}", allow_exts)
+ if FileTest.directory?("#{resdir}/#{fname}")
+ recursive_copy_files("#{resdir}/#{fname}", "#{destdir}/#{fname}", allow_exts)
else
if fname =~ /\.(#{allow_exts.join("|")})\Z/i
Dir.mkdir(destdir) unless File.exist?(destdir)
- log("Copy #{imagedir}/#{fname} to the temporary directory.")
- FileUtils.cp("#{imagedir}/#{fname}", destdir)
+ log("Copy #{resdir}/#{fname} to the temporary directory.")
+ FileUtils.cp("#{resdir}/#{fname}", destdir)
end
end
end
end
end
@@ -132,18 +191,19 @@
else
htmlfile = "part_#{part.number}.#{@params["htmlext"]}"
build_part(part, basetmpdir, htmlfile)
title = ReVIEW::I18n.t("part", part.number)
title += ReVIEW::I18n.t("chapter_postfix") + part.name.strip if part.name.strip.present?
- write_tochtmltxt(basetmpdir, "0\t#{htmlfile}\t#{title}")
+ write_tochtmltxt(basetmpdir, "0\t#{htmlfile}\t#{title}\tchaptype=part")
+ write_buildlogtxt(basetmpdir, htmlfile, "")
end
end
part.chapters.each do |chap|
build_chap(chap, base_path, basetmpdir, yamlfile, nil)
end
-
+
end
end
def build_part(part, basetmpdir, htmlfile)
log("Create #{htmlfile} from a template.")
@@ -156,20 +216,26 @@
if part.name.strip.present?
f.puts <<EOT
<h2 class="part-title">#{part.name.strip}</h2>
EOT
end
-
+
f.puts <<EOT
</div>
EOT
f.puts footer
end
end
def build_chap(chap, base_path, basetmpdir, yamlfile, ispart=nil)
filename = ""
+
+ chaptype = "body"
+ chaptype = "part" unless ispart.nil?
+ chaptype = "pre" if chap.on_PREDEF?
+ chaptype = "post" if chap.on_POSTDEF?
+
if !ispart.nil?
filename = chap.path
else
filename = Pathname.new(chap.path).relative_path_from(base_path).to_s
end
@@ -187,52 +253,57 @@
id = sprintf("chap%02d", @bodycount)
end
end
htmlfile = "#{id}.#{@params["htmlext"]}"
+ write_buildlogtxt(basetmpdir, htmlfile, filename)
log("Create #{htmlfile} from #{filename}.")
level = @params["secnolevel"]
-
- if !ispart.nil?
- level = @params["part_secnolevel"]
- else
- level = @params["pre_secnolevel"] if chap.on_PREDEF?
- level = @params["post_secnolevel"] if chap.on_POSTDEF?
- end
+# TODO: It would be nice if we can modify level in PART, PREDEF, or POSTDEF.
+# But we have to care about section number reference (@<hd>) also.
+#
+# if !ispart.nil?
+# level = @params["part_secnolevel"]
+# else
+# level = @params["pre_secnolevel"] if chap.on_PREDEF?
+# level = @params["post_secnolevel"] if chap.on_POSTDEF?
+# end
+
stylesheet = ""
if @params["stylesheet"].size > 0
stylesheet = "--stylesheet=#{@params["stylesheet"].join(",")}"
end
- system("review-compile --yaml=#{yamlfile} --target=html --level=#{level} --htmlversion=#{@params["htmlversion"]} --epubversion=#{@params["epubversion"]} #{stylesheet} #{@params["params"]} #{filename} > \"#{basetmpdir}/#{htmlfile}\"")
+ system("#{ReVIEW::MakerHelper.bindir}/review-compile --yaml=#{yamlfile} --target=html --level=#{level} --htmlversion=#{@params["htmlversion"]} --epubversion=#{@params["epubversion"]} #{stylesheet} #{@params["params"]} #{filename} > \"#{basetmpdir}/#{htmlfile}\"")
- write_info_body(basetmpdir, id, htmlfile, ispart)
+ write_info_body(basetmpdir, id, htmlfile, ispart, chaptype)
end
- def write_info_body(basetmpdir, id, filename, ispart=nil)
+ def write_info_body(basetmpdir, id, filename, ispart=nil, chaptype=nil)
headlines = []
# FIXME:nonumを修正する必要あり
Document.parse_stream(File.new("#{basetmpdir}/#{filename}"), ReVIEWHeaderListener.new(headlines))
first = true
headlines.each do |headline|
headline["level"] = 0 if !ispart.nil? && headline["level"] == 1
if first.nil?
- write_tochtmltxt(basetmpdir, "#{headline["level"]}\t#{filename}##{headline["id"]}\t#{headline["title"]}")
+ write_tochtmltxt(basetmpdir, "#{headline["level"]}\t#{filename}##{headline["id"]}\t#{headline["title"]}\tchaptype=#{chaptype}")
else
- write_tochtmltxt(basetmpdir, "#{headline["level"]}\t#{filename}\t#{headline["title"]}\tforce_include=true")
+ write_tochtmltxt(basetmpdir, "#{headline["level"]}\t#{filename}\t#{headline["title"]}\tforce_include=true,chaptype=#{chaptype}")
first = nil
end
end
end
def push_contents(basetmpdir)
File.open("#{basetmpdir}/#{@tochtmltxt}") do |f|
f.each_line do |l|
force_include = nil
customid = nil
+ chaptype = nil
level, file, title, custom = l.chomp.split("\t")
unless custom.nil?
# custom setting
vars = custom.split(/,\s*/)
vars.each do |var|
@@ -240,20 +311,22 @@
case k
when "id"
customid = v
when "force_include"
force_include = true
+ when "chaptype"
+ chaptype = v
end
end
end
next if level.to_i > @params["toclevel"] && force_include.nil?
log("Push #{file} to ePUB contents.")
if customid.nil?
- @epub.contents.push(Content.new("file" => file, "level" => level.to_i, "title" => title))
+ @epub.contents.push(Content.new("file" => file, "level" => level.to_i, "title" => title, "chaptype" => chaptype))
else
- @epub.contents.push(Content.new("id" => customid, "file" => file, "level" => level.to_i, "title" => title))
+ @epub.contents.push(Content.new("id" => customid, "file" => file, "level" => level.to_i, "title" => title, "chaptype" => chaptype))
end
end
end
end
@@ -268,26 +341,26 @@
def copy_frontmatter(basetmpdir)
FileUtils.cp(@params["cover"], "#{basetmpdir}/#{File.basename(@params["cover"])}") if !@params["cover"].nil? && File.exist?(@params["cover"])
if @params["titlepage"]
- if @params["titlepagefile"].nil?
+ if @params["titlefile"].nil?
build_titlepage(basetmpdir, "titlepage.#{@params["htmlext"]}")
else
- FileUtils.cp(@params["titlepagefile"], "titlepage.#{@params["htmlext"]}")
+ FileUtils.cp(@params["titlefile"], "#{basetmpdir}/titlepage.#{@params["htmlext"]}")
end
- write_tochtmltxt(basetmpdir, "1\ttitlepage.#{@params["htmlext"]}\t#{@epub.res.v("titlepagetitle")}")
+ write_tochtmltxt(basetmpdir, "1\ttitlepage.#{@params["htmlext"]}\t#{@epub.res.v("titlepagetitle")}\tchaptype=pre")
end
if !@params["originaltitlefile"].nil? && File.exist?(@params["originaltitlefile"])
FileUtils.cp(@params["originaltitlefile"], "#{basetmpdir}/#{File.basename(@params["originaltitlefile"])}")
- write_tochtmltxt(basetmpdir, "1\t#{File.basename(@params["originaltitlefile"])}\t#{@epub.res.v("originaltitle")}")
+ write_tochtmltxt(basetmpdir, "1\t#{File.basename(@params["originaltitlefile"])}\t#{@epub.res.v("originaltitle")}\tchaptype=pre")
end
if !@params["creditfile"].nil? && File.exist?(@params["creditfile"])
FileUtils.cp(@params["creditfile"], "#{basetmpdir}/#{File.basename(@params["creditfile"])}")
- write_tochtmltxt(basetmpdir, "1\t#{File.basename(@params["creditfile"])}\t#{@epub.res.v("credittitle")}")
+ write_tochtmltxt(basetmpdir, "1\t#{File.basename(@params["creditfile"])}\t#{@epub.res.v("credittitle")}\tchaptype=pre")
end
end
def build_titlepage(basetmpdir, htmlfile)
File.open("#{basetmpdir}/#{htmlfile}", "w") do |f|
@@ -316,34 +389,45 @@
end
def copy_backmatter(basetmpdir)
if @params["profile"]
FileUtils.cp(@params["profile"], "#{basetmpdir}/#{File.basename(@params["profile"])}")
- write_tochtmltxt(basetmpdir, "1\t#{File.basename(@params["profile"])}\t#{@epub.res.v("profiletitle")}")
+ write_tochtmltxt(basetmpdir, "1\t#{File.basename(@params["profile"])}\t#{@epub.res.v("profiletitle")}\tchaptype=post")
end
if @params["advfile"]
FileUtils.cp(@params["advfile"], "#{basetmpdir}/#{File.basename(@params["advfile"])}")
- write_tochtmltxt(basetmpdir, "1\t#{File.basename(@params["advfile"])}\t#{@epub.res.v("advtitle")}")
+ write_tochtmltxt(basetmpdir, "1\t#{File.basename(@params["advfile"])}\t#{@epub.res.v("advtitle")}\tchaptype=post")
end
if @params["colophon"]
if @params["colophon"].instance_of?(String) # FIXME:このやり方はやめる?
FileUtils.cp(@params["colophon"], "#{basetmpdir}/colophon.#{@params["htmlext"]}")
else
File.open("#{basetmpdir}/colophon.#{@params["htmlext"]}", "w") {|f| @epub.colophon(f) }
end
- write_tochtmltxt(basetmpdir, "1\tcolophon.#{@params["htmlext"]}\t#{@epub.res.v("colophontitle")}")
+ write_tochtmltxt(basetmpdir, "1\tcolophon.#{@params["htmlext"]}\t#{@epub.res.v("colophontitle")}\tchaptype=post")
end
+
+ if @params["backcover"]
+ FileUtils.cp(@params["backcover"], "#{basetmpdir}/#{File.basename(@params["backcover"])}")
+ write_tochtmltxt(basetmpdir, "1\t#{File.basename(@params["backcover"])}\t#{@epub.res.v("backcovertitle")}\tchaptype=post")
+ end
end
def write_tochtmltxt(basetmpdir, s)
File.open("#{basetmpdir}/#{@tochtmltxt}", "a") do |f|
f.puts s
end
end
+ def write_buildlogtxt(basetmpdir, htmlfile, reviewfile)
+ File.open("#{basetmpdir}/#{@buildlogtxt}", "a") do |f|
+ f.puts "#{htmlfile},#{reviewfile}"
+ end
+ end
+
def header(title)
# titleはすでにエスケープ済みと想定
s = <<EOT
<?xml version="1.0" encoding="UTF-8"?>
EOT
@@ -390,11 +474,11 @@
def initialize(headlines)
@level = nil
@content = ""
@headlines = headlines
end
-
+
def tag_start(name, attrs)
if name =~ /\Ah(\d+)/
unless @level.nil?
raise "#{name}, #{attrs}"
end
@@ -406,19 +490,19 @@
elsif name == "a" && !attrs["id"].nil?
@id = attrs["id"]
end
end
end
-
+
def tag_end(name)
if name =~ /\Ah\d+/
@headlines.push({"level" => @level, "id" => @id, "title" => @content}) unless @id.nil?
@content = ""
@level = nil
@id = nil
end
end
-
+
def text(text)
unless @level.nil?
@content << text.gsub("\t", " ") # FIXME:区切り文字
end
end