191 lines
5.8 KiB
JavaScript
191 lines
5.8 KiB
JavaScript
var _ = require('lodash');
|
|
var util = require('util');
|
|
var juice = require('juice');
|
|
|
|
var command = require('../utils/command');
|
|
var fs = require('../utils/fs');
|
|
var Promise = require('../utils/promise');
|
|
var error = require('../utils/error');
|
|
var WebsiteOutput = require('./website');
|
|
var assetsInliner = require('./assets-inliner');
|
|
|
|
function _EbookOutput() {
|
|
WebsiteOutput.apply(this, arguments);
|
|
|
|
// ebook-convert does not support link like "./"
|
|
this.opts.directoryIndex = false;
|
|
}
|
|
util.inherits(_EbookOutput, WebsiteOutput);
|
|
|
|
var EbookOutput = assetsInliner(_EbookOutput);
|
|
|
|
EbookOutput.prototype.name = 'ebook';
|
|
|
|
// Finish generation, create ebook using ebook-convert
|
|
EbookOutput.prototype.finish = function() {
|
|
var that = this;
|
|
if (that.book.isMultilingual()) {
|
|
return EbookOutput.super_.prototype.finish.apply(that);
|
|
}
|
|
|
|
return Promise()
|
|
.then(function() {
|
|
return EbookOutput.super_.prototype.finish.apply(that);
|
|
})
|
|
|
|
// Generate SUMMARY.html
|
|
.then(function() {
|
|
return that.render('summary', that.getContext())
|
|
.then(function(html) {
|
|
return that.writeFile(
|
|
'SUMMARY.html',
|
|
html
|
|
);
|
|
});
|
|
})
|
|
|
|
// Start ebook-convert
|
|
.then(function() {
|
|
return that.ebookConvertOption();
|
|
})
|
|
|
|
.then(function(options) {
|
|
if (!that.opts.format) return;
|
|
|
|
var cmd = [
|
|
'ebook-convert',
|
|
that.resolve('SUMMARY.html'),
|
|
that.resolve('index.'+that.opts.format),
|
|
command.optionsToShellArgs(options)
|
|
].join(' ');
|
|
|
|
return command.exec(cmd)
|
|
.progress(function(data) {
|
|
that.book.log.debug(data);
|
|
})
|
|
.fail(function(err) {
|
|
if (err.code == 127) {
|
|
throw error.RequireInstallError({
|
|
cmd: 'ebook-convert',
|
|
install: 'Install it from Calibre: https://calibre-ebook.com'
|
|
});
|
|
}
|
|
|
|
throw error.EbookError(err);
|
|
});
|
|
});
|
|
};
|
|
|
|
// Generate header/footer for PDF
|
|
EbookOutput.prototype.getPDFTemplate = function(tpl) {
|
|
var that = this;
|
|
var context = _.extend(
|
|
{
|
|
// Nunjucks context mapping to ebook-convert templating
|
|
page: {
|
|
num: '_PAGENUM_',
|
|
title: '_TITLE_',
|
|
section: '_SECTION_'
|
|
}
|
|
},
|
|
this.getContext()
|
|
);
|
|
|
|
return this.render('pdf_'+tpl, context)
|
|
|
|
// Inline css, include css relative to the output folder
|
|
.then(function(output) {
|
|
return Promise.nfcall(juice.juiceResources, output, {
|
|
webResources: {
|
|
relativeTo: that.root()
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
// Locate the cover file to use
|
|
// Use configuration or search a "cover.jpg" file
|
|
// For multi-lingual book, it can use the one from the main book
|
|
EbookOutput.prototype.locateCover = function() {
|
|
var cover = this.book.config.get('cover', 'cover.jpg');
|
|
|
|
// Resolve to absolute
|
|
cover = this.resolve(cover);
|
|
|
|
// Cover doesn't exist and multilingual?
|
|
if (!fs.existsSync(cover)) {
|
|
if (this.parent) return this.parent.locateCover()
|
|
else return undefined;
|
|
}
|
|
|
|
return cover;
|
|
};
|
|
|
|
// Generate options for ebook-convert
|
|
EbookOutput.prototype.ebookConvertOption = function() {
|
|
var that = this;
|
|
|
|
var options = {
|
|
'--cover': this.locateCover(),
|
|
'--title': that.book.config.get('title'),
|
|
'--comments': that.book.config.get('description'),
|
|
'--isbn': that.book.config.get('isbn'),
|
|
'--authors': that.book.config.get('author'),
|
|
'--language': that.book.config.get('language'),
|
|
'--book-producer': 'GitBook',
|
|
'--publisher': 'GitBook',
|
|
'--chapter': 'descendant-or-self::*[contains(concat(\' \', normalize-space(@class), \' \'), \' book-chapter \')]',
|
|
'--level1-toc': 'descendant-or-self::*[contains(concat(\' \', normalize-space(@class), \' \'), \' book-chapter-1 \')]',
|
|
'--level2-toc': 'descendant-or-self::*[contains(concat(\' \', normalize-space(@class), \' \'), \' book-chapter-2 \')]',
|
|
'--level3-toc': 'descendant-or-self::*[contains(concat(\' \', normalize-space(@class), \' \'), \' book-chapter-3 \')]',
|
|
'--no-chapters-in-toc': true,
|
|
'--max-levels': '1',
|
|
'--breadth-first': true
|
|
};
|
|
|
|
if (that.opts.format == 'epub') {
|
|
options = _.extend(options, {
|
|
'--dont-split-on-page-breaks': true
|
|
});
|
|
}
|
|
|
|
if (that.opts.format != 'pdf') return Promise(options);
|
|
|
|
var pdfOptions = that.book.config.get('pdf');
|
|
|
|
options = _.extend(options, {
|
|
'--chapter-mark': String(pdfOptions.chapterMark),
|
|
'--page-breaks-before': String(pdfOptions.pageBreaksBefore),
|
|
'--margin-left': String(pdfOptions.margin.left),
|
|
'--margin-right': String(pdfOptions.margin.right),
|
|
'--margin-top': String(pdfOptions.margin.top),
|
|
'--margin-bottom': String(pdfOptions.margin.bottom),
|
|
'--pdf-default-font-size': String(pdfOptions.fontSize),
|
|
'--pdf-mono-font-size': String(pdfOptions.fontSize),
|
|
'--paper-size': String(pdfOptions.paperSize),
|
|
'--pdf-page-numbers': Boolean(pdfOptions.pageNumbers),
|
|
'--pdf-header-template': that.getPDFTemplate('header'),
|
|
'--pdf-footer-template': that.getPDFTemplate('footer'),
|
|
'--pdf-sans-family': String(pdfOptions.fontFamily)
|
|
});
|
|
|
|
return that.getPDFTemplate('header')
|
|
.then(function(tpl) {
|
|
options['--pdf-header-template'] = tpl;
|
|
|
|
return that.getPDFTemplate('footer');
|
|
})
|
|
.then(function(tpl) {
|
|
options['--pdf-footer-template'] = tpl;
|
|
|
|
return options;
|
|
});
|
|
};
|
|
|
|
// Don't write multi-lingual index for wbook
|
|
EbookOutput.prototype.outputMultilingualIndex = function() {
|
|
|
|
};
|
|
|
|
module.exports = EbookOutput;
|