summaryrefslogtreecommitdiffstats
path: root/lib/output
diff options
context:
space:
mode:
authorSamy Pessé <samypesse@gmail.com>2016-04-29 16:50:50 +0200
committerSamy Pessé <samypesse@gmail.com>2016-04-29 16:50:50 +0200
commit98f70879bde88d32e898ff057f4dc7ceaff7e25e (patch)
tree557e0948683cd985fdcc50519f693ca07a2a972c /lib/output
parentceb4627f4e700b0e8058fae6760dbf9bb2ca7333 (diff)
downloadgitbook-98f70879bde88d32e898ff057f4dc7ceaff7e25e.zip
gitbook-98f70879bde88d32e898ff057f4dc7ceaff7e25e.tar.gz
gitbook-98f70879bde88d32e898ff057f4dc7ceaff7e25e.tar.bz2
Complete ebook generation using ebook-convert
Diffstat (limited to 'lib/output')
-rw-r--r--lib/output/ebook/getConvertOptions.js73
-rw-r--r--lib/output/ebook/getCoverPath.js30
-rw-r--r--lib/output/ebook/getPDFTemplate.js42
-rw-r--r--lib/output/ebook/index.js2
-rw-r--r--lib/output/ebook/onFinish.js66
-rw-r--r--lib/output/ebook/onInit.js21
-rw-r--r--lib/output/ebook/options.js17
7 files changed, 226 insertions, 25 deletions
diff --git a/lib/output/ebook/getConvertOptions.js b/lib/output/ebook/getConvertOptions.js
new file mode 100644
index 0000000..bc80493
--- /dev/null
+++ b/lib/output/ebook/getConvertOptions.js
@@ -0,0 +1,73 @@
+var extend = require('extend');
+
+var Promise = require('../../utils/promise');
+var getPDFTemplate = require('./getPDFTemplate');
+var getCoverPath = require('./getCoverPath');
+
+/**
+ Generate options for ebook-convert
+
+ @param {Output}
+ @return {Promise<Object>}
+*/
+function getConvertOptions(output) {
+ var options = output.getOptions();
+ var format = options.get('format');
+
+ var book = output.getBook();
+ var config = book.getConfig();
+
+ return Promise()
+ .then(function() {
+ var coverPath = getCoverPath(output);
+ var options = {
+ '--cover': coverPath,
+ '--title': config.getValue('title'),
+ '--comments': config.getValue('description'),
+ '--isbn': config.getValue('isbn'),
+ '--authors': config.getValue('author'),
+ '--language': book.getLanguage() || config.getValue('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 \')]',
+ '--max-levels': '1',
+ '--no-chapters-in-toc': true,
+ '--breadth-first': true,
+ '--dont-split-on-page-breaks': format === 'epub'? true : undefined
+ };
+
+ if (format !== 'pdf') {
+ return options;
+ }
+
+ return Promise.all([
+ getPDFTemplate(output, 'header'),
+ getPDFTemplate(output, 'footer')
+ ])
+ .spread(function(headerTpl, footerTpl) {
+ var pdfOptions = config.getValue('pdf').toJS();
+
+ return 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-sans-family': String(pdfOptions.fontFamily),
+ '--pdf-header-template': headerTpl,
+ '--pdf-footer-template': footerTpl
+ });
+ });
+ });
+}
+
+
+module.exports = getConvertOptions;
diff --git a/lib/output/ebook/getCoverPath.js b/lib/output/ebook/getCoverPath.js
new file mode 100644
index 0000000..c2192d4
--- /dev/null
+++ b/lib/output/ebook/getCoverPath.js
@@ -0,0 +1,30 @@
+var path = require('path');
+var fs = require('../../utils/fs');
+
+/**
+ Resolve path to cover file to use
+
+ @param {Output}
+ @return {String}
+*/
+function getCoverPath(output) {
+ var outputRoot = output.getRoot();
+ var book = output.getBook();
+ var config = book.getConfig();
+ var cover = config.getValue('cover', 'cover.jpg');
+
+ // Resolve to absolute
+ cover = fs.pickFile(outputRoot, cover);
+ if (cover) {
+ return cover;
+ }
+
+ // Multilingual? try parent folder
+ if (book.isLanguageBook()) {
+ cover = fs.pickFile(path.join(outputRoot, '..'), cover);
+ }
+
+ return cover;
+}
+
+module.exports = getCoverPath;
diff --git a/lib/output/ebook/getPDFTemplate.js b/lib/output/ebook/getPDFTemplate.js
new file mode 100644
index 0000000..f7a450d
--- /dev/null
+++ b/lib/output/ebook/getPDFTemplate.js
@@ -0,0 +1,42 @@
+var juice = require('juice');
+
+var WebsiteGenerator = require('../website');
+var JSONUtils = require('../../json');
+var Templating = require('../../templating');
+var Promise = require('../../utils/promise');
+
+
+/**
+ Generate PDF header/footer templates
+
+ @param {Output} output
+ @param {String} type
+ @return {String}
+*/
+function getPDFTemplate(output, type) {
+ var filePath = 'pdf_' + type + '.html';
+ var outputRoot = output.getRoot();
+ var engine = WebsiteGenerator.createTemplateEngine(output, filePath);
+
+ // Generate context
+ var context = JSONUtils.encodeOutput(output);
+ context.page = {
+ num: '_PAGENUM_',
+ title: '_TITLE_',
+ section: '_SECTION_'
+ };
+
+ // Render the theme
+ return Templating.renderFile(engine, 'ebook/' + filePath, context)
+
+ // Inline css and assets
+ .then(function(html) {
+ return Promise.nfcall(juice.juiceResources, html, {
+ webResources: {
+ relativeTo: outputRoot
+ }
+ });
+ });
+}
+
+module.exports = getPDFTemplate;
diff --git a/lib/output/ebook/index.js b/lib/output/ebook/index.js
index 344a6c5..786a10a 100644
--- a/lib/output/ebook/index.js
+++ b/lib/output/ebook/index.js
@@ -3,7 +3,7 @@ var WebsiteGenerator = require('../website');
module.exports = extend({}, WebsiteGenerator, {
name: 'ebook',
- onInit: require('./onInit'),
+ Options: require('./options'),
onPage: require('./onPage'),
onFinish: require('./onFinish')
});
diff --git a/lib/output/ebook/onFinish.js b/lib/output/ebook/onFinish.js
index e82f679..17a8e5e 100644
--- a/lib/output/ebook/onFinish.js
+++ b/lib/output/ebook/onFinish.js
@@ -1,16 +1,22 @@
+var path = require('path');
+
var WebsiteGenerator = require('../website');
var JSONUtils = require('../../json');
var Templating = require('../../templating');
+var Promise = require('../../utils/promise');
+var error = require('../../utils/error');
+var command = require('../../utils/command');
var writeFile = require('../helper/writeFile');
+var getConvertOptions = require('./getConvertOptions');
+
/**
- Finish the generation, generates the SUMMARY.html
+ Write the SUMMARY.html
@param {Output}
@return {Output}
*/
-function onFinish(output) {
- var book = output.getBook();
+function writeSummary(output) {
var options = output.getOptions();
var prefix = options.get('prefix');
@@ -27,4 +33,58 @@ function onFinish(output) {
});
}
+/**
+ Generate the ebook file as "index.pdf"
+
+ @param {Output}
+ @return {Output}
+*/
+function runEbookConvert(output) {
+ var logger = output.getLogger();
+ var options = output.getOptions();
+ var format = options.get('format');
+ var outputFolder = output.getRoot();
+
+ if (!format) {
+ return Promise(output);
+ }
+
+ return getConvertOptions(output)
+ .then(function(options) {
+ var cmd = [
+ 'ebook-convert',
+ path.resolve(outputFolder, 'SUMMARY.html'),
+ path.resolve(outputFolder, 'index.' + format),
+ command.optionsToShellArgs(options)
+ ].join(' ');
+
+ return command.exec(cmd)
+ .progress(function(data) {
+ logger.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);
+ });
+ })
+ .thenResolve(output);
+}
+
+/**
+ Finish the generation, generates the SUMMARY.html
+
+ @param {Output}
+ @return {Output}
+*/
+function onFinish(output) {
+ return writeSummary(output)
+ .then(runEbookConvert);
+}
+
module.exports = onFinish;
diff --git a/lib/output/ebook/onInit.js b/lib/output/ebook/onInit.js
deleted file mode 100644
index 402e318..0000000
--- a/lib/output/ebook/onInit.js
+++ /dev/null
@@ -1,21 +0,0 @@
-var WebsiteGenerator = require('../website');
-
-/**
- Initialize the generator
-
- @param {Output}
- @return {Output}
-*/
-function onInit(output) {
- return WebsiteGenerator.onInit(output)
- .then(function(resultOutput) {
- var options = resultOutput.getOptions();
-
- options = options.set('directoryIndex', false);
- options = options.set('prefix', 'ebook');
-
- return resultOutput.setOptions(options);
- });
-}
-
-module.exports = onInit;
diff --git a/lib/output/ebook/options.js b/lib/output/ebook/options.js
new file mode 100644
index 0000000..ea7b8b4
--- /dev/null
+++ b/lib/output/ebook/options.js
@@ -0,0 +1,17 @@
+var Immutable = require('immutable');
+
+var Options = Immutable.Record({
+ // Root folder for the output
+ root: String(),
+
+ // Prefix for generation
+ prefix: String('ebook'),
+
+ // Format to generate using ebook-convert
+ format: String(),
+
+ // Force use of absolute urls ("index.html" instead of "/")
+ directoryIndex: Boolean(false)
+});
+
+module.exports = Options;