"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] }; }