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