kindlerb 0.1.1 → 1.0.1

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.
data/_document.yml.sample CHANGED
@@ -1,7 +1,7 @@
1
- doc_uuid:
2
- title:
3
- author:
4
- publisher:
5
- subject: News
6
- date: 2012-01-04
7
-
1
+ doc_uuid:
2
+ title:
3
+ author:
4
+ publisher:
5
+ subject: News
6
+ date: 2012-01-04
7
+
data/bin/setupkindlerb ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'kindlerb'
3
+
4
+ Kindlerb.download
5
+
6
+ puts "Kindlerb is successfully set up!"
data/kindlerb.gemspec CHANGED
@@ -1,26 +1,25 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "kindlerb"
4
-
5
- Gem::Specification.new do |s|
6
- s.name = "kindlerb"
7
- s.version = Kindlerb::VERSION
8
- s.platform = Gem::Platform::RUBY
9
- s.required_ruby_version = '>= 1.9.0'
10
-
11
- s.authors = ["Daniel Choi"]
12
- s.email = ["dhchoi@gmail.com"]
13
- s.homepage = "http://github.com/danchoi/kindlerb"
14
- s.summary = %q{Kindle eperiodical generator}
15
- s.description = %q{Kindle eperiodical generator}
16
-
17
- s.rubyforge_project = "kindlerb"
18
-
19
- s.files = `git ls-files`.split("\n")
20
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
- s.require_paths = ["lib"]
23
-
24
- s.add_dependency 'nokogiri'
25
- s.add_dependency 'mustache'
26
- end
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "kindlerb"
6
+ s.version = '1.0.1'
7
+ s.platform = Gem::Platform::RUBY
8
+ s.required_ruby_version = '>= 2.0.0'
9
+
10
+ s.authors = ["Daniel Choi", "Emir Aydin"]
11
+ s.email = ["dhchoi@gmail.com", "emir@emiraydin.com"]
12
+ s.homepage = "http://github.com/danchoi/kindlerb"
13
+ s.summary = %q{Kindle eperiodical generator}
14
+ s.description = %q{Kindle eperiodical generator}
15
+
16
+ s.rubyforge_project = "kindlerb"
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+
23
+ s.add_dependency 'nokogiri'
24
+ s.add_dependency 'mustache'
25
+ end
data/lib/kindlerb.rb CHANGED
@@ -1,146 +1,232 @@
1
- # encoding: utf-8
2
-
3
- unless `which kindlegen` =~ /kindlegen/
4
- abort "Please install kindlegen on your path"
5
- end
6
-
7
- # extract nav structure
8
-
9
- require 'pathname'
10
- require 'yaml'
11
- require 'nokogiri'
12
- require 'mustache'
13
- require 'fileutils'
14
-
15
- # monkeypatch
16
- class String
17
- def shorten(max)
18
- length > max ? Array(self[0,max].split(/\s+/)[0..-2]).join(' ') + '...' : self
19
- end
20
- end
21
-
22
-
23
- module Kindlerb
24
- VERSION = '0.1.1'
25
-
26
- def self.run
27
-
28
- target_dir = Pathname.new(ARGV.first || '.')
29
-
30
- opf_template = File.read(File.join(File.dirname(__FILE__), '..', "templates/opf.mustache"))
31
- ncx_template = File.read(File.join(File.dirname(__FILE__), '..', "templates/ncx.mustache"))
32
- contents_template = File.read(File.join(File.dirname(__FILE__), '..', "templates/contents.mustache"))
33
- section_template = File.read(File.join(File.dirname(__FILE__), '..', "templates/section.mustache"))
34
- masthead_gif = File.join(File.dirname(__FILE__), '..', "templates/masthead.gif")
35
- cover_gif = File.join(File.dirname(__FILE__), '..', "templates/cover-image.gif")
36
-
37
- Dir.chdir target_dir do
38
- playorder = 1
39
-
40
- images = []
41
- manifest_items = []
42
-
43
- unless File.exist?("_document.yml")
44
-
45
- puts "Usage: kindlerb [target file directory]"
46
-
47
- abort "Missing _document.yml. Your input file tree is not structured correctly. Please read the README."
48
- end
49
-
50
- document = YAML::load_file("_document.yml")
51
-
52
- document[:spine_items] = []
53
- section_html_files = []
54
-
55
- sections = Dir['sections/*'].entries.sort.map.with_index {|section_dir|
56
- c = File.read(Pathname.new(section_dir) + '_section.txt')
57
- c.force_encoding("UTF-8")
58
- section_title = c.strip
59
- articles = Dir[Pathname.new(section_dir) + '*'].entries.select {|x| File.basename(x) !~ /section/}.sort
60
- section_html_files << (section_html_file = (Pathname.new(section_dir) + 'section.html').to_s)
61
- idref = "item-#{section_dir.gsub(/\D/, '')}"
62
-
63
- document[:spine_items] << {:idref => idref}
64
- manifest_items << {
65
- :href => section_html_file,
66
- :media => "application/xhtml+xml",
67
- :idref => idref
68
- }
69
-
70
- s = {
71
- :path => section_dir,
72
- :title => section_title.shorten(40),
73
- :playorder => (playorder += 1),
74
- :idref => idref,
75
- :href => Pathname.new(section_dir) + 'section.html',
76
- :articles => articles.map {|article_file|
77
- doc = Nokogiri::HTML(File.read(article_file))
78
- article_images = doc.search("img").map {|img|
79
- mimetype = img[:src] ? "image/#{File.extname(img[:src]).sub('.', '')}" : nil
80
- {:href => img[:src], :mimetype => mimetype}
81
- }
82
- images.push *article_images
83
- title = doc.search("html/head/title").map(&:inner_text).first || "no title"
84
- idref = "item-#{article_file.gsub(/\D/, '')}"
85
- document[:spine_items] << {:idref => idref}
86
- article = {
87
- :file => article_file,
88
- :href => article_file,
89
- :title => title,
90
- :short_title => title.shorten(60),
91
- :author => doc.search("html/head/meta[@name=author]").map{|n|n[:content]}.first,
92
- :description => doc.search("html/head/meta[@name=description]").map{|n|n[:content]}.first,
93
- :playorder => (playorder += 1),
94
- :idref => idref
95
- }
96
- manifest_items << {
97
- :href => article[:file],
98
- :media => "application/xhtml+xml",
99
- :idref => article[:idref]
100
- }
101
- article
102
- }
103
- }
104
-
105
- # Generate the section html
106
- out = Mustache.render section_template, s
107
- File.open(section_html_file, "w") {|f| f.puts out}
108
- s
109
-
110
- }
111
-
112
- document[:first_article] = sections[0][:articles][0]
113
- document['sections'] = sections
114
-
115
-
116
- document[:manifest_items] = manifest_items + images.map.with_index {|img, idx|
117
- {
118
- :href => img[:href],
119
- :media => img[:mimetype],
120
- :idref => "img-%03d" % idx
121
- }
122
- }
123
- document[:cover_mimetype] ||= "image/gif"
124
-
125
- opf = Mustache.render opf_template, document
126
- File.open("kindlerb.opf", "w") {|f| f.puts opf}
127
- puts "Wrote #{target_dir}/kindlerb.opf"
128
-
129
- # NCX
130
- ncx = Mustache.render ncx_template, document
131
- File.open("nav-contents.ncx", "w") {|f| f.puts ncx}
132
- puts "Wrote #{target_dir}/nav-contents.ncx"
133
-
134
- # contents
135
- contents = Mustache.render contents_template, document
136
- File.open("contents.html", "w") {|f| f.puts contents}
137
- puts "Wrote #{target_dir}/contents.html"
138
-
139
- outfile = document['mobi_outfile']
140
- puts "Writing #{outfile}"
141
- cmd = "kindlegen -verbose -c2 -o #{outfile} kindlerb.opf && echo 'Wrote MOBI to #{outfile}'"
142
- puts cmd
143
- exec cmd
144
- end
145
- end
146
- end
1
+ # encoding: utf-8
2
+
3
+ # extract nav structure
4
+
5
+ require 'pathname'
6
+ require 'yaml'
7
+ require 'nokogiri'
8
+ require 'mustache'
9
+ require 'fileutils'
10
+
11
+ # monkeypatch
12
+ class String
13
+ def shorten(max)
14
+ length > max ? Array(self[0,max].split(/\s+/)[0..-2]).join(' ') + '...' : self
15
+ end
16
+ end
17
+
18
+ module Kindlerb
19
+
20
+ def self.download
21
+
22
+ gem_path = Gem::Specification.find_by_name('kindlerb').gem_dir
23
+ ext_dir = gem_path + '/ext/'
24
+ bin_dir = gem_path + '/bin/'
25
+
26
+ # Define Kindlegen download files for different OS's
27
+ executable = 'kindlegen'
28
+ windows = false
29
+ compressed_file = case RbConfig::CONFIG['host_os']
30
+ when /mac|darwin/i
31
+ extract = 'unzip '
32
+ "KindleGen_Mac_i386_v2_9.zip"
33
+ when /linux|cygwin/i
34
+ extract = 'tar zxf '
35
+ "kindlegen_linux_2.6_i386_v2_9.tar.gz"
36
+ when /mingw32/i
37
+ windows = true
38
+ extract = 'unzip '
39
+ executable = 'kindlegen.exe'
40
+ "kindlegen_win32_v2_9.zip"
41
+ else
42
+ STDERR.puts "Host OS is not supported!"
43
+ exit(1)
44
+ end
45
+
46
+ url = 'http://kindlegen.s3.amazonaws.com/' + compressed_file
47
+
48
+ # Download and extract the Kindlegen file into gem's /etc folder
49
+ unless File.directory?(ext_dir)
50
+ FileUtils.mkdir_p(ext_dir)
51
+ end
52
+ system 'curl ' + url + ' -o ' + ext_dir + compressed_file
53
+ puts "Kindlegen downloaded: " + ext_dir + compressed_file
54
+ FileUtils.cd(ext_dir)
55
+ system extract + compressed_file
56
+
57
+ # Move the executable into gem's /bin folder
58
+ unless File.directory?(bin_dir)
59
+ FileUtils.mkdir_p(bin_dir)
60
+ end
61
+ moved = FileUtils.mv(ext_dir + executable, bin_dir)
62
+ puts "Kindlegen extracted to: " + bin_dir
63
+ # Clean up ext folder
64
+ if moved
65
+ FileUtils.rm_rf(ext_dir)
66
+ end
67
+
68
+ # Give exec permissions to Kindlegen file
69
+ exec_file = bin_dir + executable
70
+ if windows
71
+ cmd = "icacls #{exec_file} /T /C /grant Everyone:(f)"
72
+ system cmd
73
+ else
74
+ FileUtils.chmod 0754, exec_file
75
+ end
76
+ puts "Execution permissions granted to the user for Kindlegen executable"
77
+
78
+ end
79
+
80
+ # Returns the full path to executable Kindlegen file
81
+ def self.executable
82
+
83
+ gem_path = Gem::Specification.find_by_name('kindlerb').gem_dir
84
+
85
+ # Different extensions based on OS
86
+ kindlegen = case RbConfig::CONFIG['host_os']
87
+ when /mac|darwin/i
88
+ "kindlegen"
89
+ when /linux|cygwin/i
90
+ "kindlegen"
91
+ when /mingw32/i
92
+ "kindlegen.exe"
93
+ else
94
+ STDERR.puts "Kindlegen is not installed because host OS is not supported!"
95
+ exit(1)
96
+ end
97
+
98
+ exec_path = gem_path + '/bin/' + kindlegen
99
+
100
+ return exec_path
101
+
102
+ end
103
+
104
+ def self.run(target_dir, verbose = false, compression_method = 'c2')
105
+
106
+ opf_template = File.read(File.join(File.dirname(__FILE__), '..', "templates/opf.mustache"))
107
+ ncx_template = File.read(File.join(File.dirname(__FILE__), '..', "templates/ncx.mustache"))
108
+ contents_template = File.read(File.join(File.dirname(__FILE__), '..', "templates/contents.mustache"))
109
+ section_template = File.read(File.join(File.dirname(__FILE__), '..', "templates/section.mustache"))
110
+ masthead_gif = File.join(File.dirname(__FILE__), '..', "templates/masthead.gif")
111
+ cover_gif = File.join(File.dirname(__FILE__), '..', "templates/cover-image.gif")
112
+
113
+ Dir.chdir target_dir do
114
+ playorder = 1
115
+
116
+ images = []
117
+ manifest_items = []
118
+
119
+ unless File.exist?("_document.yml")
120
+
121
+ puts "Usage: kindlerb [target file directory]"
122
+
123
+ abort "Missing _document.yml. Your input file tree is not structured correctly. Please read the README."
124
+ end
125
+
126
+ document = YAML::load_file("_document.yml")
127
+
128
+ document[:spine_items] = []
129
+ section_html_files = []
130
+
131
+ sections = Dir['sections/*'].entries.sort.map.with_index {|section_dir|
132
+ c = File.read(Pathname.new(section_dir) + '_section.txt')
133
+ c.force_encoding("UTF-8")
134
+ section_title = c.strip
135
+ articles = Dir[Pathname.new(section_dir) + '*'].entries.select {|x| File.basename(x) !~ /section/}.sort
136
+ section_html_files << (section_html_file = (Pathname.new(section_dir) + 'section.html').to_s)
137
+ idref = "item-#{section_dir.gsub(/\D/, '')}"
138
+
139
+ document[:spine_items] << {:idref => idref}
140
+ manifest_items << {
141
+ :href => section_html_file,
142
+ :media => "application/xhtml+xml",
143
+ :idref => idref
144
+ }
145
+
146
+ s = {
147
+ :path => section_dir,
148
+ :title => section_title.shorten(40),
149
+ :playorder => (playorder += 1),
150
+ :idref => idref,
151
+ :href => Pathname.new(section_dir) + 'section.html',
152
+ :articles => articles.map {|article_file|
153
+ doc = Nokogiri::HTML(File.read(article_file, :encoding => 'UTF-8'))
154
+ article_images = doc.search("img").map {|img|
155
+ mimetype = img[:src] ? "image/#{File.extname(img[:src]).sub('.', '')}" : nil
156
+ {:href => img[:src], :mimetype => mimetype}
157
+ }
158
+ images.push *article_images
159
+ title = doc.search("html/head/title").map(&:inner_text).first || "no title"
160
+ idref = "item-#{article_file.gsub(/\D/, '')}"
161
+ document[:spine_items] << {:idref => idref}
162
+ article = {
163
+ :file => article_file,
164
+ :href => article_file,
165
+ :title => title,
166
+ :short_title => title.shorten(60),
167
+ :author => doc.search("html/head/meta[@name=author]").map{|n|n[:content]}.first,
168
+ :description => doc.search("html/head/meta[@name=description]").map{|n|n[:content]}.first,
169
+ :playorder => (playorder += 1),
170
+ :idref => idref
171
+ }
172
+ manifest_items << {
173
+ :href => article[:file],
174
+ :media => "application/xhtml+xml",
175
+ :idref => article[:idref]
176
+ }
177
+ article
178
+ }
179
+ }
180
+
181
+ # Generate the section html
182
+ out = Mustache.render section_template, s
183
+ File.open(section_html_file, "w") {|f| f.puts out}
184
+ s
185
+
186
+ }
187
+
188
+ document[:first_article] = sections[0][:articles][0]
189
+ document['sections'] = sections
190
+
191
+
192
+ document[:manifest_items] = manifest_items + images.map.with_index {|img, idx|
193
+ {
194
+ :href => img[:href],
195
+ :media => img[:mimetype],
196
+ :idref => "img-%03d" % idx
197
+ }
198
+ }
199
+ document[:cover_mimetype] ||= "image/gif"
200
+
201
+ opf = Mustache.render opf_template, document
202
+ File.open("kindlerb.opf", "w") {|f| f.puts opf}
203
+ puts "Wrote #{target_dir}/kindlerb.opf"
204
+
205
+ # NCX
206
+ ncx = Mustache.render ncx_template, document
207
+ File.open("nav-contents.ncx", "w") {|f| f.puts ncx}
208
+ puts "Wrote #{target_dir}/nav-contents.ncx"
209
+
210
+ # contents
211
+ contents = Mustache.render contents_template, document
212
+ File.open("contents.html", "w") {|f| f.puts contents}
213
+ puts "Wrote #{target_dir}/contents.html"
214
+
215
+ outfile = document['mobi_outfile']
216
+ puts "Writing #{outfile}"
217
+ cmd = self.executable + "#{' -verbose' if verbose} -#{compression_method} -o #{outfile} kindlerb.opf && echo 'Wrote MOBI to #{outfile}'"
218
+ puts cmd
219
+ system cmd
220
+
221
+ # If the system call returns anything other than nil, the call was successful
222
+ # Because Kindlegen completes build successfully with warnings
223
+ successful = $?.exitstatus.nil? ? false : true
224
+ if successful
225
+ return true
226
+ else
227
+ return false
228
+ end
229
+
230
+ end
231
+ end
232
+ end