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,25 +0,0 @@
1
- class Bookbinder::Transform::MP3Audiobook_CoverImage < Bookbinder::Transform
2
-
3
- TAG = 'APIC'
4
- PATH = 'cover.jpg'
5
-
6
- def to_map(package)
7
- return unless path = package.audio_paths.first
8
- package.file(path).get_file { |mp3|
9
- Mp3Info.open(mp3) { |info|
10
- info.tag2.pictures.each { |desc, data|
11
- parts = [File.basename(desc), File.extname(desc)]
12
- path = Dir::Tmpname.create(parts) {}
13
- File.binwrite(path, data)
14
- package.file_system.set_file(desc, File.new(path))
15
- package.map['cover'] = { 'front' => {
16
- 'path' => desc,
17
- 'media-type' => Bookbinder::MediaType.of(desc)
18
- } }
19
- return
20
- }
21
- }
22
- }
23
- end
24
-
25
- end
@@ -1,27 +0,0 @@
1
- class Bookbinder::Transform::MP3Audiobook_Creator < Bookbinder::Transform
2
-
3
- TAG = 'TPE1'
4
-
5
-
6
- def dependencies
7
- [Bookbinder::Transform::MP3Audiobook_Metadata]
8
- end
9
-
10
-
11
- def to_map(package)
12
- return unless md = package.map['metadata']
13
- return unless md[TAG] && md[TAG].first
14
- creator = md[TAG].first['@']
15
- md.delete(TAG)
16
- creators = creator.split('/')
17
- package.map['creator'] = [{
18
- 'name' => creators.shift,
19
- 'role' => 'aut'
20
- }]
21
- package.map['creator'].push({
22
- 'name' => creators.shift,
23
- 'role' => 'nrt'
24
- }) if creators.any?
25
- end
26
-
27
- end
@@ -1,18 +0,0 @@
1
- class Bookbinder::Transform::MP3Audiobook_Description < Bookbinder::Transform
2
-
3
- TAG = 'COMM'
4
-
5
-
6
- def dependencies
7
- [Bookbinder::Transform::MP3Audiobook_Metadata]
8
- end
9
-
10
-
11
- def to_map(package)
12
- return unless md = package.map['metadata']
13
- return unless md[TAG] && md[TAG].first
14
- package.map['description'] = { 'full' => md[TAG].first['@'] }
15
- md.delete(TAG)
16
- end
17
-
18
- end
@@ -1,20 +0,0 @@
1
- class Bookbinder::Transform::MP3Audiobook_Metadata < Bookbinder::Transform
2
-
3
- SKIP_FIELDS = ['TRCK', 'TENC', 'APIC']
4
-
5
-
6
- def to_map(package)
7
- return unless path = package.audio_paths.first
8
- md = {}
9
- package.file(path).get_file { |mp3|
10
- Mp3Info.open(mp3) { |info|
11
- info.tag2.each_pair { |name, value|
12
- next if value == 'null' || SKIP_FIELDS.include?(name)
13
- md[name] = [md[name], { '@' => value }].flatten.compact
14
- }
15
- }
16
- }
17
- package.map['metadata'] = md
18
- end
19
-
20
- end
@@ -1,71 +0,0 @@
1
- # TXXX MediaMarker XML format is like this:
2
- #
3
- # OverDrive MediaMarkers\\x00<Markers><Marker><Name>Part I - Chapter 1</Name><Time>0:00.000</Time></Marker>... etc ...</Markers>
4
- #
5
- class Bookbinder::Transform::MP3Audiobook_NavToc < Bookbinder::Transform
6
-
7
- TAG = 'TXXX'
8
- MEDIAMARKER_PREFIX_RE = /^.*MediaMarkers[^<]*/
9
-
10
-
11
- def dependencies
12
- [Bookbinder::Transform::MP3Audiobook_Metadata]
13
- end
14
-
15
-
16
- def to_map(package)
17
- toc = []
18
- package.audio_paths.each { |aud_path|
19
- xml = nil
20
- package.file(aud_path).get_file { |mp3|
21
- Mp3Info.open(mp3) { |info| xml = info.tag2[TAG] }
22
- }
23
- next unless xml && xml.slice!(MEDIAMARKER_PREFIX_RE)
24
- doc = Nokogiri::XML(xml)
25
- doc.root.css('Marker').each { |marker_tag|
26
- arr = toc
27
- title = marker_tag.at_css('Name').content
28
- if title.match(/^[[:space:]]+/)
29
- arr = (toc.last['contents'] ||= [])
30
- title.gsub!(/^[[:space:]]+|[[:space:]]+$/, '')
31
- end
32
- seconds = translate_time(marker_tag.at_css('Time').content)
33
- arr << {
34
- 'title' => title,
35
- 'path' => "#{aud_path}#{seconds ? "##{seconds}" : ''}"
36
- }
37
- }
38
- }
39
- package.map['nav'] = { 'toc' => toc }
40
- if txxx = package.map['metadata'][TAG]
41
- txxx.delete_if { |val| val['@'].match(MEDIAMARKER_PREFIX_RE) }
42
- end
43
- package.map['metadata'].delete(TAG) if txxx.empty?
44
- end
45
-
46
-
47
- protected
48
-
49
- # MediaMarker time string comes in like:
50
- #
51
- # 74:48.000
52
- #
53
- # We should translate to 74*60+48.0 ==> 4488
54
- #
55
- def translate_time(time_str)
56
- if match = time_str.match(/^(\d+):(\d+):([\d\.]+)$/)
57
- minutes = match[1].to_i*60 + match[2].to_i
58
- seconds = match[3].to_f
59
- elsif match = time_str.match(/^(\d+):([\d\.]+)$/)
60
- minutes = match[1].to_i
61
- seconds = match[2].to_f
62
- else
63
- puts("Unknown time format: #{time_str}")
64
- return nil
65
- end
66
- seconds = seconds.round if seconds % 1 == 0
67
- out = minutes * 60 + seconds
68
- out > 0 ? out : nil
69
- end
70
-
71
- end
@@ -1,18 +0,0 @@
1
- class Bookbinder::Transform::MP3Audiobook_Publisher < Bookbinder::Transform
2
-
3
- TAG = 'TPUB'
4
-
5
-
6
- def dependencies
7
- [Bookbinder::Transform::MP3Audiobook_Metadata]
8
- end
9
-
10
-
11
- def to_map(package)
12
- return unless md = package.map['metadata']
13
- return unless md[TAG] && md[TAG].first
14
- package.map['publisher'] = md[TAG].first['@']
15
- md.delete(TAG)
16
- end
17
-
18
- end
@@ -1,7 +0,0 @@
1
- class Bookbinder::Transform::MP3Audiobook_Rendition < Bookbinder::Transform
2
-
3
- def to_map(package)
4
- package.map['rendition-format'] = 'audiobook'
5
- end
6
-
7
- end
@@ -1,33 +0,0 @@
1
- class Bookbinder::Transform::MP3Audiobook_Spine < Bookbinder::Transform
2
-
3
- def to_map(package)
4
- package.map['resources'] = []
5
- package.map['spine'] = package.audio_paths.collect { |path|
6
- {
7
- 'path' => path,
8
- 'media-type' => 'audio/mpeg'
9
- }.tap { |cmpt|
10
- break unless cmpt_info = audio_info(package, path)
11
- cmpt.update('audio-duration' => cmpt_info.length)
12
- cmpt.update('audio-bitrate' => cmpt_info.bitrate) unless cmpt_info.vbr
13
- }
14
- }
15
- end
16
-
17
-
18
- protected
19
-
20
- def audio_info(package, path)
21
- info = nil
22
- begin
23
- package.file(path).get_file { |mp3|
24
- Mp3Info.open(mp3) { |inf| info = inf }
25
- }
26
- rescue => e
27
- # TODO - is there error handling to do here?
28
- raise e
29
- end
30
- info
31
- end
32
-
33
- end
@@ -1,18 +0,0 @@
1
- class Bookbinder::Transform::MP3Audiobook_Subject < Bookbinder::Transform
2
-
3
- TAG = 'TCON'
4
-
5
-
6
- def dependencies
7
- [Bookbinder::Transform::MP3Audiobook_Metadata]
8
- end
9
-
10
-
11
- def to_map(package)
12
- return unless md = package.map['metadata']
13
- return unless md[TAG] && md[TAG].first
14
- package.map['subject'] = md[TAG].collect { |h| h['@'] }
15
- md.delete(TAG)
16
- end
17
-
18
- end
@@ -1,18 +0,0 @@
1
- class Bookbinder::Transform::MP3Audiobook_Title < Bookbinder::Transform
2
-
3
- TAG = 'TALB'
4
-
5
- def dependencies
6
- [Bookbinder::Transform::MP3Audiobook_Metadata]
7
- end
8
-
9
-
10
- def to_map(package)
11
- package.map['title'] = titles = {}
12
- return unless md = package.map['metadata']
13
- return unless md[TAG] && md[TAG].first
14
- titles['main'] = md[TAG].first['@']
15
- md.delete(TAG)
16
- end
17
-
18
- end