bookbinder 0.3.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/lib/bookbinder.rb +6 -5
  2. data/lib/bookbinder/file.rb +1 -2
  3. data/lib/bookbinder/file_system/zip_file.rb +4 -4
  4. data/lib/bookbinder/operations.rb +7 -1
  5. data/lib/bookbinder/package.rb +25 -27
  6. data/lib/bookbinder/package/openbook.rb +2 -3
  7. data/lib/bookbinder/scratch.rb +36 -0
  8. data/lib/bookbinder/transform/{openbook/json.rb → book_json.rb} +1 -1
  9. data/lib/bookbinder/version.rb +1 -1
  10. metadata +12 -63
  11. data/lib/bookbinder/package/epub.rb +0 -64
  12. data/lib/bookbinder/package/media_ripper.rb +0 -47
  13. data/lib/bookbinder/package/mp3_audiobook.rb +0 -43
  14. data/lib/bookbinder/transform/epub/audio_overlay.rb +0 -227
  15. data/lib/bookbinder/transform/epub/audio_soundtrack.rb +0 -73
  16. data/lib/bookbinder/transform/epub/contributor.rb +0 -11
  17. data/lib/bookbinder/transform/epub/cover_image.rb +0 -80
  18. data/lib/bookbinder/transform/epub/cover_page.rb +0 -148
  19. data/lib/bookbinder/transform/epub/creator.rb +0 -67
  20. data/lib/bookbinder/transform/epub/description.rb +0 -43
  21. data/lib/bookbinder/transform/epub/language.rb +0 -29
  22. data/lib/bookbinder/transform/epub/metadata.rb +0 -140
  23. data/lib/bookbinder/transform/epub/nav.rb +0 -60
  24. data/lib/bookbinder/transform/epub/nav_toc.rb +0 -177
  25. data/lib/bookbinder/transform/epub/ncx.rb +0 -63
  26. data/lib/bookbinder/transform/epub/ocf.rb +0 -33
  27. data/lib/bookbinder/transform/epub/opf.rb +0 -22
  28. data/lib/bookbinder/transform/epub/package_identifier.rb +0 -87
  29. data/lib/bookbinder/transform/epub/rendition.rb +0 -273
  30. data/lib/bookbinder/transform/epub/resources.rb +0 -38
  31. data/lib/bookbinder/transform/epub/spine.rb +0 -79
  32. data/lib/bookbinder/transform/epub/title.rb +0 -92
  33. data/lib/bookbinder/transform/epub/version.rb +0 -39
  34. data/lib/bookbinder/transform/media_ripper/cover_image.rb +0 -12
  35. data/lib/bookbinder/transform/media_ripper/eisbn.rb +0 -15
  36. data/lib/bookbinder/transform/media_ripper/metadata.rb +0 -27
  37. data/lib/bookbinder/transform/media_ripper/nav_toc.rb +0 -57
  38. data/lib/bookbinder/transform/media_ripper/publisher.rb +0 -15
  39. data/lib/bookbinder/transform/media_ripper/rendition.rb +0 -7
  40. data/lib/bookbinder/transform/media_ripper/spine.rb +0 -34
  41. data/lib/bookbinder/transform/media_ripper/title.rb +0 -16
  42. data/lib/bookbinder/transform/mp3_audiobook/cover_image.rb +0 -25
  43. data/lib/bookbinder/transform/mp3_audiobook/creator.rb +0 -27
  44. data/lib/bookbinder/transform/mp3_audiobook/description.rb +0 -18
  45. data/lib/bookbinder/transform/mp3_audiobook/metadata.rb +0 -20
  46. data/lib/bookbinder/transform/mp3_audiobook/nav_toc.rb +0 -71
  47. data/lib/bookbinder/transform/mp3_audiobook/publisher.rb +0 -18
  48. data/lib/bookbinder/transform/mp3_audiobook/rendition.rb +0 -7
  49. data/lib/bookbinder/transform/mp3_audiobook/spine.rb +0 -33
  50. data/lib/bookbinder/transform/mp3_audiobook/subject.rb +0 -18
  51. data/lib/bookbinder/transform/mp3_audiobook/title.rb +0 -18
@@ -1,148 +0,0 @@
1
- class Bookbinder::Transform::EPUB_CoverPage < Bookbinder::Transform
2
-
3
- def dependencies
4
- [Bookbinder::Transform::EPUB_Spine]
5
- end
6
-
7
-
8
- # A: look in the Nav (if it exists) for a landmark li with an
9
- # epub:type of 'cover', and find the spine item with that href.
10
- #
11
- # B: look for an OPF <guide><reference type="cover"> and find
12
- # the spine item with the same href.
13
- #
14
- # C: look at the first spine item:
15
- # - is it have /cover/ in the filename?
16
- # - no? does it have an image and no body text?
17
- # - no? does it have an svg and no body text?
18
- #
19
- # -> If found, add to map['nav']['landmarks'] with a 'type'
20
- # of 'cover'.
21
- #
22
- def to_map(package)
23
- cover_page_item =
24
- cover_page_item_from_nav(package) ||
25
- cover_page_item_from_opf_guide(package) ||
26
- cover_page_item_from_first_spine_item(package)
27
-
28
- if cover_page_item
29
- package.map['nav'] ||= {}
30
- package.map['nav']['landmarks'] ||= []
31
- package.map['nav']['landmarks'].unshift(cover_page_item)
32
- package.map['spine'].each { |item|
33
- if item['path'] == cover_page_item['path']
34
- item['linear'] = false
35
- end
36
- }
37
- end
38
- end
39
-
40
-
41
- # Do nothing unless we have a map['nav']['landmark'] type='cover'.
42
- #
43
- # In the Nav (if it exists), create a landmark with an
44
- # epub:type of 'cover'. Actually, don't -- let the landmarks feature
45
- # handle this.
46
- #
47
- # In the OPF, create a <guide> element if it doesn't exist,
48
- # and create a <reference type="cover" title="Cover" href="..."> tag
49
- # within it.
50
- #
51
- def from_map(package)
52
- return unless package.map['nav'] && package.map['nav']['landmarks']
53
- cover_page_item = package.map['nav']['landmarks'].detect { |item|
54
- item['type'] == 'cover'
55
- }
56
- return unless cover_page_item
57
-
58
- opf_doc = package.file(:opf).document
59
- unless guide_tag = opf_doc.find('opf|guide')
60
- guide_tag = opf_doc.new_node('guide', :append => opf_doc.root)
61
- end
62
-
63
- opf_doc.new_node('reference', :append => guide_tag) { |ref_tag|
64
- ref_tag['type'] = 'cover'
65
- ref_tag['href'] = package.make_href(cover_page_item['path'])
66
- ref_tag['title'] = cover_page_item['title']
67
- }
68
- end
69
-
70
-
71
- protected
72
-
73
- # Look for an EPUB3 landmark with type 'cover'.
74
- #
75
- def cover_page_item_from_nav(package)
76
- return unless nav_file = package.file(:nav)
77
- nav_doc = nav_file.document('r')
78
- if li = nav_doc.find('nav[epub|type="landmark"] li[epub|type="cover"]')
79
- href_to_cover_page_item(
80
- package,
81
- li['href'],
82
- li['title'] || li.content.strip
83
- )
84
- end
85
- end
86
-
87
-
88
- # Look for a guide reference with type 'cover' in the OPF.
89
- #
90
- def cover_page_item_from_opf_guide(package)
91
- opf_doc = package.file(:opf).document('r')
92
- if guide_ref_tag = opf_doc.find('opf|guide > opf|reference[type="cover"]')
93
- href_to_cover_page_item(package, guide_ref_tag['href'])
94
- end
95
- end
96
-
97
-
98
- # Investigate whether the first spine item is a cover page.
99
- #
100
- def cover_page_item_from_first_spine_item(package)
101
- spine = package.map['spine']
102
- if spine.any? && file_path = package.map['spine'].first['path']
103
- file_href = package.make_href(file_path)
104
- if file_path.match(/cover/)
105
- return href_to_cover_page_item(package, file_href)
106
- end
107
- package.if_file(file_path) { |cmpt_file|
108
- if cmpt_doc = cmpt_file.document('r')
109
- body = cmpt_doc.find('body')
110
- nodes = body.xpath('.//text()[normalize-space()]')
111
- # If the body has no text...
112
- if nodes.empty?
113
- # ...and it has an <img> or an <svg>...
114
- if cmpt_doc.find('body img') || cmpt_doc.find('body svg')
115
- # ...we'll treat it as a cover page.
116
- return href_to_cover_page_item(package, file_href)
117
- end
118
- end
119
- end
120
- }
121
- end
122
- end
123
-
124
-
125
- # Given a href for a cover page, create the cover page item
126
- # that will go into the landmarks array in the package map.
127
- #
128
- def href_to_cover_page_item(package, cover_href, page_title = nil)
129
- cover_href = cover_href.sub(/#.*$/, '')
130
- cover_page_path = package.make_path(cover_href)
131
- if cover_page_file = package.file(cover_page_path)
132
- if doc = cover_page_file.document('r')
133
- unless page_title
134
- title_tag = cover_page_file.document('r').find('head > title')
135
- page_title = title_tag ? title_tag.content.strip : 'Cover page'
136
- end
137
- {
138
- 'type' => 'cover',
139
- 'path' => cover_page_path,
140
- 'title' => page_title,
141
- # FIXME: acquire the real media-type from manifest item?
142
- 'media-type' => cover_page_file.media_type
143
- }
144
- end
145
- end
146
- end
147
-
148
- end
@@ -1,67 +0,0 @@
1
- class Bookbinder::Transform::EPUB_Creator < Bookbinder::Transform
2
-
3
- def dependencies
4
- [Bookbinder::Transform::EPUB_Metadata]
5
- end
6
-
7
-
8
- def to_map(package)
9
- return unless package.map['metadata']
10
- return unless metadata_array = package.map['metadata'][actor_type]
11
- actors = []
12
- actor_data = metadata_array.sort { |a, b|
13
- if a['display-seq'] && b['display-seq']
14
- a['display-seq']['@'].to_i <=> b['display-seq']['@'].to_i
15
- else
16
- 0
17
- end
18
- }
19
- actor_data.each { |cdata|
20
- actor = {
21
- 'name' => cdata['@'],
22
- 'role' => cdata['role'] ? cdata['role']['@'] : 'aut',
23
- }
24
- actor['file-as'] = cdata['file-as']['@'] if cdata['file-as']
25
- # Eh, 'alternate-script' is too messy for now.
26
-
27
- metadata_array.delete(cdata)
28
- actors.push(actor)
29
- }
30
- package.map['metadata'].delete(actor_type) if metadata_array.empty?
31
- package.map[actor_type] = actors
32
- end
33
-
34
-
35
- def from_map(package)
36
- return unless actors = package.map[actor_type]
37
- opf_doc = package.file(:opf).document
38
- metadata_tag = opf_doc.find('opf|metadata')
39
- actors.each_with_index { |actor, seq|
40
- actor_tag = opf_doc.new_node('dc:'+actor_type, :append => metadata_tag)
41
- actor_tag.content = actor['name']
42
- if actors.length > 1
43
- seq += 1
44
- actor_id = "dc-#{actor_type}-metadata-#{seq}"
45
- actor_tag['id'] = actor_id
46
- opf_doc.new_node('meta', :append => metadata_tag) { |role_meta_tag|
47
- role_meta_tag.content = actor['role']
48
- role_meta_tag['property'] = 'role'
49
- role_meta_tag['refines'] = '#'+actor_id
50
- }
51
- opf_doc.new_node('meta', :append => metadata_tag) { |seq_meta_tag|
52
- seq_meta_tag.content = seq
53
- seq_meta_tag['property'] = 'display-seq'
54
- seq_meta_tag['refines'] = '#'+actor_id
55
- }
56
- end
57
- }
58
- end
59
-
60
-
61
- protected
62
-
63
- def actor_type
64
- 'creator'
65
- end
66
-
67
- end
@@ -1,43 +0,0 @@
1
- class Bookbinder::Transform::EPUB_Description < Bookbinder::Transform
2
-
3
- def dependencies
4
- [Bookbinder::Transform::EPUB_Metadata]
5
- end
6
-
7
-
8
- def to_map(package)
9
- desc_hashes = package.map['metadata'].delete('description')
10
- descs = []
11
- if desc_hashes && desc_hashes.any?
12
- descs = desc_hashes.collect { |dh| dh['@'] }
13
- descs.sort! { |a, b| a.length <=> b.length }
14
- full = descs.shift
15
- if full && !full.empty?
16
- short = descs.shift || first_sentence(full)
17
- desc = { 'full' => full }
18
- desc['short'] = short if short
19
- package.map['description'] = desc
20
- end
21
- end
22
- end
23
-
24
-
25
- def from_map(package)
26
- if desc = package.map['description']
27
- opf_doc = package.file(:opf).document
28
- opf_doc.new_node('dc:description', :append => 'opf|metadata') { |desc_tag|
29
- desc_tag.content = desc['full']
30
- }
31
- end
32
- end
33
-
34
-
35
- protected
36
-
37
- def first_sentence(str)
38
- str = Nokogiri::HTML(str).text
39
- sentences = str.split(/\./)
40
- sentences.first+'.' if sentences.any?
41
- end
42
-
43
- end
@@ -1,29 +0,0 @@
1
- class Bookbinder::Transform::EPUB_Language < Bookbinder::Transform
2
-
3
- def dependencies
4
- [Bookbinder::Transform::EPUB_Metadata]
5
- end
6
-
7
-
8
- def to_map(package)
9
- lang_hashes = package.map['metadata'].delete('language')
10
- if lang_hashes && lang_hashes.any?
11
- package.map['language'] = lang_hashes.collect { |lh| lh['@'] }
12
- else
13
- package.warn('No <dc:language> found in OPF metadata')
14
- end
15
- end
16
-
17
-
18
- def from_map(package)
19
- if langs = package.map['language']
20
- opf_doc = package.file(:opf).document
21
- langs.each { |lang|
22
- opf_doc.new_node('dc:language', :append => 'opf|metadata') { |lang_tag|
23
- lang_tag.content = lang
24
- }
25
- }
26
- end
27
- end
28
-
29
- end
@@ -1,140 +0,0 @@
1
- # Takes all the elements in the <metadata> tag of the OPF file and
2
- # generates a clean hash of the data. Other transforms will pick and
3
- # choose from this hash. What's left over is mostly just for
4
- # preserving EPUB's guff.
5
- #
6
- # So this:
7
- #
8
- # <metadata>
9
- # <dc:identifier id="isbn-id">
10
- # urn:isbn:9780101010101
11
- # </dc:identifier>
12
- # <meta
13
- # refines="#isbn-id"
14
- # property="identifier-type"
15
- # scheme="onix:codelist5"
16
- # >
17
- # 15
18
- # </meta>
19
- # <dc:source id="src-id">
20
- # urn:isbn:9780375704024
21
- # </dc:source>
22
- # <meta
23
- # refines="#src-id"
24
- # property="identifier-type"
25
- # scheme="onix:codelist5"
26
- # >
27
- # 15
28
- # </meta>
29
- # </metadata>
30
- #
31
- # ... becomes this:
32
- #
33
- # "metadata": {
34
- # "identifier": [{
35
- # "@": "urn:isbn:9780101010101",
36
- # "identifier-type": {
37
- # "@": 15,
38
- # "scheme": {
39
- # "@": "onix-codelist5"
40
- # }
41
- # }
42
- # }],
43
- # "source": [{
44
- # "@": "urn:isbn:9780375704024",
45
- # "identifier-type": {
46
- # "@": 15,
47
- # "scheme": {
48
- # "@": "onix-codelist5"
49
- # }
50
- # }
51
- # }]
52
- # }
53
- #
54
- # You can nest properties arbitrarily deep in the map's "metadata" structure.
55
- #
56
- # "metadata": {
57
- # "some-property": [{
58
- # "@": "value-of-some-property",
59
- # "some-property-property": {
60
- # "@": "value-of-some-property-property",
61
- # "some-property-property-property": {
62
- # "@": "value-of-etc"
63
- # }
64
- # }
65
- # }],
66
- # "other-property": [
67
- # { "@": "other-property-first-value" },
68
- # { "@": "other-property-second-value" }
69
- # ]
70
- # }
71
- #
72
- class Bookbinder::Transform::EPUB_Metadata < Bookbinder::Transform
73
-
74
-
75
- def dependencies
76
- [Bookbinder::Transform::EPUB_OPF]
77
- end
78
-
79
-
80
- def to_map(package)
81
- opf_doc = package.file(:opf).document('r')
82
- md = {}
83
- opf_doc.each('opf|metadata > *') { |tag|
84
- # If this tag refines another metadata tag, we can skip it
85
- next if tag['refines'] && opf_doc.find('opf|metadata > '+tag['refines'])
86
-
87
- # Find the basic name and value of the meta tag
88
- name = tag.node_name
89
- value = { '@' => tag.content.strip }
90
- # If the meta tag has attributes, add them to the value
91
- # (but note that these are deprecated in EPUB3 in favor
92
- # of refinements).
93
- tag.attributes.each_pair { |key, attr|
94
- value[key] = { '@' => attr.value }
95
- value[key]['deprecated'] = true unless key == 'id' || key == 'refines'
96
- }
97
- if name == 'meta'
98
- if tag['property']
99
- name = tag['property']
100
- value.delete('property')
101
- elsif tag['name']
102
- # Note that <meta name="" content=""> is deprecated in EPUB3.
103
- name = tag['name']
104
- value['@'] = tag['content']
105
- value['deprecated'] = true
106
- value.delete('name')
107
- end
108
- end
109
- # If the meta tag is refined by another meta tag, add the
110
- # refinements to our value hash.
111
- if tag['id']
112
- refines = opf_doc.search(
113
- 'opf|metadata > opf|meta[refines="#'+tag['id']+'"]'
114
- )
115
- refines.each { |refinement|
116
- refine_value = { '@' => refinement.content.strip }
117
- refinement.attributes.each_pair { |key, attr|
118
- refine_value[key] = attr.value
119
- }
120
- value[refinement['property']] = refine_value
121
- }
122
- end
123
- # Add the name and value to our metadata hash
124
- add_to_hash(md, name, value)
125
- }
126
- package.map['metadata'] = md
127
- end
128
-
129
-
130
- def from_map(package)
131
- end
132
-
133
-
134
- protected
135
-
136
- def add_to_hash(hash, key, val)
137
- hash[key] = [hash[key], val].flatten.compact
138
- end
139
-
140
- end
@@ -1,60 +0,0 @@
1
- class Bookbinder::Transform::EPUB_Nav < Bookbinder::Transform
2
-
3
- DEFAULT_FILE_NAME = 'book-nav.xhtml'
4
-
5
- def dependencies
6
- [Bookbinder::Transform::EPUB_Resources]
7
- end
8
-
9
-
10
- def to_map(package)
11
- opf_doc = package.file(:opf).document('r')
12
- if nav_item = opf_doc.find('opf|manifest > opf|item[properties~="nav"]')
13
- nav_path = package.make_path(nav_item['href'])
14
- package.file_aliases[:nav] = nav_path
15
- package.map['resources'].delete_if { |rsrc|
16
- package.file_path(rsrc['path']) == nav_path
17
- }
18
- end
19
- end
20
-
21
-
22
- def from_map(package)
23
- if package.options['nav_file'] != false
24
- stub_nav(package)
25
- add_to_opf_manifest(package)
26
- end
27
- end
28
-
29
-
30
- protected
31
-
32
- def stub_nav(package)
33
- package.file_aliases[:nav] = DEFAULT_FILE_NAME
34
- package.file(:nav).new_xml_document { |doc, x|
35
- x.doc.create_internal_subset('html', nil, nil)
36
- x.html {
37
- doc.add_node_namespace(x.parent, 'xhtml', true)
38
- doc.add_node_namespace(x.parent, 'epub')
39
- x.head {
40
- x.meta('charset' => 'utf-8')
41
- x.style('ol { list-style: none; }')
42
- }
43
- x.body
44
- }
45
- }
46
- end
47
-
48
-
49
- def add_to_opf_manifest(package)
50
- opf_file = package.file(:opf)
51
- nav_file = package.file(:nav)
52
- opf_file.document.new_node('item', :append => 'opf|manifest') { |item_tag|
53
- item_tag['href'] = package.make_href(DEFAULT_FILE_NAME)
54
- item_tag['id'] = package.make_id(DEFAULT_FILE_NAME)
55
- item_tag['properties'] = 'nav'
56
- item_tag['media-type'] = nav_file.media_type
57
- }
58
- end
59
-
60
- end