Start generalizing to work for Ward too
* Updates the command-line options in various ways, notably changing --start-url to --book * Renames the "book" directory to "staging" * Abstracts out most book-specific data into books.js (but not yet cover or substitutions.json) * Makes per-book subfolders under cache and staging directories
This commit is contained in:
parent
27e14360c9
commit
fd914b43f5
5 changed files with 87 additions and 49 deletions
41
lib/books.js
Normal file
41
lib/books.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
"use strict";
|
||||
|
||||
// TODO cover
|
||||
|
||||
exports.worm = {
|
||||
startURL: "https://parahumans.wordpress.com/2011/06/11/1-1/",
|
||||
title: "Worm",
|
||||
author: "wildbow",
|
||||
id: "e7f3532d-8db6-4888-be80-1976166b7059",
|
||||
|
||||
// First paragraph of https://parahumans.wordpress.com/about/
|
||||
description: `
|
||||
An introverted teenage girl with an unconventional superpower, Taylor goes out in costume to find escape from a deeply
|
||||
unhappy and frustrated civilian life. Her first attempt at taking down a supervillain sees her mistaken for one,
|
||||
thrusting her into the midst of the local ‘cape’ scene’s politics, unwritten rules, and ambiguous morals. As she risks
|
||||
life and limb, Taylor faces the dilemma of having to do the wrong things for the right reasons.
|
||||
`.trim()
|
||||
};
|
||||
|
||||
exports.ward = {
|
||||
startURL: "https://www.parahumans.net/2017/09/11/daybreak-1-1/",
|
||||
title: "Ward",
|
||||
author: "wildbow",
|
||||
id: "a6b6b156-2f17-43c0-8bb1-bfa91f3ef62a",
|
||||
|
||||
// Synposis from https://www.parahumans.net/
|
||||
description: `
|
||||
The unwritten rules that govern the fights and outright wars between ‘capes’ have been amended: everyone gets their
|
||||
second chance. It’s an uneasy thing to come to terms with when notorious supervillains and even monsters are playing at
|
||||
being hero. The world ended two years ago, and as humanity straddles the old world and the new, there aren’t records,
|
||||
witnesses, or facilities to answer the villains’ past actions in the present. One of many compromises, uneasy truces and
|
||||
deceptions that are starting to splinter as humanity rebuilds.
|
||||
|
||||
None feel the injustice of this new status quo or the lack of established footing more than the past residents of the
|
||||
parahuman asylums. The facilities hosted parahumans and their victims, but the facilities are ruined or gone; one of
|
||||
many fragile ex-patients is left to find a place in a fractured world. She’s perhaps the person least suited to have
|
||||
anything to do with this tenuous peace or to stand alongside these false heroes. She’s put in a position to make the
|
||||
decision: will she compromise to help forge what they call, with dark sentiment, a second golden age? Or will she stand
|
||||
tall as a gilded dark age dawns?
|
||||
`.trim()
|
||||
};
|
||||
|
|
@ -3,17 +3,7 @@ const fs = require("fs").promises;
|
|||
const path = require("path");
|
||||
const cpr = require("util").promisify(require("cpr"));
|
||||
|
||||
const BOOK_TITLE = "Worm";
|
||||
const BOOK_AUTHOR = "wildbow";
|
||||
const BOOK_PUBLISHER = "Domenic Denicola";
|
||||
const BOOK_ID = "urn:uuid:e7f3532d-8db6-4888-be80-1976166b7059";
|
||||
|
||||
// First paragraph of https://parahumans.wordpress.com/about/
|
||||
const BOOK_DESCRIPTION = `
|
||||
An introverted teenage girl with an unconventional superpower, Taylor goes out in costume to find escape from a deeply
|
||||
unhappy and frustrated civilian life. Her first attempt at taking down a supervillain sees her mistaken for one,
|
||||
thrusting her into the midst of the local ‘cape’ scene’s politics, unwritten rules, and ambiguous morals. As she risks
|
||||
life and limb, Taylor faces the dilemma of having to do the wrong things for the right reasons.`;
|
||||
|
||||
const NCX_FILENAME = "toc.ncx";
|
||||
|
||||
|
|
@ -21,13 +11,13 @@ const COVER_IMG_FILENAME = "cover.png";
|
|||
const COVER_XHTML_FILENAME = "cover.xhtml";
|
||||
const COVER_MIMETYPE = "image/png";
|
||||
|
||||
module.exports = async (scaffoldingPath, bookPath, contentPath, chaptersPath, manifestPath) => {
|
||||
module.exports = async (scaffoldingPath, bookPath, contentPath, chaptersPath, manifestPath, bookInfo) => {
|
||||
await Promise.all([
|
||||
cpr(scaffoldingPath, bookPath, { overwrite: true, confirm: true, filter: noThumbs }),
|
||||
getChapters(contentPath, chaptersPath, manifestPath).then(chapters => {
|
||||
return Promise.all([
|
||||
writeOPF(chapters, contentPath),
|
||||
writeNcx(chapters, contentPath)
|
||||
writeOPF(chapters, contentPath, bookInfo),
|
||||
writeNcx(chapters, contentPath, bookInfo)
|
||||
]);
|
||||
})
|
||||
]);
|
||||
|
|
@ -38,7 +28,7 @@ function noThumbs(filePath) {
|
|||
return path.basename(filePath) !== "Thumbs.db";
|
||||
}
|
||||
|
||||
function writeOPF(chapters, contentPath) {
|
||||
function writeOPF(chapters, contentPath, bookInfo) {
|
||||
const manifestChapters = chapters.map(c => {
|
||||
return `<item id="${c.id}" href="${c.href}" media-type="application/xhtml+xml"/>`;
|
||||
}).join("\n");
|
||||
|
|
@ -51,12 +41,12 @@ function writeOPF(chapters, contentPath) {
|
|||
<package version="2.0" xmlns="http://www.idpf.org/2007/opf" unique-identifier="BookId">
|
||||
|
||||
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
|
||||
<dc:title>${BOOK_TITLE}</dc:title>
|
||||
<dc:title>${bookInfo.title}</dc:title>
|
||||
<dc:language>en</dc:language>
|
||||
<dc:identifier id="BookId" opf:scheme="UUID">${BOOK_ID}</dc:identifier>
|
||||
<dc:creator opf:file-as="${BOOK_AUTHOR}" opf:role="aut">${BOOK_AUTHOR}</dc:creator>
|
||||
<dc:identifier id="BookId" opf:scheme="UUID">urn:uuid:${bookInfo.id}</dc:identifier>
|
||||
<dc:creator opf:file-as="${bookInfo.author}" opf:role="aut">${bookInfo.author}</dc:creator>
|
||||
<dc:publisher>${BOOK_PUBLISHER}</dc:publisher>
|
||||
<dc:description>${BOOK_DESCRIPTION}</dc:description>
|
||||
<dc:description>${bookInfo.description}</dc:description>
|
||||
<meta name="cover" content="cover-image"/>
|
||||
</metadata>
|
||||
|
||||
|
|
@ -80,7 +70,7 @@ ${spineChapters}
|
|||
return fs.writeFile(path.resolve(contentPath, "content.opf"), contents);
|
||||
}
|
||||
|
||||
function writeNcx(chapters, contentPath) {
|
||||
function writeNcx(chapters, contentPath, bookInfo) {
|
||||
const navPoints = chapters.map((c, i) => {
|
||||
return `<navPoint class="chapter" id="${c.id}" playOrder="${i + 1}">
|
||||
<navLabel><text>${c.title}</text></navLabel>
|
||||
|
|
@ -92,18 +82,18 @@ function writeNcx(chapters, contentPath) {
|
|||
<!DOCTYPE ncx PUBLIC "-//NISO//DTD ncx 2005-1//EN" "http://www.daisy.org/z3986/2005/ncx-2005-1.dtd">
|
||||
<ncx version="2005-1" xml:lang="en" xmlns="http://www.daisy.org/z3986/2005/ncx/">
|
||||
<head>
|
||||
<meta name="dtb:uid" content="${BOOK_ID}"/>
|
||||
<meta name="dtb:uid" content="urn:uuid:${bookInfo.id}"/>
|
||||
<meta name="dtb:depth" content="1"/>
|
||||
<meta name="dtb:totalPageCount" content="0"/>
|
||||
<meta name="dtb:maxPageNumber" content="0"/>
|
||||
</head>
|
||||
|
||||
<docTitle>
|
||||
<text>${BOOK_TITLE}</text>
|
||||
<text>${bookInfo.title}</text>
|
||||
</docTitle>
|
||||
|
||||
<docAuthor>
|
||||
<text>${BOOK_AUTHOR}</text>
|
||||
<text>${bookInfo.author}</text>
|
||||
</docAuthor>
|
||||
|
||||
<navMap>
|
||||
|
|
|
|||
|
|
@ -6,51 +6,54 @@ const fs = require("fs").promises;
|
|||
const yargs = require("yargs");
|
||||
|
||||
const packageJson = require("../package.json");
|
||||
const books = require("./books.js");
|
||||
const download = require("./download.js");
|
||||
const convert = require("./convert.js");
|
||||
const scaffold = require("./scaffold.js");
|
||||
const zip = require("./zip.js");
|
||||
|
||||
const OUTPUT_DEFAULT = "(Book name).epub";
|
||||
|
||||
const argv = yargs
|
||||
.usage(`${packageJson.description}\n\n${packageJson.name} [<command1> [<command2> [<command3> ...]]]\n\n` +
|
||||
"Each command will fail if the previously-listed one has not yet been run (with matching options).")
|
||||
.command("download", "download all chapters by crawling parahumans.wordpress.com")
|
||||
.command("convert", "convert the raw chapter HTML files into cleaned-up ebook chapters")
|
||||
.command("scaffold", "assemble the table of contents, etc. to complete the EPUB")
|
||||
.command("zip", "zip up the EPUB files into a .epub output")
|
||||
.option("s", {
|
||||
alias: "start-url",
|
||||
default: "https://parahumans.wordpress.com/2011/06/11/1-1/",
|
||||
describe: "the URL from which to start crawling, for the download command",
|
||||
.command("download", "download all chapters into the cache")
|
||||
.command("convert", "convert the raw HTML into cleaned-up ebook chapters")
|
||||
.command("scaffold", "assemble the table of contents, etc.")
|
||||
.command("zip", "zip up the created files into a .epub output")
|
||||
.option("b", {
|
||||
alias: "book",
|
||||
default: Object.keys(books)[0],
|
||||
describe: "the book to operate on",
|
||||
choices: Object.keys(books),
|
||||
requiresArg: true,
|
||||
global: true
|
||||
})
|
||||
.option("c", {
|
||||
alias: "cache-directory",
|
||||
alias: "cache",
|
||||
default: "cache",
|
||||
describe: "cache directory, for the download and convert commands",
|
||||
describe: "cache directory for downloaded raw chapters",
|
||||
requiresArg: true,
|
||||
global: true
|
||||
})
|
||||
.option("b", {
|
||||
alias: "book-directory",
|
||||
default: "book",
|
||||
describe: "directory in which to assemble the EPUB files before zipping, for the convert, scaffold, and zip " +
|
||||
"commands",
|
||||
.option("s", {
|
||||
alias: "staging",
|
||||
default: "staging",
|
||||
describe: "directory in which to assemble the EPUB files",
|
||||
requiresArg: true,
|
||||
global: true
|
||||
})
|
||||
.option("o", {
|
||||
alias: "out",
|
||||
default: "Worm.epub",
|
||||
describe: "output file destination, for the zip command",
|
||||
default: OUTPUT_DEFAULT,
|
||||
describe: "output file destination",
|
||||
requiresArg: true,
|
||||
global: true
|
||||
})
|
||||
.option("j", {
|
||||
alias: "jobs",
|
||||
default: 10,
|
||||
describe: "Number of concurrent read/write jobs to run, for the convert command",
|
||||
describe: "Number of concurrent read/write conversion jobs",
|
||||
requiresArg: true,
|
||||
global: true
|
||||
})
|
||||
|
|
@ -60,18 +63,21 @@ const argv = yargs
|
|||
.version()
|
||||
.argv;
|
||||
|
||||
const cachePath = path.resolve(argv.cacheDirectory);
|
||||
const outputFilename = argv.out === OUTPUT_DEFAULT ? `${books[argv.book].title}.epub` : argv.out;
|
||||
|
||||
const cachePath = path.resolve(argv.cache, argv.book);
|
||||
const manifestPath = path.resolve(cachePath, "manifest.json");
|
||||
|
||||
const scaffoldingPath = path.resolve(__dirname, "../scaffolding");
|
||||
const bookPath = path.resolve(argv.bookDirectory);
|
||||
const contentPath = path.resolve(bookPath, "OEBPS");
|
||||
const stagingPath = path.resolve(argv.staging, argv.book);
|
||||
const contentPath = path.resolve(stagingPath, "OEBPS");
|
||||
const chaptersPath = path.resolve(contentPath, "chapters");
|
||||
|
||||
const commands = [];
|
||||
|
||||
if (argv._.includes("download")) {
|
||||
commands.push(() => download(argv.startUrl, cachePath, manifestPath));
|
||||
const startURL = books[argv.book].startURL;
|
||||
commands.push(() => download(startURL, cachePath, manifestPath));
|
||||
}
|
||||
|
||||
if (argv._.includes("convert")) {
|
||||
|
|
@ -83,11 +89,12 @@ if (argv._.includes("convert")) {
|
|||
}
|
||||
|
||||
if (argv._.includes("scaffold")) {
|
||||
commands.push(() => scaffold(scaffoldingPath, bookPath, contentPath, chaptersPath, manifestPath));
|
||||
const bookInfo = books[argv.book];
|
||||
commands.push(() => scaffold(scaffoldingPath, stagingPath, contentPath, chaptersPath, manifestPath, bookInfo));
|
||||
}
|
||||
|
||||
if (argv._.includes("zip")) {
|
||||
commands.push(() => zip(bookPath, contentPath, path.resolve(argv.out)));
|
||||
commands.push(() => zip(stagingPath, contentPath, path.resolve(outputFilename)));
|
||||
}
|
||||
|
||||
(async () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue