#!/usr/bin/env ruby # encoding: utf-8 # # Copyright (c) 2010 Kenshi Muto and Masayoshi Takahashi # # This program is free software. # You can distribute or modify this program under the terms of # the GNU LGPL, Lesser General Public License version 2.1. # For details of the GNU LGPL, see the file "COPYING". # require 'tmpdir' require 'fileutils' require 'yaml' require 'optparse' require 'rexml/document' require 'time' require 'pathname' bindir = Pathname.new(__FILE__).realpath.dirname $LOAD_PATH.unshift((bindir + '../lib').realpath) require 'uuid' require 'review' require 'review/i18n' require 'review/htmlutils' include ReVIEW::HTMLUtils $essential_files = ['top', 'toc', 'colophon'] def main if ARGV.size != 1 puts "Usage: #{$0} configfile" exit 0 end yamlfile = ARGV[0] values = ReVIEW::Configure.values.merge(YAML.load_file(yamlfile)) bookname = values["bookname"] $essential_files <<= bookname tmp = values["debug"].nil? ? Dir.mktmpdir : "." @bookdir = "#{tmp}/#{bookname}-epub" @epubversion = values["epubversion"] || 2 @htmlversion = values["htmlversion"] || 4 if @epubversion == 3 ## if epubversion is 3, htmlversion should be 5 @htmlversion = 5 end if File.exist?("#{bookname}.epub") STDERR.puts "#{bookname}.epub exists. Please remove or rename first." exit 1 end if File.exist?(@bookdir) STDERR.puts "#{@bookdir} directory exists. Please remove or rename first." exit 1 end @identifier = values["urnid"].nil? ? "urn:uuid:#{UUID.create}" : values["urnid"] Dir.mkdir(@bookdir) # MIME type File.open("#{@bookdir}/mimetype", "w") {|f| f.write "application/epub+zip" } Dir.mkdir("#{@bookdir}/OEBPS") # XHTML @manifeststr = "" @ncxstr = "" @tocdesc = Array.new basedir = Dir.pwd base_path = Pathname.new(basedir) ReVIEW::Book.load(basedir).parts.each do |part| if part.name.present? if part.file? filename = (base_path + part.path).to_s output_chaps_by_file(filename, values) htmlfile = File.basename(filename.chomp.strip,".*")+".html" else htmlfile = "part_#{part.number}.html" make_part_page(part, htmlfile, values) end file_id = "part_#{part.number}" part_name = "#{ReVIEW::I18n.t("part", part.number)} #{part.name.strip}" @tocdesc << [1, htmlfile, nil, part_name] @manifeststr << %Q(\n) @ncxstr << %Q(\n) end part.chapters.each do |chap| filename = Pathname.new(chap.path).relative_path_from(base_path).to_s output_chaps_by_file(filename, values) end end if File.exist?("images") Dir.mkdir("#{@bookdir}/OEBPS/images") image_files = ReVIEW::MakerHelper.copy_images_to_dir("images", "#{@bookdir}/OEBPS/images") image_files.each do |image_file| dirname = File.dirname(image_file) fname = File.basename(image_file) figid = getFigId(dirname.gsub(%r|/|,'-')+"-"+fname) mime = nil next unless fname =~ /\.(png|gif|jpg|jpeg|svg)$/i case fname.downcase.match(/\.(png|gif|jpg|jpeg|svg)$/)[1] when "png" mime = "image/png" when "gif" mime = "image/gif" when "jpg", "jpeg" mime = "image/jpeg" when "svg" mime = "image/svg+xml" else raise "unsupported type #{fname}" end @manifeststr << %Q(\n) end end # container Dir.mkdir("#{@bookdir}/META-INF") File.open("#{@bookdir}/META-INF/container.xml", "w") {|f| f.puts < EOT } # opf (meta info) if @epubversion == 3 make_opf_filev3(values, bookname) else make_opf_file(values, bookname) end # ncx (toc) if values["toc"] File.open("#{@bookdir}/OEBPS/#{bookname}.ncx", "w") {|f| f.puts < #{values["booktitle"]} #{values["aut"].nil? ? "" : values["aut"]} #{values["booktitle"]} EOT nav_count = 2 if values["mytoc"] f.puts < 目次 EOT nav_count = 3 end @tocdesc.each {|item| level, file, id, content = item # values["level"] next if level > values["toclevel"].to_i indent = "" if level > values["secnolevel"].to_i indent = "- " end fragment_id = (id ? '#'+id : '') f.puts < #{indent}#{strip_html(content)} EOT nav_count += 1 } f.puts < EOT } end # Cover page File.open("#{@bookdir}/OEBPS/#{bookname}.html", "w") {|f| f.puts < EOT doctype = make_doctype() f.puts doctype f.puts < EOT if @htmlversion == 4 f.puts < EOT else f.puts < EOT end f.puts <#{values["booktitle"]} EOT if !values["coverfile"].nil? && File.exist?(values["coverfile"]) File.open(values["coverfile"]) {|f2| f2.each_line {|l| f.puts l } } else f.puts <#{values["booktitle"]} EOT end f.puts < EOT } # Title page File.open("#{@bookdir}/OEBPS/top.html", "w") {|f| f.puts < EOT doctype = make_doctype() f.puts doctype f.puts < EOT if @htmlversion == 4 f.puts < EOT else f.puts < EOT end f.puts <#{values["booktitle"]} EOT if !values["titlepagefile"].nil? && File.exist?(values["titlepagefile"]) File.open(values["titlepagefile"]) {|f2| f2.each_line {|l| f.puts l } } else f.puts <#{values["booktitle"]} EOT if values["aut"] f.puts <

#{values["aut"]}

EOT end if values["prt"] f.puts <



#{values["prt"]}

EOT end end f.puts < EOT } # Additional toc page if values["toc"] && values["mytoc"] File.open("#{@bookdir}/OEBPS/toc.html", "w") {|f| if @epubversion == 3 listelm = "ol" else listelm = "ul" end f.puts < EOT doctype = make_doctype() f.puts doctype f.puts < EOT if @htmlversion == 4 f.puts < EOT else f.puts < EOT end f.puts <目次 EOT f.puts %q() if @epubversion == 3 f.puts < EOT } end # stylesheet if File.exist?(values["stylesheet"]) FileUtils.cp values["stylesheet"], "#{@bookdir}/OEBPS/#{values["stylesheet"]}" else File.open("#{@bookdir}/OEBPS/#{values["stylesheet"]}", "w") {|f| f.puts <) else %q() end end def make_opf_file(values, bookname) File.open("#{@bookdir}/OEBPS/#{bookname}.opf", "w") {|f| f.puts < #{values["booktitle"]} EOT f.puts %Q(#{values["aut"]}) unless values["aut"].nil? # FIXME: support multiple members f.puts %Q(#{values["prt"]}) unless values["prt"].nil? f.puts %Q(#{values["date"]}) unless values["date"].nil? f.puts %Q(#{values["rights"]}) unless values["rights"].nil? f.puts %Q(#{values["asn"]}) unless values["asn"].nil? f.puts %Q(#{values["ant"]}) unless values["ant"].nil? f.puts %Q(#{values["clb"]}) unless values["clb"].nil? f.puts %Q(#{values["edt"]}) unless values["edt"].nil? f.puts %Q(#{values["dsr"]}) unless values["dsr"].nil? f.puts %Q(#{values["ill"]}) unless values["ill"].nil? f.puts %Q(#{values["pht"]}) unless values["pht"].nil? f.puts %Q(#{values["trl"]}) unless values["trl"].nil? f.puts %Q(#{values["description"]}) unless values["description"].nil? if values["coverimage"] f.puts %Q() end f.puts <ja #{@identifier} EOT if values["toc"] f.puts < EOT end f.puts < EOT if values["toc"] && values["mytoc"] f.puts < EOT end f.puts @manifeststr if values["colophon"] f.puts < EOT end if values["cover_linear"] && values["cover_linear"] != "no" cover_linear = "yes" else cover_linear = "no" end f.puts < EOT if values["toc"] && values["mytoc"] f.puts < EOT end f.puts @ncxstr if values["colophon"] f.puts < EOT end f.puts < EOT if values["titlepage"] f.puts < EOT end if values["toc"] && values["mytoc"] f.puts < EOT end f.puts < EOT } end def make_opf_filev3(values, bookname) File.open("#{@bookdir}/OEBPS/#{bookname}.opf", "w") {|f| f.puts < #{values["booktitle"]} EOT unless values["aut"].nil? # FIXME: support multiple members f.puts %Q(#{values["aut"]}) f.puts %Q(aut) end f.puts %Q(#{values["prt"]}) unless values["prt"].nil? f.puts %Q(#{values["date"]}) unless values["date"].nil? f.puts %Q(#{values["rights"]}) unless values["rights"].nil? %w(asn ant clb edt dsr ill pht trl).each do |attr| unless values[attr].nil? f.puts %Q(#{values[attr]}) f.puts %Q(#{attr}) end end f.puts %Q(#{values["description"]}) unless values["description"].nil? f.puts %Q(#{Time.now.utc.iso8601(0)}) if values["coverimage"] f.puts %Q() end f.puts <ja #{@identifier} EOT if values["toc"] f.puts < EOT end f.puts < EOT if values["toc"] && values["mytoc"] f.puts < EOT end f.puts @manifeststr if values["colophon"] f.puts < EOT end if values["cover_linear"] && values["cover_linear"] != "no" cover_linear = "yes" else cover_linear = "no" end f.puts < EOT if values["toc"] && values["mytoc"] f.puts < EOT end f.puts @ncxstr if values["colophon"] f.puts < EOT end f.puts < EOT if values["titlepage"] f.puts < EOT end if values["toc"] && values["mytoc"] f.puts < EOT end f.puts < EOT } end def output_chaps(chapsfile, values) File.open(chapsfile) {|chaps| chaps.each_line {|l| next if l =~ /^#/ output_chaps_by_file(l, values) } } end def output_chaps_by_file(l, values) file_id = File.basename(l.chomp.strip,".*") if (idx = $essential_files.index(file_id)) if idx == $essential_files.size - 1 STDERR.puts "#{file_id} is book name. Please rename #{l.chomp.strip}." else STDERR.puts "#{file_id} is special name. Please rename #{l.chomp.strip}." end exit 1 end filename = "#{file_id}.html" fork { STDOUT.reopen("#{@bookdir}/OEBPS/#{filename}") exec("review-compile --target=html --level=#{values["secnolevel"]} --htmlversion=#{values["htmlversion"]} #{values["params"]} #{l}") } Process.waitall getanchors("#{@bookdir}/OEBPS/#{filename}") @manifeststr << %Q(\n) @ncxstr << %Q(\n) end def getFigId(filename) figid = filename.sub(/\.(png|gif|jpg|jpeg|svg)$/, '') "fig-#{figid}" end def getTitle(filename) File.open(filename) {|f| return REXML::Document.new(f).elements["//html/head/title"].text } end def getanchors(filename) File.open(filename) {|f| file = filename.sub(/.+\//, '') f.each_line {|l| if l =~ /\A]*><\/a>(.+?)<\/h/ # level, ID, content @tocdesc << [$1.to_i, file, $2, $3] end } } end def make_colophon_page(tmp,bookname,values) header = < EOT header += make_doctype() header += < EOT if @htmlversion == 4 header += < EOT else header += < EOT end header += <#{values["booktitle"]} EOT footer = < EOT colophon_path = "#{@bookdir}/OEBPS/colophon.html" colophon = values["colophon"] if colophon.kind_of?(String) && File.exist?(colophon) File.open(colophon_path, "w") {|f| f.puts header File.open(values["colophon"]) {|f2| f2.each_line {|l| f.puts l } } f.puts footer } else File.open(colophon_path, "w") {|f| f.puts header f.puts <

#{values["booktitle"]}

EOT if values["pubhistory"] f.puts %Q[
\n

#{values["pubhistory"].gsub(/\n/,"
")}

\n
] end f.puts < EOT f.puts %Q[\n 著 者#{values["aut"]}\n] if values["aut"] f.puts %Q[\n 翻 訳#{values["trl"]}\n] if values["trl"] f.puts %Q[\n デザイン#{values["dsr"]}\n] if values["dsr"] f.puts %Q[\n イラスト#{values["ill"]}\n] if values["ill"] f.puts %Q[\n 編 集#{values["edt"]}\n] if values["edt"] f.puts %Q[\n 発行所#{values["prt"]}\n] if values["prt"] f.puts < EOT if values["rights"] f.puts %Q[] end f.puts "" f.puts footer } end end def make_part_page(part, filename, values) File.open("#{@bookdir}/OEBPS/#{filename}", "w") {|f| f.puts <<-EOT EOT doctype = make_doctype() f.puts doctype f.puts <<-EOT #{values["booktitle"]}

#{ReVIEW::I18n.t("part", part.number)}

EOT if part.name.strip.present? f.puts <<-EOT

#{part.name.strip}

EOT end f.puts <<-EOT EOT } end main