"use strict";
const fs = require("fs").promises;
const path = require("path");
const cpr = require("util").promisify(require("cpr"));
const BOOK_PUBLISHER = "Domenic Denicola";
const BOOK_AUTHOR = "Wildbow";
const NCX_FILENAME = "toc.ncx";
module.exports = async (scaffoldingPath, coverPath, bookPath, contentPath, chaptersPath, manifestPath, bookInfo) => {
await Promise.all([
cpr(scaffoldingPath, bookPath, { overwrite: true, confirm: true, filter: noThumbs }),
cpr(coverPath, path.resolve(bookPath, "OEBPS"), { overwrite: true, confirm: true, filter: noThumbs }),
Promise.all([
getChapters(contentPath, chaptersPath, manifestPath),
getCoverFiles(coverPath)
]).then(([chapters, coverFiles]) => {
return Promise.all([
writeOPF(chapters, contentPath, coverFiles, bookInfo),
writeNcx(chapters, contentPath, bookInfo)
]);
})
]);
console.log(`EPUB contents assembled into ${scaffoldingPath}`);
};
function noThumbs(filePath) {
// Thumbs.db causes the strangest errors as Windows has it locked a lot of the time.
return path.basename(filePath) !== "Thumbs.db";
}
function writeOPF(chapters, contentPath, coverFiles, bookInfo) {
const manifestChapters = chapters.map(c => {
return ` `;
}).join("\n");
const spineChapters = chapters.map(c => {
return ``;
}).join("\n");
const contents = `
${bookInfo.title}
en
urn:uuid:${bookInfo.id}
${BOOK_AUTHOR}
${BOOK_PUBLISHER}
${bookInfo.description}
${manifestChapters}
${spineChapters}
`;
return fs.writeFile(path.resolve(contentPath, "content.opf"), contents);
}
function writeNcx(chapters, contentPath, bookInfo) {
const navPoints = chapters.map((c, i) => {
return `
${c.title}
`;
}).join("\n");
const contents = `
${bookInfo.title}
${BOOK_AUTHOR}
${navPoints}
`;
return fs.writeFile(path.resolve(contentPath, NCX_FILENAME), contents);
}
async function getChapters(contentPath, chaptersPath, manifestPath) {
const hrefPrefix = `${path.relative(contentPath, chaptersPath)}/`;
const manifestContents = await fs.readFile(manifestPath, { encoding: "utf-8" });
const manifestChapters = JSON.parse(manifestContents);
const filenames = await fs.readdir(chaptersPath);
return filenames
.filter(f => path.extname(f) === ".xhtml")
.sort()
.map((f, i) => {
return {
id: path.basename(f),
title: manifestChapters[i].title,
href: `${hrefPrefix}${f}`
};
});
}
async function getCoverFiles(coverPath) {
const filenames = await fs.readdir(coverPath);
const images = filenames.filter(f => [".png", ".jpg"].includes(path.extname(f)));
if (images.length !== 1) {
throw new Error(`Expected one cover image in ${coverPath}; found ${images.length}`);
}
const imageMimeType = path.extname(images[0]) === ".png" ? "image/png" : "image/jpeg";
return { xhtml: "cover.xhtml", imageMimeType, image: images[0] };
}