Created
January 2, 2016 09:12
-
-
Save KitaitiMakoto/7b2286b61a0bafcc5926 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
# coding: utf-8 | |
gem 'epub-parser', '>= 0.2.4' | |
gem 'epub-maker', '>= 0.0.2' | |
require 'English' | |
require 'epub/maker' | |
require 'epub/parser/cfi' | |
require 'nokogiri/xml/range' | |
TARGET_RELEASE_IDENTIFIER = 'urn:uuid:14eadcd9-214a-4f45-9623-d8ac54f22af7@2015-12-04T09:00:00Z' | |
ERRATA = [ | |
{target: '/6/36!/4/2/16/5,:25,:27', operation: :replace, replace: 'ri'}, | |
{target: '/6/36!/4/2/18/7,:33,:35', operation: :replace, replace: 'ri'}, | |
{target: '/6/46!/4/2/70/6/1,:0,:4', operation: :replace, replace: 'send'}, | |
{target: '/6/52!/4/2/28/1,:61,:62', operation: :remove}, | |
{target: '/6/68!/4/2/44/1:267', operation: :add, add: 'が'}, | |
{target: '/6/98!/4/2/12/9:7', operation: :add, add: '*10'}, | |
{target: '/6/118!/4/2/50/3,:45,:46', operation: :remove} | |
] | |
UNOFFICIAL_ERRATA = [ | |
{target: '/6/84!/4/2/34/4/1,:53,:54', operation: :remove} | |
] | |
NEW_MODIFIED = '2015-12-30T14:03:00Z' | |
def main(argv) | |
epub_path = argv.shift | |
if epub_path.nil? or !File.file?(epub_path) | |
$stderr.puts "EPUBファイルを指定してください。" | |
$stderr.puts usage | |
abort | |
end | |
epub = EPUB::Parser.parse(epub_path) | |
$stderr.puts "#{$PROGRAM_NAME}: このプログラムは指定された本(#{epub_path})を上書きします。よろしいですか?(y/N)" | |
unless gets.chomp.downcase == "y" | |
exit | |
end | |
unless assert_release_identifier(epub) | |
$stderr.puts "指定された本は、エラッタが適用可能なバージョン(Release Identifier)ではありません。" | |
$stderr.puts " エラッタの対象バージョン:#{TARGET_RELEASE_IDENTIFIER}" | |
$stderr.puts " 指定された本のバージョン:#{epub.release_identifier}" | |
abort | |
end | |
reflect_errata(epub) | |
update_modified(epub) | |
rescue => error | |
$stderr.puts error | |
$stderr.puts error.backtrace | |
$stderr.puts usage | |
abort | |
end | |
def usage | |
"Usage: ruby #{$PROGRAM_NAME} EPUB_PATH" | |
end | |
def assert_release_identifier(epub) | |
epub.release_identifier == TARGET_RELEASE_IDENTIFIER | |
end | |
def reflect_errata(epub) | |
errata = setup_errata | |
errata.each do |erratum| | |
reflect_erratum erratum, epub | |
end | |
end | |
def update_modified(epub) | |
epub.package.edit do |package| | |
package.metadata.modified.content = NEW_MODIFIED | |
end | |
end | |
def reflect_erratum(erratum, epub) | |
if erratum[:target].kind_of? EPUB::CFI::Location | |
item, start_node = end_node = get_item_and_element(erratum[:target], epub) | |
start_offset = end_offset = erratum[:target].paths.last.offset.value | |
else | |
# TODO: Search nodes from parent subpath | |
item, start_node = get_item_and_element(erratum[:target].first, epub) | |
_, end_node = get_item_and_element(erratum[:target].last, epub) | |
start_offset = erratum[:target].first.paths.last.offset.value | |
end_offset = erratum[:target].last.paths.last.offset.value | |
end | |
range = Nokogiri::XML::Range.new(start_node, start_offset, end_node, end_offset) | |
# page_title = (range.document/'h1').first.content.gsub(/\s+/, ' ') | |
# puts '===========================' | |
# puts "#{page_title}(#{item.href})" | |
# puts '-----------BEFORE----------' | |
# puts range.start_node.parent.content | |
case erratum[:operation] | |
when :add | |
range.insert_node Nokogiri::XML::Text.new(erratum[:add], range.document) | |
when :remove | |
range.delete_contents | |
when :replace | |
range.delete_contents | |
range.insert_node Nokogiri::XML::Text.new(erratum[:replace], range.document) | |
end | |
# puts '-----------AFTER----------' | |
# puts range.start_node.parent.content | |
item.content = range.document.to_xml | |
item.save | |
end | |
def get_item_and_element(cfi, epub) | |
path_in_package = cfi.paths.first | |
step_to_itemref = path_in_package.steps[1] | |
itemref = epub.spine.itemrefs[step_to_itemref.step / 2 - 1] | |
doc = itemref.item.content_document.nokogiri | |
path_in_doc = cfi.paths[1] | |
current_node = doc.root | |
path_in_doc.steps.each do |step| | |
if step.element? | |
current_node = current_node.element_children[step.value / 2 - 1] | |
else | |
element_index = (step.value - 1) / 2 - 1 | |
if element_index == -1 | |
current_node = current_node.children.first | |
else | |
prev = current_node.element_children[element_index] | |
break unless prev | |
current_node = prev.next_sibling | |
break unless current_node | |
end | |
end | |
end | |
[itemref.item, current_node] | |
end | |
def setup_errata | |
(ERRATA + UNOFFICIAL_ERRATA).map {|erratum| | |
erratum[:target] = EPUB::CFI(erratum[:target]) | |
erratum | |
}.sort_by {|erratum| | |
cfi = erratum[:target] | |
cfi = cfi.first if cfi.kind_of? EPUB::CFI::Range | |
cfi | |
}.reverse | |
end | |
main(ARGV) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment