kindlerb 0.1.1 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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