Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
275 lines (235 sloc) 8.07 KB
require 'rubygems'
require 'jekyll'
require 'uuid'
require 'mime/types'
require 'jekyll/tags/epub'
module Jekyll
class StaticFile #:nodoc:
# This is a Jekyll[http://jekyllrb.com] extension
#
# Give the URL of a static file
def url #:nodoc:
File.join( @dir, @name )
end
end
class Site #:nodoc:
def all
if self.config["epub"]["pages-order"]
self.create_order( pages.clone, posts.clone, self.config["epub"]["pages-order"], :url )
else
posts + pages
end
end
def get_item( item, method, posts, pages ) #:nodoc:
_out = []
posts.each do |p|
if p.send(method).gsub( /^\//, "" ) == item
_out << posts.delete(p)
end
end
pages.each do |p|
if p.send(method).gsub( /^\//, "" ) == item
_out << pages.delete(p)
end
end
return _out, posts, pages
end
def create_order( pages, posts, order, method ) #:nodoc:
_result = []
_order = {}
order.each do |item|
if item.class == Symbol
_order[item] = eval(item.to_s)
else
_order[item], posts, pages = get_item( item, method, posts, pages )
end
end
order.each do |item|
_result = _result + _order[item]
end
return _result
end
# This is a Jekyll[http://jekyllrb.com] extension
#
# Same as Site::process but generate the epub.
def epub #:nodoc:
self.reset
self.read
# Change layout to use epub
self.layouts.each do |name, layout|
self.layouts[name].data['layout'] = layout.data['epub'] if layout.data['epub']
end
# Generate specifics epub files
FileUtils.rm_rf( self.dest )
self.package_epub
self.render
# Apply filters
self.apply_epub_filters( pages )
self.apply_epub_filters( posts )
self.write
# Create epub file
self.zip
end
# This is a Jekyll[http://jekyllrb.com] extension
#
# Generate the specifics epub files : content.opf, toc.ncx, mimetype,
# page-template.xpgt and META-INF/container.xml
def package_epub #:nodoc:
files = []
order = 0
# Check for cover image
if self.config["epub"]["cover-image"]
self.config["epub"]["cover"] = {
"image" => self.config["epub"]["cover-image"],
"mime" => MIME::Types.type_for( self.config["epub"]["cover-image"] ).to_s
}
end
(all + static_files).each do |p|
url = p.url.gsub( /^\//, "" )
next if url == self.config["epub"]["cover-image"]
mime = MIME::Types.type_for( url ).to_s
mime = "application/xhtml+xml" if mime == "text/html"
next if self.config['exclude'].include?(File.basename( url ))
if mime == "" then
$stderr.puts "** Ignore file #{url}, unknown mime type!"
next
end
file_data = {
'id' => url.gsub( /\/|\./, "_" ),
'url' => url,
'mime' => mime
}
begin
p.data['layout'] = p.data['epub'] if p.data['epub']
file_data['title'] = p.data["title"]
file_data['order'] = order
order += 1
rescue => e
if file_data['mime'] == "text/html"
$stderr.puts "** Ignore file #{url} : #{e.message}"
next
end
end
files << file_data
end
FileUtils.mkdir_p(self.dest)
FileUtils.mkdir_p(File.join( self.dest, "META-INF" ))
write_epub_file( "content.opf", files )
write_epub_file( "toc.ncx", files )
write_epub_file( "mimetype", files )
write_epub_file( "page-template.xpgt", files )
write_epub_file( File.join( "META-INF", "container.xml" ) , files )
if self.config["epub"]["cover-image"]
write_epub_file( "cover.xhtml", files )
end
end
# This is a Jekyll[http://jekyllrb.com] extension
#
# Write a specific epub file using Liquid. See Jekyll::Site::package_epub
def write_epub_file( tmpl, files ) #:nodoc:
$stderr.puts "** Create #{tmpl}"
template_file = File.join( File.expand_path( File.dirname( __FILE__ ) ), "epub", "templates", tmpl )
template_content = Liquid::Template.parse(File.open(template_file).read).render( 'epub' => self.config['epub'], 'files' => files )
File.open( File.join( self.dest, tmpl ), "w+" ).puts template_content
end
# This is a Jekyll[http://jekyllrb.com] extension
#
# Very simple post-filters
#
# This method need to be rewritten and add the possibility to use user's defined filters
def apply_epub_filters( files ) #:nodoc:
files.each do |file|
file.output = file.output.gsub( /(src\s*=\s*['|"])\//, '\1' )
file.output = file.output.gsub( /(href\s*=\s*['|"])\//, '\1' )
# Remove all <script> tags
file.output = file.output.gsub( /<script[^>]*>[^<\/script>]*<\/script>/, "" )
file.output = file.output.gsub( /<script[^>]*\/>/, "" )
file.output = file.output.gsub( /<noscript>.*<\/noscript>/, "" )
end
end
# This is a Jekyll[http://jekyllrb.com] extension
#
# Create the epub file...
def zip #:nodoc:
Dir.chdir( self.dest ) do
filename = self.config['epub']['name']
filename += ".epub" unless File.extname(filename) == ".epub"
$stderr.puts "** Create epub file #{filename} in #{Dir.pwd}..."
%x(zip -X9 \"#{filename}\" mimetype)
%x(zip -Xr9D \"#{filename}\" * -xi mimetype)
end
end
end
class Epub
include Jekyll::Filters
DEFAULTS = Jekyll::DEFAULTS.merge( {
'destination' => File.join('.', '_epub', 'src'),
'permalink' => '/:title.html',
'epub' => {
'title' => "My Jekyll Blog",
'language' => 'en',
'identifier' => UUID.generate
}
} )
# Generate a Jekyll::Epub configuration Hash by merging the default options
# with anything in _epub.yml, and adding the given options on top
# +override+ is a Hash of config directives
#
# Returns Hash
def self.configuration(override = {})
# _epub.yml may override default source location, but until
# then, we need to know where to look for _config.yml
source = override['source'] || Jekyll::Epub::DEFAULTS['source']
# Get configuration from <source>/_epub.yml
config_file = File.join(source, '_epub.yml')
begin
config = YAML.load_file(config_file)
raise "Invalid configuration - #{config_file}" if !config.is_a?(Hash)
$stdout.puts "** Configuration from #{config_file}"
rescue => err
$stderr.puts "** WARNING: Could not read configuration. Using defaults (and options)."
$stderr.puts "\t" + err.to_s
config = {}
end
# Merge DEFAULTS < _config.yml < override
Jekyll::Epub::DEFAULTS.deep_merge(config).deep_merge(override)
end
# Generate the epub! All in one!
def create( override )
options = Jekyll::Epub.configuration( override )
site = Jekyll::Site.new(options)
site.epub
if options['epub']['validate'] == true
self.validate( site )
end
end
# A tiny XHTML validator.
#
# If you want to validate your xhtml files, juste add
#
# epub:
# validate: true
#
# in your _epub.yml file.
def validate( site )
begin
require 'xml/libxml'
rescue => e
$stderr.puts "** WARNING: libxml-ruby is not installed. Can't validate!"
return
end
dtd_file = File.join( File.expand_path( File.dirname( __FILE__ ) ), "epub", "dtd", "xhtml1-strict.dtd" )
dtd = XML::Dtd.new("-//W3C//DTD XHTML 1.0 Strict//EN", dtd_file)
(site.posts + site.pages).each do |path|
file = File.join( site.dest, path.url )
$stderr.puts "** Validate #{file}."
begin
doc = XML::Document.file(file)
doc.validate(dtd)
rescue => e
$stderr.puts e.message
end
end
end
end
end