wp-epub-gen 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +261 -75
- package/build/downloadImage.d.ts +0 -5
- package/build/errors.d.ts +0 -1
- package/build/generateTempFile.d.ts +0 -5
- package/build/index.d.ts +1 -5
- package/build/index.js +422 -118
- package/build/index.mjs +1043 -0
- package/build/libs/safeFineName.d.ts +0 -1
- package/build/libs/utils.d.ts +1 -7
- package/build/makeCover.d.ts +0 -5
- package/build/parseContent.d.ts +0 -5
- package/build/render.d.ts +0 -5
- package/build/templates.d.ts +11 -0
- package/build/types.d.ts +0 -1
- package/package.json +29 -35
- package/tsconfig.json +8 -7
- package/vite.config.ts +76 -3
- package/vitest.config.ts +9 -0
package/build/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const mime = require("mime");
|
|
4
3
|
const os = require("os");
|
|
5
4
|
const path = require("path");
|
|
5
|
+
const url = require("url");
|
|
6
6
|
const uuid = require("uuid");
|
|
7
7
|
const cheerio = require("cheerio");
|
|
8
8
|
const diacritics = require("diacritics");
|
|
@@ -14,6 +14,7 @@ const fs = require("fs");
|
|
|
14
14
|
const util = require("util");
|
|
15
15
|
const ejs = require("ejs");
|
|
16
16
|
const entities = require("entities");
|
|
17
|
+
var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
|
|
17
18
|
function _interopNamespaceDefault(e) {
|
|
18
19
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
19
20
|
if (e) {
|
|
@@ -30,13 +31,7 @@ function _interopNamespaceDefault(e) {
|
|
|
30
31
|
n.default = e;
|
|
31
32
|
return Object.freeze(n);
|
|
32
33
|
}
|
|
33
|
-
const
|
|
34
|
-
const os__namespace = /* @__PURE__ */ _interopNamespaceDefault(os);
|
|
35
|
-
const path__namespace = /* @__PURE__ */ _interopNamespaceDefault(path);
|
|
36
|
-
const fs__namespace$1 = /* @__PURE__ */ _interopNamespaceDefault(fs$1);
|
|
37
|
-
const request__namespace = /* @__PURE__ */ _interopNamespaceDefault(request);
|
|
38
|
-
const fs__namespace = /* @__PURE__ */ _interopNamespaceDefault(fs);
|
|
39
|
-
const ejs__namespace = /* @__PURE__ */ _interopNamespaceDefault(ejs);
|
|
34
|
+
const cheerio__namespace = /* @__PURE__ */ _interopNamespaceDefault(cheerio);
|
|
40
35
|
const entities__namespace = /* @__PURE__ */ _interopNamespaceDefault(entities);
|
|
41
36
|
const errors = {
|
|
42
37
|
no_output_path: "No output path!",
|
|
@@ -46,6 +41,8 @@ const errors = {
|
|
|
46
41
|
function safeFineName(name) {
|
|
47
42
|
return name.replace(/[/\\?%*:|"<>\t\r\n]/g, "_");
|
|
48
43
|
}
|
|
44
|
+
const mimeModule$1 = require("mime/lite");
|
|
45
|
+
const mime$1 = mimeModule$1.default || mimeModule$1;
|
|
49
46
|
function parseContent(content, index, epubConfigs) {
|
|
50
47
|
let chapter = { ...content };
|
|
51
48
|
let { filename } = chapter;
|
|
@@ -289,17 +286,21 @@ function parseContent(content, index, epubConfigs) {
|
|
|
289
286
|
"tt",
|
|
290
287
|
"var"
|
|
291
288
|
];
|
|
292
|
-
let $ =
|
|
293
|
-
|
|
294
|
-
|
|
289
|
+
let $ = cheerio__namespace.load(chapter.data, {
|
|
290
|
+
xml: {
|
|
291
|
+
lowerCaseTags: true,
|
|
292
|
+
recognizeSelfClosing: true
|
|
293
|
+
}
|
|
295
294
|
});
|
|
296
295
|
let body = $("body");
|
|
297
296
|
if (body.length) {
|
|
298
297
|
let html = body.html();
|
|
299
298
|
if (html) {
|
|
300
|
-
$ =
|
|
301
|
-
|
|
302
|
-
|
|
299
|
+
$ = cheerio__namespace.load(html, {
|
|
300
|
+
xml: {
|
|
301
|
+
lowerCaseTags: true,
|
|
302
|
+
recognizeSelfClosing: true
|
|
303
|
+
}
|
|
303
304
|
});
|
|
304
305
|
}
|
|
305
306
|
}
|
|
@@ -336,8 +337,8 @@ function parseContent(content, index, epubConfigs) {
|
|
|
336
337
|
}
|
|
337
338
|
});
|
|
338
339
|
$("img").each((index2, elem) => {
|
|
339
|
-
let
|
|
340
|
-
let image = epubConfigs.images.find((el) => el.url ===
|
|
340
|
+
let url2 = $(elem).attr("src") || "";
|
|
341
|
+
let image = epubConfigs.images.find((el) => el.url === url2);
|
|
341
342
|
let id;
|
|
342
343
|
let extension;
|
|
343
344
|
if (image) {
|
|
@@ -345,10 +346,10 @@ function parseContent(content, index, epubConfigs) {
|
|
|
345
346
|
extension = image.extension;
|
|
346
347
|
} else {
|
|
347
348
|
id = uuid.v4();
|
|
348
|
-
let mediaType = mime.getType(
|
|
349
|
-
extension = mime.getExtension(mediaType) || "";
|
|
349
|
+
let mediaType = mime$1.getType(url2.replace(/\?.*/, "")) || "";
|
|
350
|
+
extension = mime$1.getExtension(mediaType) || "";
|
|
350
351
|
let dir = chapter.dir || "";
|
|
351
|
-
let img = { id, url, dir, mediaType, extension };
|
|
352
|
+
let img = { id, url: url2, dir, mediaType, extension };
|
|
352
353
|
epubConfigs.images.push(img);
|
|
353
354
|
}
|
|
354
355
|
$(elem).attr("src", `images/${id}.${extension}`);
|
|
@@ -361,18 +362,17 @@ function parseContent(content, index, epubConfigs) {
|
|
|
361
362
|
}
|
|
362
363
|
return chapter;
|
|
363
364
|
}
|
|
364
|
-
|
|
365
|
-
const writeFile = util.promisify(
|
|
365
|
+
util.promisify(fs.readFile);
|
|
366
|
+
const writeFile = util.promisify(fs.writeFile);
|
|
366
367
|
const USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36";
|
|
367
368
|
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
368
369
|
async function fileIsStable(filename, max_wait = 3e4) {
|
|
369
370
|
let start_time = (/* @__PURE__ */ new Date()).getTime();
|
|
370
|
-
let last_size =
|
|
371
|
+
let last_size = fs.statSync(filename).size;
|
|
371
372
|
while ((/* @__PURE__ */ new Date()).getTime() - start_time <= max_wait) {
|
|
372
373
|
await wait(1e3);
|
|
373
|
-
let size =
|
|
374
|
-
if (size === last_size)
|
|
375
|
-
return true;
|
|
374
|
+
let size = fs.statSync(filename).size;
|
|
375
|
+
if (size === last_size) return true;
|
|
376
376
|
last_size = size;
|
|
377
377
|
}
|
|
378
378
|
return false;
|
|
@@ -382,93 +382,394 @@ function simpleMinifier(xhtml) {
|
|
|
382
382
|
return xhtml;
|
|
383
383
|
}
|
|
384
384
|
const downloadImage = async (epubData, options) => {
|
|
385
|
-
let { url } = options;
|
|
385
|
+
let { url: url2 } = options;
|
|
386
386
|
let { log } = epubData;
|
|
387
387
|
let epub_dir = epubData.dir;
|
|
388
|
-
if (!
|
|
388
|
+
if (!url2) {
|
|
389
389
|
return;
|
|
390
390
|
}
|
|
391
|
-
let image_dir =
|
|
392
|
-
|
|
393
|
-
let filename =
|
|
394
|
-
if (
|
|
395
|
-
let
|
|
391
|
+
let image_dir = path.join(epub_dir, "OEBPS", "images");
|
|
392
|
+
fs$1.ensureDirSync(image_dir);
|
|
393
|
+
let filename = path.join(image_dir, options.id + "." + options.extension);
|
|
394
|
+
if (url2.startsWith("file://") || url2.startsWith("/")) {
|
|
395
|
+
let aux_path = url2.replace(/^file:\/\//i, "");
|
|
396
|
+
try {
|
|
397
|
+
aux_path = decodeURIComponent(aux_path);
|
|
398
|
+
} catch (e) {
|
|
399
|
+
log(`[URL Decode Warning] Failed to decode path: ${aux_path}`);
|
|
400
|
+
}
|
|
396
401
|
if (process.platform === "win32") {
|
|
397
|
-
if (
|
|
398
|
-
|
|
402
|
+
if (aux_path.match(/^\/[a-zA-Z]:/)) {
|
|
403
|
+
aux_path = aux_path.replace(/^\//, "");
|
|
399
404
|
}
|
|
400
405
|
}
|
|
401
|
-
log(`[Copy 1] '${
|
|
402
|
-
if (
|
|
406
|
+
log(`[Copy 1] '${aux_path}' to '${filename}'`);
|
|
407
|
+
if (fs$1.existsSync(aux_path)) {
|
|
403
408
|
try {
|
|
404
|
-
|
|
409
|
+
fs$1.copySync(aux_path, filename);
|
|
405
410
|
} catch (e) {
|
|
406
411
|
log("[Copy 1 Error] " + e.message);
|
|
407
412
|
}
|
|
408
413
|
} else {
|
|
409
|
-
log(`[Copy 1 Fail] '${
|
|
414
|
+
log(`[Copy 1 Fail] '${url2}' not exists!`);
|
|
410
415
|
}
|
|
411
416
|
return;
|
|
412
417
|
}
|
|
413
418
|
let requestAction;
|
|
414
|
-
if (
|
|
415
|
-
requestAction =
|
|
416
|
-
requestAction.pipe(
|
|
419
|
+
if (url2.startsWith("http")) {
|
|
420
|
+
requestAction = request.get(url2).set({ "User-Agent": USER_AGENT });
|
|
421
|
+
requestAction.pipe(fs$1.createWriteStream(filename));
|
|
417
422
|
} else {
|
|
418
|
-
log(`[Copy 2] '${
|
|
419
|
-
requestAction =
|
|
420
|
-
requestAction.pipe(
|
|
423
|
+
log(`[Copy 2] '${url2}' to '${filename}'`);
|
|
424
|
+
requestAction = fs$1.createReadStream(path.join(options.dir || "", url2));
|
|
425
|
+
requestAction.pipe(fs$1.createWriteStream(filename));
|
|
421
426
|
}
|
|
422
427
|
return new Promise((resolve, reject) => {
|
|
423
428
|
requestAction.on("error", (err) => {
|
|
424
|
-
log("[Download Error] Error while downloading: " +
|
|
429
|
+
log("[Download Error] Error while downloading: " + url2);
|
|
425
430
|
log(err);
|
|
426
|
-
|
|
431
|
+
fs$1.unlinkSync(filename);
|
|
427
432
|
resolve();
|
|
428
433
|
});
|
|
429
434
|
requestAction.on("end", () => {
|
|
430
|
-
log("[Download Success] " +
|
|
435
|
+
log("[Download Success] " + url2);
|
|
431
436
|
resolve();
|
|
432
437
|
});
|
|
433
438
|
});
|
|
434
439
|
};
|
|
435
440
|
const downloadAllImages = async (epubData) => {
|
|
436
441
|
let { images } = epubData;
|
|
437
|
-
if (images.length === 0)
|
|
438
|
-
|
|
439
|
-
fs__namespace$1.ensureDirSync(path__namespace.join(epubData.dir, "OEBPS", "images"));
|
|
442
|
+
if (images.length === 0) return;
|
|
443
|
+
fs$1.ensureDirSync(path.join(epubData.dir, "OEBPS", "images"));
|
|
440
444
|
for (let image of images) {
|
|
441
445
|
await downloadImage(epubData, image);
|
|
442
446
|
}
|
|
443
447
|
};
|
|
448
|
+
const epub2_content_opf_ejs = `<?xml version="1.0" encoding="UTF-8"?>
|
|
449
|
+
<package xmlns="http://www.idpf.org/2007/opf"
|
|
450
|
+
version="2.0"
|
|
451
|
+
unique-identifier="BookId">
|
|
452
|
+
|
|
453
|
+
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
454
|
+
xmlns:opf="http://www.idpf.org/2007/opf">
|
|
455
|
+
|
|
456
|
+
<dc:identifier id="BookId" opf:scheme="URN"><%= id %></dc:identifier>
|
|
457
|
+
<dc:title><%= title %></dc:title>
|
|
458
|
+
<dc:description><%= description %></dc:description>
|
|
459
|
+
<dc:publisher><%= publisher || "anonymous" %></dc:publisher>
|
|
460
|
+
<dc:creator opf:role="aut" opf:file-as="<%= author.length ? author.join(",") : author %>"><%= author.length ? author.join(",") : author %></dc:creator>
|
|
461
|
+
<dc:date opf:event="modification"><%= date %></dc:date>
|
|
462
|
+
<dc:language><%= lang || "en" %></dc:language>
|
|
463
|
+
<meta name="cover" content="image_cover"/>
|
|
464
|
+
<meta name="generator" content="epub-gen"/>
|
|
465
|
+
|
|
466
|
+
</metadata>
|
|
467
|
+
|
|
468
|
+
<manifest>
|
|
469
|
+
<item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml"/>
|
|
470
|
+
<item id="toc" href="toc.xhtml" media-type="application/xhtml+xml"/>
|
|
471
|
+
<item id="css" href="style.css" media-type="text/css"/>
|
|
472
|
+
|
|
473
|
+
<% if(locals.cover) { %>
|
|
474
|
+
<item id="image_cover" href="cover.<%= _coverExtension %>" media-type="<%= _coverMediaType %>"/>
|
|
475
|
+
<% } %>
|
|
476
|
+
|
|
477
|
+
<% images.forEach(function(image, index){ %>
|
|
478
|
+
<item id="image_<%= index %>" href="images/<%= image.id %>.<%= image.extension %>" media-type="<%= image.mediaType %>"/>
|
|
479
|
+
<% }) %>
|
|
480
|
+
|
|
481
|
+
<% content.forEach(function(content, index){ %>
|
|
482
|
+
<item id="content_<%= index %>_<%= content.id %>" href="<%= content.href %>" media-type="application/xhtml+xml"/>
|
|
483
|
+
<% }) %>
|
|
484
|
+
|
|
485
|
+
<% fonts.forEach(function(font, index) { %>
|
|
486
|
+
<item id="font_<%= index %>" href="fonts/<%= font %>" media-type="application/x-font-ttf"/>
|
|
487
|
+
<% }) %>
|
|
488
|
+
</manifest>
|
|
489
|
+
|
|
490
|
+
<spine toc="ncx">
|
|
491
|
+
<% content.forEach(function(content, index){ %>
|
|
492
|
+
<% if(content.beforeToc && !content.excludeFromToc){ %>
|
|
493
|
+
<itemref idref="content_<%= index %>_<%= content.id %>"/>
|
|
494
|
+
<% } %>
|
|
495
|
+
<% }) %>
|
|
496
|
+
<itemref idref="toc"/>
|
|
497
|
+
<% content.forEach(function(content, index){ %>
|
|
498
|
+
<% if(!content.beforeToc && !content.excludeFromToc){ %>
|
|
499
|
+
<itemref idref="content_<%= index %>_<%= content.id %>"/>
|
|
500
|
+
<% } %>
|
|
501
|
+
<% }) %>
|
|
502
|
+
</spine>
|
|
503
|
+
<guide/>
|
|
504
|
+
</package>
|
|
505
|
+
`;
|
|
506
|
+
const epub2_toc_xhtml_ejs = `<?xml version="1.0" encoding="UTF-8"?>
|
|
507
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
|
508
|
+
<html xml:lang="<%- lang %>" xmlns="http://www.w3.org/1999/xhtml">
|
|
509
|
+
<head>
|
|
510
|
+
<title><%= title %></title>
|
|
511
|
+
<meta charset="UTF-8"/>
|
|
512
|
+
<link rel="stylesheet" type="text/css" href="style.css"/>
|
|
513
|
+
</head>
|
|
514
|
+
<body>
|
|
515
|
+
<h1 class="h1"><%= tocTitle %></h1>
|
|
516
|
+
<% content.forEach(function(content, index){ %>
|
|
517
|
+
<% if(!content.excludeFromToc){ %>
|
|
518
|
+
<p class="table-of-content">
|
|
519
|
+
<a href="<%= content.href %>"><%= (1 + index) + ". " + (content.title || "Chapter " + (1 + index)) %>
|
|
520
|
+
<% if(content.author.length){ %>
|
|
521
|
+
- <small class="toc-author"><%= content.author.join(",") %></small>
|
|
522
|
+
<% } %>
|
|
523
|
+
<% if(content.url){ %><span class="toc-link"><%= content.url %></span>
|
|
524
|
+
<% }else{ %><span class="toc-link"></span>
|
|
525
|
+
<% } %>
|
|
526
|
+
</a>
|
|
527
|
+
</p>
|
|
528
|
+
<% } %>
|
|
529
|
+
<% }) %>
|
|
530
|
+
</body>
|
|
531
|
+
</html>
|
|
532
|
+
`;
|
|
533
|
+
const epub3_content_opf_ejs = `<?xml version="1.0" encoding="UTF-8"?>
|
|
534
|
+
<package xmlns="http://www.idpf.org/2007/opf"
|
|
535
|
+
version="3.0"
|
|
536
|
+
unique-identifier="BookId"
|
|
537
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
538
|
+
xmlns:dcterms="http://purl.org/dc/terms/"
|
|
539
|
+
xml:lang="en"
|
|
540
|
+
xmlns:media="http://www.idpf.org/epub/vocab/overlays/#"
|
|
541
|
+
prefix="ibooks: http://vocabulary.itunes.apple.com/rdf/ibooks/vocabulary-extensions-1.0/">
|
|
542
|
+
|
|
543
|
+
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
|
|
544
|
+
|
|
545
|
+
<dc:identifier id="BookId"><%= id %></dc:identifier>
|
|
546
|
+
<meta refines="#BookId" property="identifier-type" scheme="onix:codelist5">22</meta>
|
|
547
|
+
<meta property="dcterms:identifier" id="meta-identifier">BookId</meta>
|
|
548
|
+
<dc:title><%= title %></dc:title>
|
|
549
|
+
<meta property="dcterms:title" id="meta-title"><%= title %></meta>
|
|
550
|
+
<dc:language><%= lang || "en" %></dc:language>
|
|
551
|
+
<meta property="dcterms:language" id="meta-language"><%= lang || "en" %></meta>
|
|
552
|
+
<meta property="dcterms:modified"><%= (new Date()).toISOString().split(".")[0] + "Z" %></meta>
|
|
553
|
+
<dc:creator id="creator"><%= author.length ? author.join(",") : author %></dc:creator>
|
|
554
|
+
<meta refines="#creator" property="file-as"><%= author.length ? author.join(",") : author %></meta>
|
|
555
|
+
<meta property="dcterms:publisher"><%= publisher || "anonymous" %></meta>
|
|
556
|
+
<dc:publisher><%= publisher || "anonymous" %></dc:publisher>
|
|
557
|
+
<% var date = new Date(); var year = date.getFullYear(); var month = date.getMonth() + 1; var day = date.getDate(); var stringDate = "" + year + "-" + month + "-" + day; %>
|
|
558
|
+
<meta property="dcterms:date"><%= stringDate %></meta>
|
|
559
|
+
<dc:date><%= stringDate %></dc:date>
|
|
560
|
+
<meta property="dcterms:rights">All rights reserved</meta>
|
|
561
|
+
<dc:rights>Copyright © <%= (new Date()).getFullYear() %> by <%= publisher || "anonymous" %></dc:rights>
|
|
562
|
+
<% if(locals.cover) { %>
|
|
563
|
+
<meta name="cover" content="image_cover" />
|
|
564
|
+
<% } %>
|
|
565
|
+
<meta name="generator" content="epub-gen" />
|
|
566
|
+
<meta property="ibooks:specified-fonts">true</meta>
|
|
567
|
+
</metadata>
|
|
568
|
+
|
|
569
|
+
<manifest>
|
|
570
|
+
<item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml" />
|
|
571
|
+
<item id="toc" href="toc.xhtml" media-type="application/xhtml+xml" properties="nav" />
|
|
572
|
+
<item id="css" href="style.css" media-type="text/css" />
|
|
573
|
+
|
|
574
|
+
<% if(locals.cover) { %>
|
|
575
|
+
<item id="image_cover" href="cover.<%= _coverExtension %>" media-type="<%= _coverMediaType %>" />
|
|
576
|
+
<% } %>
|
|
577
|
+
|
|
578
|
+
<% images.forEach(function(image, index){ %>
|
|
579
|
+
<item id="image_<%= index %>" href="images/<%= image.id %>.<%= image.extension %>" media-type="<%= image.mediaType %>" />
|
|
580
|
+
<% }) %>
|
|
581
|
+
|
|
582
|
+
<% function renderContentItem(content) { %>
|
|
583
|
+
<% content.forEach(function(content){ %>
|
|
584
|
+
<item id="content_<%= content.id %>" href="<%= content.href %>" media-type="application/xhtml+xml" />
|
|
585
|
+
<% if (Array.isArray(content.children)) { %>
|
|
586
|
+
<% renderContentItem(content.children) %>
|
|
587
|
+
<% } %>
|
|
588
|
+
<% }) %>
|
|
589
|
+
<% } %>
|
|
590
|
+
<% renderContentItem(content) %>
|
|
591
|
+
|
|
592
|
+
<% fonts.forEach(function(font, index){ %>
|
|
593
|
+
<item id="font_<%= index %>" href="fonts/<%= font %>" media-type="application/x-font-ttf" />
|
|
594
|
+
<% }) %>
|
|
595
|
+
</manifest>
|
|
596
|
+
|
|
597
|
+
<spine toc="ncx">
|
|
598
|
+
<% var nodes_1 = content.filter(item => !item.excludeFromToc && item.beforeToc) %>
|
|
599
|
+
<% var nodes_2 = content.filter(item => !item.excludeFromToc && !item.beforeToc) %>
|
|
600
|
+
<% function renderToc(nodes) { %>
|
|
601
|
+
<% nodes.forEach(function(content){ %>
|
|
602
|
+
<itemref idref="content_<%= content.id %>" />
|
|
603
|
+
<% if (Array.isArray(content.children)) { %>
|
|
604
|
+
<% renderToc(content.children) %>
|
|
605
|
+
<% } %>
|
|
606
|
+
<% }) %>
|
|
607
|
+
<% } %>
|
|
608
|
+
<% renderToc(nodes_1) %>
|
|
609
|
+
<itemref idref="toc" />
|
|
610
|
+
<% renderToc(nodes_2) %>
|
|
611
|
+
</spine>
|
|
612
|
+
<guide>
|
|
613
|
+
<reference type="text" title="Table of Content" href="toc.xhtml" />
|
|
614
|
+
</guide>
|
|
615
|
+
</package>
|
|
616
|
+
`;
|
|
617
|
+
const epub3_toc_xhtml_ejs = `<?xml version="1.0" encoding="UTF-8"?>
|
|
618
|
+
<!DOCTYPE html>
|
|
619
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xml:lang="<%- lang %>"
|
|
620
|
+
lang="<%- lang %>">
|
|
621
|
+
<head>
|
|
622
|
+
<title><%= title %></title>
|
|
623
|
+
<meta charset="UTF-8" />
|
|
624
|
+
<link rel="stylesheet" type="text/css" href="style.css" />
|
|
625
|
+
</head>
|
|
626
|
+
<body>
|
|
627
|
+
<h1 class="h1"><%= tocTitle %></h1>
|
|
628
|
+
<nav id="toc" class="TOC" epub:type="toc">
|
|
629
|
+
<% var nodes_1 = content.filter(item => !item.excludeFromToc && item.beforeToc) %>
|
|
630
|
+
<% var nodes_2 = content.filter(item => !item.excludeFromToc && !item.beforeToc) %>
|
|
631
|
+
<% function renderToc(nodes, indent = 0) { %>
|
|
632
|
+
<ol>
|
|
633
|
+
<% nodes.forEach(function(content, index){ %>
|
|
634
|
+
<li class="table-of-content">
|
|
635
|
+
<a href="<%= content.href %>"><%= (content.title || "Chapter " + (1 + index)) %>
|
|
636
|
+
<% if(content.author.length){ %> - <small
|
|
637
|
+
class="toc-author"><%= content.author.join(",") %></small>
|
|
638
|
+
<% } %>
|
|
639
|
+
<% if(content.url){ %><span class="toc-link"><%= content.url %></span>
|
|
640
|
+
<% } %>
|
|
641
|
+
</a>
|
|
642
|
+
<% if (Array.isArray(content.children) && content.children.length > 0) { %>
|
|
643
|
+
<% renderToc(content.children, indent + 1) %>
|
|
644
|
+
<% } %>
|
|
645
|
+
</li>
|
|
646
|
+
<% }) %>
|
|
647
|
+
</ol>
|
|
648
|
+
<% } %>
|
|
649
|
+
<% renderToc(nodes_1) %>
|
|
650
|
+
<% renderToc(nodes_2) %>
|
|
651
|
+
</nav>
|
|
652
|
+
|
|
653
|
+
</body>
|
|
654
|
+
</html>
|
|
655
|
+
`;
|
|
656
|
+
const template_css = `.epub-author {
|
|
657
|
+
color: #555;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
.epub-link {
|
|
661
|
+
margin-bottom: 30px;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
.epub-link a {
|
|
665
|
+
color: #666;
|
|
666
|
+
font-size: 90%;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
.toc-author {
|
|
670
|
+
font-size: 90%;
|
|
671
|
+
color: #555;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
.toc-link {
|
|
675
|
+
color: #999;
|
|
676
|
+
font-size: 85%;
|
|
677
|
+
display: block;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
hr {
|
|
681
|
+
border: 0;
|
|
682
|
+
border-bottom: 1px solid #dedede;
|
|
683
|
+
margin: 60px 10%;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
.TOC > ol {
|
|
687
|
+
margin: 0;
|
|
688
|
+
padding: 0;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
.TOC > ol ol {
|
|
692
|
+
padding: 0;
|
|
693
|
+
margin-left: 2em;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
.TOC li {
|
|
697
|
+
font-size: 16px;
|
|
698
|
+
list-style: none;
|
|
699
|
+
margin: 0 auto;
|
|
700
|
+
padding: 0;
|
|
701
|
+
}
|
|
702
|
+
`;
|
|
703
|
+
const toc_ncx_ejs = `<?xml version="1.0" encoding="UTF-8"?>
|
|
704
|
+
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
|
|
705
|
+
<head>
|
|
706
|
+
<meta name="dtb:uid" content="<%= id %>"/>
|
|
707
|
+
<meta name="dtb:generator" content="epub-gen"/>
|
|
708
|
+
<meta name="dtb:depth" content="<%= (toc_depth || 1)%>"/>
|
|
709
|
+
<meta name="dtb:totalPageCount" content="0"/>
|
|
710
|
+
<meta name="dtb:maxPageNumber" content="0"/>
|
|
711
|
+
</head>
|
|
712
|
+
<docTitle>
|
|
713
|
+
<text><%= title %></text>
|
|
714
|
+
</docTitle>
|
|
715
|
+
<docAuthor>
|
|
716
|
+
<text><%= author %></text>
|
|
717
|
+
</docAuthor>
|
|
718
|
+
<navMap>
|
|
719
|
+
<% var _index = 1; %>
|
|
720
|
+
<% var nodes_1 = content.filter(c => !c.excludeFromToc && c.beforeToc) %>
|
|
721
|
+
<% var nodes_2 = content.filter(c => !c.excludeFromToc && !c.beforeToc) %>
|
|
722
|
+
<% function renderToc(nodes) { %>
|
|
723
|
+
<% nodes.forEach(function(content, index){ %>
|
|
724
|
+
<navPoint id="content_<%= content.id %>" playOrder="<%= _index++ %>" class="chapter">
|
|
725
|
+
<navLabel>
|
|
726
|
+
<text><%= (tocAutoNumber ? ((1 + index) + ". ") : "") + (content.title || "Chapter " + (1 + index)) %></text>
|
|
727
|
+
</navLabel>
|
|
728
|
+
<content src="<%= content.href %>"/>
|
|
729
|
+
<% if (Array.isArray(content.children)) { %>
|
|
730
|
+
<% renderToc(content.children) %>
|
|
731
|
+
<% } %>
|
|
732
|
+
</navPoint>
|
|
733
|
+
<% }) %>
|
|
734
|
+
<% } %>
|
|
735
|
+
|
|
736
|
+
<% renderToc(nodes_1) %>
|
|
737
|
+
|
|
738
|
+
<navPoint id="toc" playOrder="<%= _index++ %>" class="chapter">
|
|
739
|
+
<navLabel>
|
|
740
|
+
<text><%= tocTitle %></text>
|
|
741
|
+
</navLabel>
|
|
742
|
+
<content src="toc.xhtml"/>
|
|
743
|
+
</navPoint>
|
|
744
|
+
|
|
745
|
+
<% renderToc(nodes_2) %>
|
|
746
|
+
</navMap>
|
|
747
|
+
</ncx>
|
|
748
|
+
`;
|
|
444
749
|
const generateTempFile = async (epubData) => {
|
|
445
|
-
var _a;
|
|
446
750
|
let { log } = epubData;
|
|
447
|
-
let oebps_dir =
|
|
448
|
-
await
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
await fs__namespace$1.ensureDir(fonts_dir);
|
|
751
|
+
let oebps_dir = path.join(epubData.dir, "OEBPS");
|
|
752
|
+
await fs$1.ensureDir(oebps_dir);
|
|
753
|
+
epubData.css = epubData.css || template_css;
|
|
754
|
+
await writeFile(path.join(oebps_dir, "style.css"), epubData.css, "utf-8");
|
|
755
|
+
if (epubData.fonts?.length) {
|
|
756
|
+
let fonts_dir = path.join(oebps_dir, "fonts");
|
|
757
|
+
await fs$1.ensureDir(fonts_dir);
|
|
455
758
|
epubData.fonts = epubData.fonts.map((font) => {
|
|
456
|
-
let filename =
|
|
457
|
-
if (!
|
|
759
|
+
let filename = path.basename(font);
|
|
760
|
+
if (!fs$1.existsSync(font)) {
|
|
458
761
|
log(`Custom font not found at '${font}'.`);
|
|
459
762
|
} else {
|
|
460
|
-
|
|
763
|
+
fs$1.copySync(font, path.join(fonts_dir, filename));
|
|
461
764
|
}
|
|
462
765
|
return filename;
|
|
463
766
|
});
|
|
464
767
|
}
|
|
465
768
|
const isAppendTitle = (global_append, local_append) => {
|
|
466
|
-
if (typeof local_append === "boolean")
|
|
467
|
-
return local_append;
|
|
769
|
+
if (typeof local_append === "boolean") return local_append;
|
|
468
770
|
return !!global_append;
|
|
469
771
|
};
|
|
470
772
|
const saveContentToFile = (content) => {
|
|
471
|
-
var _a2;
|
|
472
773
|
let title = entities__namespace.encodeXML(content.title || "");
|
|
473
774
|
let html = `${epubData.docHeader}
|
|
474
775
|
<head>
|
|
@@ -481,21 +782,21 @@ const generateTempFile = async (epubData) => {
|
|
|
481
782
|
if (content.title && isAppendTitle(epubData.appendChapterTitles, content.appendChapterTitle)) {
|
|
482
783
|
html += `<h1>${title}</h1>`;
|
|
483
784
|
}
|
|
484
|
-
html += content.title && content.author &&
|
|
785
|
+
html += content.title && content.author && content.author?.length ? `<p class='epub-author'>${entities__namespace.encodeXML(content.author.join(", "))}</p>` : "";
|
|
485
786
|
html += content.title && content.url ? `<p class="epub-link"><a href="${content.url}">${content.url}</a></p>` : "";
|
|
486
787
|
html += `${content.data}`;
|
|
487
788
|
html += "\n</body>\n</html>";
|
|
488
|
-
|
|
489
|
-
|
|
789
|
+
fs$1.ensureDirSync(path.dirname(content.filePath));
|
|
790
|
+
fs$1.writeFileSync(content.filePath, html, "utf-8");
|
|
490
791
|
if (Array.isArray(content.children)) {
|
|
491
792
|
content.children.map(saveContentToFile);
|
|
492
793
|
}
|
|
493
794
|
};
|
|
494
795
|
epubData.content.map(saveContentToFile);
|
|
495
|
-
let metainf_dir =
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
796
|
+
let metainf_dir = path.join(epubData.dir, "META-INF");
|
|
797
|
+
fs$1.ensureDirSync(metainf_dir);
|
|
798
|
+
fs$1.writeFileSync(
|
|
799
|
+
path.join(metainf_dir, "container.xml"),
|
|
499
800
|
`<?xml version="1.0" encoding="UTF-8" ?>
|
|
500
801
|
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
|
|
501
802
|
<rootfiles><rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/></rootfiles>
|
|
@@ -503,8 +804,8 @@ const generateTempFile = async (epubData) => {
|
|
|
503
804
|
"utf-8"
|
|
504
805
|
);
|
|
505
806
|
if (epubData.version === 2) {
|
|
506
|
-
let fn =
|
|
507
|
-
|
|
807
|
+
let fn = path.join(metainf_dir, "com.apple.ibooks.display-options.xml");
|
|
808
|
+
fs$1.writeFileSync(
|
|
508
809
|
fn,
|
|
509
810
|
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
510
811
|
<display_options>
|
|
@@ -516,50 +817,53 @@ const generateTempFile = async (epubData) => {
|
|
|
516
817
|
"utf-8"
|
|
517
818
|
);
|
|
518
819
|
}
|
|
519
|
-
let
|
|
520
|
-
|
|
521
|
-
|
|
820
|
+
let opfTemplate;
|
|
821
|
+
let ncxTocTemplate;
|
|
822
|
+
let htmlTocTemplate;
|
|
823
|
+
if (epubData.customOpfTemplatePath && fs$1.existsSync(epubData.customOpfTemplatePath)) {
|
|
824
|
+
const { readFile } = require("./libs/utils");
|
|
825
|
+
opfTemplate = await readFile(epubData.customOpfTemplatePath, "utf-8");
|
|
826
|
+
} else {
|
|
827
|
+
opfTemplate = epubData.version === 2 ? epub2_content_opf_ejs : epub3_content_opf_ejs;
|
|
522
828
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
829
|
+
if (epubData.customNcxTocTemplatePath && fs$1.existsSync(epubData.customNcxTocTemplatePath)) {
|
|
830
|
+
const { readFile } = require("./libs/utils");
|
|
831
|
+
ncxTocTemplate = await readFile(epubData.customNcxTocTemplatePath, "utf-8");
|
|
832
|
+
} else {
|
|
833
|
+
ncxTocTemplate = toc_ncx_ejs;
|
|
526
834
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
835
|
+
if (epubData.customHtmlTocTemplatePath && fs$1.existsSync(epubData.customHtmlTocTemplatePath)) {
|
|
836
|
+
const { readFile } = require("./libs/utils");
|
|
837
|
+
htmlTocTemplate = await readFile(epubData.customHtmlTocTemplatePath, "utf-8");
|
|
838
|
+
} else {
|
|
839
|
+
htmlTocTemplate = epubData.version === 2 ? epub2_toc_xhtml_ejs : epub3_toc_xhtml_ejs;
|
|
530
840
|
}
|
|
531
841
|
let toc_depth = 1;
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
);
|
|
537
|
-
fs__namespace$1.writeFileSync(
|
|
538
|
-
path__namespace.join(oebps_dir, "toc.ncx"),
|
|
539
|
-
await ejs__namespace.renderFile(ncxTocPath, { ...epubData, toc_depth }),
|
|
842
|
+
fs$1.writeFileSync(path.join(oebps_dir, "content.opf"), ejs.render(opfTemplate, epubData), "utf-8");
|
|
843
|
+
fs$1.writeFileSync(
|
|
844
|
+
path.join(oebps_dir, "toc.ncx"),
|
|
845
|
+
ejs.render(ncxTocTemplate, { ...epubData, toc_depth }),
|
|
540
846
|
"utf-8"
|
|
541
847
|
);
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
simpleMinifier(
|
|
848
|
+
fs$1.writeFileSync(
|
|
849
|
+
path.join(oebps_dir, "toc.xhtml"),
|
|
850
|
+
simpleMinifier(ejs.render(htmlTocTemplate, epubData)),
|
|
545
851
|
"utf-8"
|
|
546
852
|
);
|
|
547
853
|
};
|
|
548
854
|
async function makeCover(data) {
|
|
549
855
|
let { cover, _coverExtension, log } = data;
|
|
550
|
-
if (!cover)
|
|
551
|
-
|
|
552
|
-
let destPath = path__namespace.join(data.dir, "OEBPS", `cover.${_coverExtension}`);
|
|
856
|
+
if (!cover) return;
|
|
857
|
+
let destPath = path.join(data.dir, "OEBPS", `cover.${_coverExtension}`);
|
|
553
858
|
let writeStream = null;
|
|
554
859
|
if (cover.startsWith("http")) {
|
|
555
|
-
writeStream =
|
|
556
|
-
writeStream.pipe(
|
|
860
|
+
writeStream = request.get(cover).set({ "User-Agent": USER_AGENT });
|
|
861
|
+
writeStream.pipe(fs$1.createWriteStream(destPath));
|
|
557
862
|
} else {
|
|
558
|
-
if (!
|
|
559
|
-
return;
|
|
863
|
+
if (!fs$1.existsSync(cover)) return;
|
|
560
864
|
log("local cover image: " + cover);
|
|
561
|
-
writeStream =
|
|
562
|
-
writeStream.pipe(
|
|
865
|
+
writeStream = fs$1.createReadStream(cover);
|
|
866
|
+
writeStream.pipe(fs$1.createWriteStream(destPath));
|
|
563
867
|
}
|
|
564
868
|
return new Promise((resolve) => {
|
|
565
869
|
writeStream.on("end", () => {
|
|
@@ -569,9 +873,9 @@ async function makeCover(data) {
|
|
|
569
873
|
writeStream.on("error", (e) => {
|
|
570
874
|
log("[Error] cover image error: " + e.message);
|
|
571
875
|
log("destPath: " + destPath);
|
|
572
|
-
if (
|
|
876
|
+
if (fs$1.existsSync(destPath)) {
|
|
573
877
|
try {
|
|
574
|
-
|
|
878
|
+
fs$1.unlinkSync(destPath);
|
|
575
879
|
log("destPath removed.");
|
|
576
880
|
} catch (e2) {
|
|
577
881
|
log("[Error] remove cover image error: " + e2.message);
|
|
@@ -635,7 +939,11 @@ async function genEpub(epubData) {
|
|
|
635
939
|
archive.finalize();
|
|
636
940
|
});
|
|
637
941
|
}
|
|
638
|
-
const
|
|
942
|
+
const mimeModule = require("mime/lite");
|
|
943
|
+
const mime = mimeModule.default || mimeModule;
|
|
944
|
+
const __filename$1 = url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index.js", document.baseURI).href);
|
|
945
|
+
const __dirname$1 = path.dirname(__filename$1);
|
|
946
|
+
const baseDir = __dirname$1;
|
|
639
947
|
function result(success, message, options) {
|
|
640
948
|
if (options && options.verbose) {
|
|
641
949
|
if (!success) {
|
|
@@ -666,7 +974,7 @@ function check(options) {
|
|
|
666
974
|
return result(true, void 0, options);
|
|
667
975
|
}
|
|
668
976
|
function parseOptions(options) {
|
|
669
|
-
let tmpDir = options.tmpDir ||
|
|
977
|
+
let tmpDir = options.tmpDir || os.tmpdir();
|
|
670
978
|
let id = uuid.v4();
|
|
671
979
|
let data = {
|
|
672
980
|
description: options.title,
|
|
@@ -685,7 +993,7 @@ function parseOptions(options) {
|
|
|
685
993
|
...options,
|
|
686
994
|
id,
|
|
687
995
|
tmpDir,
|
|
688
|
-
dir:
|
|
996
|
+
dir: path.resolve(tmpDir, id),
|
|
689
997
|
baseDir,
|
|
690
998
|
docHeader: "",
|
|
691
999
|
images: [],
|
|
@@ -711,8 +1019,8 @@ function parseOptions(options) {
|
|
|
711
1019
|
}
|
|
712
1020
|
data.content = options.content.map((content, index) => parseContent(content, index, data));
|
|
713
1021
|
if (data.cover) {
|
|
714
|
-
data._coverMediaType =
|
|
715
|
-
data._coverExtension =
|
|
1022
|
+
data._coverMediaType = mime.getType(data.cover) || "";
|
|
1023
|
+
data._coverExtension = mime.getExtension(data._coverMediaType) || "";
|
|
716
1024
|
}
|
|
717
1025
|
return data;
|
|
718
1026
|
}
|
|
@@ -724,8 +1032,7 @@ async function epubGen(options, output) {
|
|
|
724
1032
|
let o = check(options);
|
|
725
1033
|
let verbose = options.verbose !== false;
|
|
726
1034
|
if (!o.success) {
|
|
727
|
-
if (verbose)
|
|
728
|
-
console.error(o.message);
|
|
1035
|
+
if (verbose) console.error(o.message);
|
|
729
1036
|
return o;
|
|
730
1037
|
}
|
|
731
1038
|
let t;
|
|
@@ -733,20 +1040,17 @@ async function epubGen(options, output) {
|
|
|
733
1040
|
let data = parseOptions(options);
|
|
734
1041
|
let timeoutSeconds = data.timeoutSeconds || 0;
|
|
735
1042
|
if (timeoutSeconds > 0) {
|
|
736
|
-
if (verbose)
|
|
737
|
-
console.log(`TIMEOUT: ${timeoutSeconds}s`);
|
|
1043
|
+
if (verbose) console.log(`TIMEOUT: ${timeoutSeconds}s`);
|
|
738
1044
|
t = setTimeout(() => {
|
|
739
1045
|
throw new Error("timeout!");
|
|
740
1046
|
}, timeoutSeconds * 1e3);
|
|
741
1047
|
} else {
|
|
742
|
-
if (verbose)
|
|
743
|
-
console.log(`TIMEOUT: N/A`);
|
|
1048
|
+
if (verbose) console.log(`TIMEOUT: N/A`);
|
|
744
1049
|
}
|
|
745
1050
|
await render(data);
|
|
746
1051
|
return result(true, void 0, data);
|
|
747
1052
|
} catch (e) {
|
|
748
|
-
if (verbose)
|
|
749
|
-
console.error(e);
|
|
1053
|
+
if (verbose) console.error(e);
|
|
750
1054
|
return result(false, e.message, options);
|
|
751
1055
|
} finally {
|
|
752
1056
|
clearTimeout(t);
|