pubgen 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ doc
5
+ pkg
6
+ *.epub
7
+ .rvmrc
8
+ Gemfile.lock
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2012 Hyun Rae Cho
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the 'Software'), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,145 @@
1
+ # Pubgen
2
+
3
+ Pubgen is a simple command-line based epub generator. With the simple YAML
4
+ file, Pubgen generate the epub file for you.
5
+
6
+ ## Installation
7
+
8
+ ```bash
9
+ $ # First, install Ruby and then
10
+ $ gem install pubgen
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```bash
16
+ $ pubgen -h
17
+ pubgen 0.1.0, a epub generator.
18
+
19
+ Usage:
20
+ pubgen <yaml file> [-o <epub file>] [-v]
21
+ pubgen <yaml file> -m
22
+
23
+ -o, --output EPUB_PATH Specify output epub file path
24
+ -m, --meta-file-only Generate .opf, .ncx, mimetype, ...
25
+ -v, --verbose Verbose output
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ Prepare files (documents, images, style sheets, etc.) that make up the
31
+ publication. iBooks requires strict xhtml format,
32
+ [`tidy -asxhtml`] (http://tidy.sourceforge.net/) will be helpful.
33
+
34
+ ```bash
35
+ $ find .
36
+ .
37
+ ./contents
38
+ ./contents/a-1.html
39
+ ./contents/a-2.html
40
+ ./contents/a.html
41
+ ./contents/b.html
42
+ ./images
43
+ ./images/1.jpg
44
+ ./images/2.jpg
45
+ ./images/3.jpg
46
+ ./images/cover.jpg
47
+ ./style.css
48
+ ```
49
+ Create the YAML file describing your publication. As a example,
50
+ `will_oldham.yml`.
51
+
52
+ ```yaml
53
+ # METADATA: Publication metadata (title, author, publisher, etc.).
54
+ #
55
+ # See http://idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.2
56
+ # -*- encoding: utf-8 -*-
57
+ metadata:
58
+ title: "Will Oldham: Wikipedia, the free encyclopedia"
59
+ creator: Wikipedia
60
+ date: 2012
61
+ language: en
62
+ subject: American alternative country singers
63
+ publisher:
64
+ contrubuter:
65
+ description:
66
+ source: "http://en.wikipedia.org/wiki/Will_Oldham"
67
+ rights:
68
+ relation:
69
+
70
+ # GUIDE: A set of references to fundamental structural features of the
71
+ # publication, such as table of contents, foreword, bibliography, etc.
72
+ #
73
+ # See http://idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.6
74
+ guide:
75
+ toc-page:
76
+ title-page:
77
+ # If you provide cover-image without cover-page, pubgen automatically
78
+ # generate cover-page xhtml, and add it to manifest and spine
79
+ cover-image: images/cover.jpg
80
+ cover-page:
81
+
82
+ # MANIFEST: A list of files (documents, images, style sheets, etc.) that make
83
+ # up the publication.
84
+ #
85
+ # All the files in manifest ought to be in the same or sub-directory of yaml.
86
+ # Say yaml's path is /book/a.yaml.
87
+ # - a/b/c.html # good. in the sub-directory
88
+ # - d.jpg # good. in the same directory
89
+ # - ./e.jpg # good. in the same directory
90
+ # - /a/b/c.html # bad. in the different directory
91
+ # - ../d.png # bad. in the parent directory
92
+ # - /book/e.html # bad. although in the same directory
93
+ # - ../book/f.png # bad. although in the same directory
94
+ manifest:
95
+ - contents/a.html
96
+ - contents/a-1.html
97
+ - contents/a-2.html
98
+ - contents/b.html
99
+ - images/cover.jpg
100
+ - images/1.jpg
101
+ - images/2.jpg
102
+ - images/3.jpg
103
+ - style.css
104
+
105
+ # SPINE: An arrangement of documents providing a linear reading order.
106
+ spine:
107
+ - contents/a.html
108
+ - contents/a-1.html
109
+ - contents/a-2.html
110
+ - contents/b.html
111
+
112
+ # TOC: Table of contents
113
+ toc:
114
+ - Music -- contents/a.html: # don't forget colon to indent
115
+ - Discography -- contents/a-1.html
116
+ - Response -- contents/a-2.html
117
+ - Film -- contents/b.html
118
+ ```
119
+
120
+ Run pubgen.
121
+
122
+ ```bash
123
+ $ pubgen /path/to/will_oldham.yml -v
124
+ mkdir .pubgen-4f4a210e
125
+ cp ./contents/a.html .pubgen-4f4a210e/contents
126
+ cp ./contents/a-1.html .pubgen-4f4a210e/contents
127
+ cp ./contents/a-2.html .pubgen-4f4a210e/contents
128
+ cp ./contents/b.html .pubgen-4f4a210e/contents
129
+ cp ./images/cover.jpg .pubgen-4f4a210e/images
130
+ cp ./images/1.jpg .pubgen-4f4a210e/images
131
+ cp ./images/2.jpg .pubgen-4f4a210e/images
132
+ cp ./images/3.jpg .pubgen-4f4a210e/images
133
+ cp ./style.css .pubgen-4f4a210e/.
134
+ cd .pubgen-4f4a210e
135
+ cat > META-INF/container.xml
136
+ cat > mimetype
137
+ cat > cover-pubgen.xhtml
138
+ cat > content.opf
139
+ cat > toc.ncx
140
+ zip > pubgen.epub
141
+ cd /path/to/pwd
142
+ mv .pubgen-4f4a210e /pubgen.epub 'Will Oldham_ Wikipedia, the free encyclopedia.epub'
143
+ rm -rf .pubgen-4f4a210e
144
+ # Successfully generated 'Will Oldham_ Wikipedia, the free encyclopedia.epub'
145
+ ```
@@ -0,0 +1,211 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ PACKAGE = 'pubgen'
4
+ VERSION = '0.1.0'
5
+
6
+ require 'yaml'
7
+ require 'fileutils'
8
+ require 'optparse'
9
+
10
+ require 'zipruby'
11
+
12
+ $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
13
+ require 'pubgen'
14
+
15
+ HELP = <<EOF
16
+ #{PACKAGE} #{VERSION}, a epub generator.
17
+
18
+ Usage:
19
+ #{PACKAGE} <yaml file> [-o <epub file>] [-v]
20
+ #{PACKAGE} <yaml file> -m
21
+
22
+ EOF
23
+
24
+ options = {}
25
+ opts = OptionParser.new do |opts|
26
+ opts.banner = HELP
27
+
28
+ opts.on('-o', '--output EPUB_PATH', 'Specify output epub file path') do |epub_path|
29
+ options[:epub_path] = epub_path
30
+ end
31
+
32
+ opts.on('-m', '--meta-file-only', 'Generate .opf, .ncx, mimetype, ...') do |m|
33
+ options[:meta_file_only] = m
34
+ end
35
+
36
+ opts.on('-v', '--verbose', 'Verbose output') do |v|
37
+ options[:verbose] = v
38
+ end
39
+ end
40
+ opts.parse!(ARGV)
41
+
42
+ # check options validity
43
+ if (options[:meta_file_only] == true && options[:epub_path] != nil)
44
+ $stderr << <<EOF
45
+ #{PACKAGE}: `--meta-file-only' with `--output EPUB_PATH', not allowed
46
+
47
+ Try `#{PACKAGE} -h' for more informations
48
+ EOF
49
+ exit 1
50
+ end
51
+
52
+ if ARGV.size != 1
53
+ $stderr << <<EOF
54
+ #{PACKAGE}: specify one yaml file
55
+
56
+ Try `#{PACKAGE} -h' for more informations
57
+ EOF
58
+ exit 1
59
+ else
60
+ options[:yaml_path] = ARGV[0]
61
+ end
62
+
63
+ begin
64
+ yaml = YAML::load File.open(options[:yaml_path])
65
+ rescue Exception=>e
66
+ pubgen_err("While loading yaml: " + e.to_s)
67
+ exit 1
68
+ end
69
+
70
+ if yaml['metadata']['title'] == nil
71
+ pubgen_err("Failed to find the value of 'title' attribute in: " + options[:yaml_path])
72
+ exit 1
73
+ end
74
+
75
+ # if `--output EPUB_PATH' is not given. get it from yaml
76
+ if !options[:meta_file_only] && !options[:epub_path]
77
+ options[:epub_path] = yaml['metadata']['title'] + ".epub"
78
+ options[:epub_path].gsub!(/[\/:?]/, "_") # file-system friendly
79
+ end
80
+ # now, options done
81
+
82
+ # just for one line
83
+ def pubgen_log(log, verbose = true)
84
+ $stdout << log + "\n" if verbose
85
+ end
86
+
87
+ # just for one line
88
+ def pubgen_err(err)
89
+ $stderr << '# ' + err + "\n"
90
+ end
91
+
92
+ yaml['metadata']['creator'] = "#{PACKAGE}-#{VERSION}" if yaml['metadata']['creator'] == nil
93
+ yaml['metadata']['contributor'] = "#{PACKAGE}-#{VERSION}" if yaml['metadata']['contributor'] == nil
94
+
95
+ $tmpdir = ""
96
+ $pwd_old = Dir.pwd
97
+ $exit_code = 0
98
+
99
+ begin
100
+ if !options[:meta_file_only]
101
+ # we need temporal working directory
102
+ $tmpdir = ".pubgen-%08x" % Time.now.to_i
103
+ Dir.mkdir($tmpdir)
104
+ pubgen_log("mkdir " + $tmpdir, options[:verbose])
105
+
106
+ # copy all files of manifest to $tmpdir
107
+ yaml['manifest'].each do |file|
108
+ if Pubgen::OPF.valid_manifest_element?(file) == false
109
+ raise "Invalid manifest (not in sub-directory of yaml file): " + file
110
+ end
111
+ target_dir = "#{$tmpdir}/#{File.dirname(file)}"
112
+ FileUtils.mkdir_p(target_dir)
113
+ FileUtils.cp("#{File.dirname(options[:yaml_path])}/#{file}", target_dir, :verbose=>options[:verbose])
114
+ end
115
+
116
+ # change pwd
117
+ Dir.chdir($tmpdir)
118
+ pubgen_log("cd " + $tmpdir, options[:verbose])
119
+ end
120
+
121
+ # generate container.xml
122
+ # it's name and path are fixed (META-INF/container.xml)
123
+ Dir.mkdir('META-INF') if !File::directory?('META-INF')
124
+ container = File.new('META-INF/container.xml', 'w')
125
+ container.write(Pubgen::Container.generate)
126
+ container.close
127
+ pubgen_log('cat > META-INF/container.xml', options[:meta_file_only] || options[:verbose])
128
+
129
+ # generate mimetype
130
+ # it's name and path are also fixed (./mimetype)
131
+ mimetype = File.new('mimetype', 'w')
132
+ mimetype.write('application/epub+zip')
133
+ mimetype.close
134
+ pubgen_log('cat > mimetype', options[:meta_file_only] || options[:verbose])
135
+
136
+ # pubgen automatically generates cover page if cover-image is given without
137
+ # cover-page
138
+ if Pubgen::CoverPage.need_to_generate?(yaml['guide'])
139
+ COVER_PAGE_PATH = 'cover-pubgen.xhtml'
140
+ cover_page = File.new(COVER_PAGE_PATH, 'w')
141
+ cover_page.write(Pubgen::CoverPage.generate(yaml['guide']['cover-image']))
142
+ cover_page.close
143
+ pubgen_log("cat > " + COVER_PAGE_PATH, options[:meta_file_only] || options[:verbose])
144
+
145
+ # add/set it to manifest, spine, and cover-page
146
+ yaml['manifest'] << COVER_PAGE_PATH
147
+ yaml['spine'].unshift(COVER_PAGE_PATH)
148
+ yaml['guide']['cover-page'] = COVER_PAGE_PATH
149
+ end
150
+
151
+ # generate uuid
152
+ uuid = "%08x" % Time.now.to_i + "-" + [4,4,4,12].map {|l| "%0#{l}x" % rand(1 << l*4) }.join('-')
153
+ # require 'uuid'
154
+ # uuid = UUID.new.generate
155
+
156
+ # generate opf file
157
+ opf = File.new(Pubgen::Container.opf_path, 'w')
158
+ opf.write(Pubgen::OPF.generate(yaml, uuid))
159
+ opf.close
160
+ pubgen_log("cat > " + Pubgen::Container.opf_path, options[:meta_file_only] || options[:verbose])
161
+ # pubgen automatically added ncx file to opf's manifest (but not to yaml[]'s)
162
+
163
+ # generate ncx file
164
+ ncx = File.new(Pubgen::OPF.ncx_path, 'w')
165
+ ncx.write(Pubgen::NCX.generate(yaml['metadata']['title'], yaml['toc'], uuid))
166
+ ncx.close
167
+ pubgen_log("cat > " + Pubgen::OPF.ncx_path, options[:meta_file_only] || options[:verbose])
168
+
169
+ # generate epub
170
+ if !options[:meta_file_only]
171
+ Zip::Archive.open("pubgen.epub", Zip::CREATE | Zip::TRUNC) do |ar|
172
+ Dir.glob('**/*').each do |path|
173
+ if File.directory?(path)
174
+ ar.add_dir(path)
175
+ else
176
+ ar.add_file(path, path)
177
+ end
178
+ end
179
+ end
180
+ pubgen_log("zip > pubgen.epub", options[:verbose])
181
+
182
+ # mv pubgen.epub to options[:epub_path]
183
+ Dir.chdir($pwd_old)
184
+ pubgen_log("cd " + $pwd_old, options[:verbose])
185
+ FileUtils.mv($tmpdir + "/pubgen.epub", options[:epub_path])
186
+ pubgen_log("mv #{$tmpdir} /pubgen.epub '#{options[:epub_path]}'", options[:verbose])
187
+ end
188
+ rescue Exception=>e
189
+ $exit_code = 1
190
+ pubgen_err(e.to_s)
191
+ ensure
192
+ # remove $tmpdir
193
+ if Dir.pwd != $pwd_old
194
+ Dir.chdir($pwd_old)
195
+ pubgen_log("cd " + $pwd_old, options[:verbose])
196
+ end
197
+ if File::directory?($tmpdir)
198
+ FileUtils.rm_rf($tmpdir)
199
+ pubgen_log("rm -rf " + $tmpdir, options[:verbose])
200
+ end
201
+ end
202
+
203
+ if $exit_code == 0 && !options[:meta_file_only]
204
+ if options[:verbose]
205
+ pubgen_log("# Successfully generated '#{options[:epub_path]}'")
206
+ else
207
+ pubgen_log("zip > '#{options[:epub_path]}'")
208
+ end
209
+ end
210
+
211
+ exit $exit_code
@@ -0,0 +1,4 @@
1
+ require 'pubgen/cover_page'
2
+ require 'pubgen/ncx'
3
+ require 'pubgen/opf'
4
+ require 'pubgen/container'
@@ -0,0 +1,20 @@
1
+ module Pubgen
2
+ module Container
3
+ def self.opf_path
4
+ 'content.opf'
5
+ end
6
+
7
+ def self.generate
8
+ <<EOF
9
+ <?xml version="1.0"?>
10
+ <container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container"
11
+ >
12
+ <rootfiles>
13
+ <rootfile full-path="#{opf_path}" media-type="application/oebps-package+xml"
14
+ />
15
+ </rootfiles>
16
+ </container>
17
+ EOF
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ module Pubgen
2
+ module CoverPage
3
+ def self.need_to_generate?(guide)
4
+ guide['cover-image'] != nil && guide['cover-page'] == nil
5
+ end
6
+
7
+ def self.generate(cover_image)
8
+ <<EOF
9
+ <?xml version='1.0' encoding='utf-8'?>
10
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
11
+ <head>
12
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
13
+ <meta name="pubgen:cover" content="true"/>
14
+ <title>Cover</title>
15
+ <style type="text/css" title="override_css">
16
+ @page {padding: 0pt; margin:0pt}
17
+ body { text-align: center; padding:0pt; margin: 0pt; }
18
+ </style>
19
+ </head>
20
+ <body>
21
+ <div>
22
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100%" height="100%" viewBox="0 0 469 616" preserveAspectRatio="xMinYMin">
23
+ <image width="469" height="616" xlink:href="#{cover_image}"/>
24
+ </svg>
25
+ </div>
26
+ </body>
27
+ </html>
28
+ EOF
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,90 @@
1
+ module Pubgen
2
+ module NCX
3
+ def self.generate(title, toc, uuid)
4
+ # header
5
+ toc_xml = TOC_XML_HEADER_FORMAT % [uuid, CGI.escapeHTML(title || '')]
6
+ # NavPoint traces indentation, so we need class and instantiation of it
7
+ nav_point = NavPointImpl.new
8
+ toc.each do |name_and_path|
9
+ toc_xml += nav_point.generate(name_and_path)
10
+ end
11
+ # footer
12
+ toc_xml += TOC_XML_FOOTER
13
+ end
14
+
15
+ # define NavPointImpl class and some constants
16
+ # they are all private, only Pubgen.NCX.generate use them
17
+ NAVPOINT_XML_HEADER_FORMAT = <<EOF
18
+ <navPoint id="d%03d" playOrder="%d">
19
+ <navLabel>
20
+ <text>%s</text>
21
+ </navLabel>
22
+ <content src="%s"/>
23
+ EOF
24
+ NAVPOINT_XML_FOOTER = " </navPoint>\n"
25
+ TOC_XML_HEADER_FORMAT = <<EOF
26
+ <?xml version='1.0' encoding='utf-8'?>
27
+ <ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1" xml:lang="en">
28
+ <head>
29
+ <meta content="%s" name="dtb:uid"/>
30
+ <meta content="2" name="dtb:depth"/>
31
+ <meta content="pubgen" name="dtb:generator"/>
32
+ <meta content="0" name="dtb:totalPageCount"/>
33
+ <meta content="0" name="dtb:maxPageNumber"/>
34
+ </head>
35
+ <docTitle>
36
+ <text>%s</text>
37
+ </docTitle>
38
+ <navMap>
39
+ EOF
40
+ TOC_XML_FOOTER = " </navMap>\n</ncx>"
41
+
42
+ class NavPointImpl
43
+ private
44
+ def generate_impl(name_and_path, depth)
45
+ header = NAVPOINT_XML_HEADER_FORMAT
46
+ footer = NAVPOINT_XML_FOOTER
47
+ @toc_indent_order += 1
48
+ if depth
49
+ depth.times do
50
+ header = header.gsub(/^/, ' ')
51
+ footer = footer.gsub(/^/, ' ')
52
+ end
53
+ end
54
+
55
+ navpoint_xml = ''
56
+ if name_and_path.is_a?(String)
57
+ if name_and_path.split(" -- ").size != 2
58
+ raise "Bad toc contents format: " + name_and_path
59
+ end
60
+ navpoint_xml = header % [@toc_indent_order, @toc_indent_order,
61
+ CGI.escapeHTML(name_and_path.split(" -- ")[0]),
62
+ name_and_path.split(" -- ")[1]]
63
+ else
64
+ # if not string, it's hash map with just one element
65
+ name_and_path.each do |key, value|
66
+ if key.split(" -- ").size != 2
67
+ raise "Bad toc contents format: " + key
68
+ end
69
+ navpoint_xml = header % [@toc_indent_order, @toc_indent_order,
70
+ CGI.escapeHTML(key.split(" -- ")[0]), key.split(" -- ")[1]]
71
+ value.each do |v|
72
+ navpoint_xml += generate_impl(v, depth + 1)
73
+ end
74
+ end
75
+ end
76
+
77
+ navpoint_xml += footer
78
+ end
79
+
80
+ public
81
+ def initialize
82
+ @toc_indent_order = 0
83
+ end
84
+
85
+ def generate(name_and_path)
86
+ generate_impl(name_and_path, 0)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,166 @@
1
+ require 'cgi'
2
+
3
+ module Pubgen
4
+ module OPF
5
+ def self.ncx_path
6
+ NCX_PATH
7
+ end
8
+
9
+ def self.generate(yaml, uuid)
10
+ cover_id, manifest_xml, file2id =
11
+ OPFImpl.get_cover_id_and_manifest_xml(yaml['guide']['cover-image'],
12
+ yaml['manifest'])
13
+ metadata_xml = OPFImpl.get_metadata_xml(yaml['metadata'], uuid, cover_id)
14
+ spine_xml = OPFImpl.get_spine_xml(yaml['spine'], file2id)
15
+ guide_xml = OPFImpl.get_guide_xml(yaml['guide'], file2id)
16
+ return OPF_XML_HEADER + metadata_xml + manifest_xml + spine_xml +
17
+ guide_xml + OPF_XML_FOOTER
18
+ end
19
+
20
+ def self.valid_manifest_element?(e)
21
+ e[0..2] != "../" && e[0] != "/"
22
+ end
23
+
24
+ # define OPFImpl class and some constants
25
+ # they are all private, only Pubgen.OPF.generate use them
26
+ NCX_PATH = "toc.ncx"
27
+ METADATA_FORMAT = <<EOF
28
+ <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
29
+ <dc:title>%s</dc:title>
30
+ <dc:creator opf:role="aut">%s</dc:creator>
31
+ <dc:date>%s</dc:date>
32
+ <dc:language>%s</dc:language>
33
+ <dc:subject>%s</dc:subject>
34
+ <dc:publisher>%s</dc:publisher>
35
+ <dc:description>%s</dc:description>
36
+ <dc:contributor opf:role="bkp">%s</dc:contributor>
37
+ <dc:source>%s</dc:source>
38
+ <dc:rights>%s</dc:rights>
39
+ <dc:relation>%s</dc:relation>
40
+ <dc:identifier id="BookID" opf:scheme="UUID">%s</dc:identifier>%s
41
+ </metadata>
42
+ EOF
43
+ OPF_XML_HEADER = <<EOF
44
+ <?xml version='1.0' encoding='utf-8'?>
45
+ <package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="uuid_id">
46
+ EOF
47
+ OPF_XML_FOOTER = '</package>'
48
+
49
+ module OPFImpl
50
+ def self.guess_media_type(filename)
51
+ case filename.downcase
52
+ when /.*\.x?html?$/i
53
+ 'application/xhtml+xml'
54
+ when /.*\.css$/i
55
+ 'text/css'
56
+ when /.*\.(jpeg|jpg)$/
57
+ 'image/jpeg'
58
+ when /.*\.png$/i
59
+ 'image/png'
60
+ when /.*\.gif$/i
61
+ 'image/gif'
62
+ when /.*\.svg$/i
63
+ 'image/svg+xml'
64
+ when /.*\.ncx$/i
65
+ 'application/x-dtbncx+xml'
66
+ when /.*\.opf$/i
67
+ 'application/oebps-package+xml'
68
+ else
69
+ 'application/octet-stream'
70
+ end
71
+ end
72
+
73
+ def self.get_cover_id_and_manifest_xml(cover_path, manifest)
74
+ no = 1;
75
+ manifest_xml = " <manifest>\n"
76
+ cover_id = nil
77
+ file2id = {}
78
+
79
+ manifest.each do |path|
80
+ if OPF.valid_manifest_element?(path) == false
81
+ raise "One of manifest element (" + path + ") is not in sub-directory of yaml file"
82
+ end
83
+ id = "i%03d" % no
84
+ manifest_xml += " <item id=\"#{id}\" href=\"#{path}\" media-type=\"#{guess_media_type(path)}\"/>\n"
85
+ if path == cover_path
86
+ cover_id = id
87
+ end
88
+ file2id[path] = id
89
+
90
+ no += 1
91
+ end
92
+
93
+ if cover_path && cover_id == nil
94
+ raise "Can't find cover-image from manifest"
95
+ end
96
+
97
+ manifest_xml += " <item id=\"ncx\" href=\"#{NCX_PATH}\" media-type=\"application/x-dtbncx+xml\"/>\n </manifest>\n"
98
+
99
+ return cover_id, manifest_xml, file2id
100
+ end
101
+
102
+ def self.get_metadata_xml(metadata, uuid, cover_id)
103
+ cover_id_xml = ''
104
+ if cover_id != nil
105
+ cover_id_xml = "\n <meta name=\"cover\" content=\"%s\"/>" % cover_id
106
+ end
107
+ METADATA_FORMAT % [
108
+ CGI.escapeHTML(metadata['title'] || ''),
109
+ CGI.escapeHTML(metadata['creator'] || ''),
110
+ CGI.escapeHTML((metadata['date'].is_a?(Fixnum) ?
111
+ metadata['date'].to_s : metadata['date']) || ''),
112
+ CGI.escapeHTML(metadata['language'] || ''),
113
+ CGI.escapeHTML(metadata['subject'] || ''),
114
+ CGI.escapeHTML(metadata['publisher'] || ''),
115
+ CGI.escapeHTML(metadata['description'] || ''),
116
+ CGI.escapeHTML(metadata['contributor'] || ''),
117
+ CGI.escapeHTML(metadata['source'] || ''),
118
+ CGI.escapeHTML(metadata['rights'] || ''),
119
+ CGI.escapeHTML(metadata['relation'] || ''),
120
+ uuid, cover_id_xml
121
+ ]
122
+ end
123
+
124
+ def self.get_guide_xml(guide, file2id)
125
+ guide_xml = " <guide>\n"
126
+ cover_page = guide['cover-page']
127
+ if cover_page != nil
128
+ if file2id[cover_page] == nil
129
+ raise "Can't find cover-page from manifest"
130
+ else
131
+ guide_xml += " <reference href=\"%s\" type=\"cover\" title=\"Cover\"/>\n" % cover_page
132
+ end
133
+ end
134
+ toc_page = guide['toc-page']
135
+ if toc_page != nil
136
+ if file2id[toc_page] == nil
137
+ raise "Can't find toc-page from manifest"
138
+ else
139
+ guide_xml += " <reference href=\"%s\" type=\"toc\" title=\"Table of Contents\"/>\n" % toc_page
140
+ end
141
+ end
142
+ title_page = guide['title-page']
143
+ if title_page != nil
144
+ if file2id[title_page] == nil
145
+ raise "Can't find title-page from manifest"
146
+ else
147
+ guide_xml += " <reference href=\"%s\" type=\"title-page\" title=\"Title Page\"/>\n" % toc_page
148
+ end
149
+ end
150
+ guide_xml += " </guide>\n"
151
+ end
152
+
153
+ def self.get_spine_xml(spine, file2id)
154
+ spine_xml = " <spine toc=\"ncx\">\n"
155
+ spine.each do |path|
156
+ if file2id[path] != nil
157
+ spine_xml += " <itemref idref=\"#{file2id[path]}\"/>\n"
158
+ else
159
+ raise "Can't find spine element `#{path}' from manifest"
160
+ end
161
+ end
162
+ spine_xml += " </spine>\n"
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "pubgen"
5
+ s.version = "0.1.0"
6
+ s.platform = Gem::Platform::RUBY
7
+ s.author = "9beach"
8
+ s.email = ["9beach@gmail.com"]
9
+ s.homepage = "https://github.com/9beach/pubgen"
10
+ s.files = `git ls-files`.split("\n")
11
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ s.bindir = 'bin'
13
+ s.require_paths = ["lib"]
14
+ s.summary = "command-line based epub generator"
15
+ s.description = "Pubgen is a simple command-line based epub generator. With the simple YAML file, Pubgen generate the epub file for you."
16
+ s.add_dependency "rubyzip"
17
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pubgen
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - 9beach
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-26 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rubyzip
16
+ requirement: &2157457660 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2157457660
25
+ description: Pubgen is a simple command-line based epub generator. With the simple
26
+ YAML file, Pubgen generate the epub file for you.
27
+ email:
28
+ - 9beach@gmail.com
29
+ executables:
30
+ - pubgen
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - .gitignore
35
+ - LICENSE
36
+ - README.md
37
+ - bin/pubgen
38
+ - lib/pubgen.rb
39
+ - lib/pubgen/container.rb
40
+ - lib/pubgen/cover_page.rb
41
+ - lib/pubgen/ncx.rb
42
+ - lib/pubgen/opf.rb
43
+ - pubgen.gemspec
44
+ homepage: https://github.com/9beach/pubgen
45
+ licenses: []
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ requirements: []
63
+ rubyforge_project:
64
+ rubygems_version: 1.8.15
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: command-line based epub generator
68
+ test_files: []