r2-shared-js
Version:
Readium 2 'shared' for NodeJS (TypeScript)
241 lines • 15.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertNccToOpfAndNcx = void 0;
var tslib_1 = require("tslib");
var he = require("he");
var debug_ = require("debug");
var mime = require("mime-types");
var path = require("path");
var xmldom = require("@xmldom/xmldom");
var media_overlay_1 = require("../models/media-overlay");
var BufferUtils_1 = require("r2-utils-js/dist/es5/src/_utils/stream/BufferUtils");
var bom_1 = require("r2-utils-js/dist/es5/src/_utils/bom");
var zipHasEntry_1 = require("../_utils/zipHasEntry");
var epub_daisy_common_1 = require("./epub-daisy-common");
var debug = debug_("r2:shared#parser/daisy-convert-to-epub");
var decodeHtmlAttributeValue = function (val) {
var decoded = he.decode(val, { isAttributeValue: true });
return decoded;
};
var decodeHtmlTextContent = function (textContent) {
var decoded = he.decode(textContent);
return decoded;
};
var encodeXmlAttributeValue = function (val) {
return val.replace(/"/g, """);
};
var encodeXmlTextContent = function (textContent) {
return textContent.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
};
var getMediaTypeFromFileExtension = function (ext) {
if (/\.smil$/i.test(ext)) {
return "application/smil+xml";
}
if (/\.css$/i.test(ext)) {
return "text/css";
}
if (/\.mp3$/i.test(ext)) {
return "audio/mpeg";
}
if (/\.wav$/i.test(ext)) {
return "audio/wav";
}
if (/\.jpe?g$/i.test(ext)) {
return "image/jpeg";
}
if (/\.png$/i.test(ext)) {
return "image/png";
}
if (/\.xml$/i.test(ext)) {
return "application/x-dtbook+xml";
}
if (/\.html$/i.test(ext)) {
return "text/html";
}
if (/\.xhtml$/i.test(ext)) {
return "application/xhtml+xml";
}
return mime.lookup("dummy" + ext);
};
var convertNccToOpfAndNcx = function (zip, rootfilePathDecoded, rootfilePath) { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
var has, err, zipEntries, _i, zipEntries_1, zipEntry, nccZipStream_, err_1, nccZipStream, nccZipData, err_2, nccStr, nccDoc, metas, aElems, multimediaContent, multimediaType, zipEntriez, manifestItemsBaseStr, arrSmils, manifestItemsStr, spineItemsStr, playOrder, pCount, pageListStr, navMapStr, opfStr, opf, ncxStr, ncx;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4, (0, zipHasEntry_1.zipHasEntry)(zip, rootfilePathDecoded, rootfilePath)];
case 1:
has = _a.sent();
if (!!has) return [3, 3];
err = "NOT IN ZIP (NCC.html): ".concat(rootfilePath, " --- ").concat(rootfilePathDecoded);
debug(err);
return [4, zip.getEntries()];
case 2:
zipEntries = _a.sent();
for (_i = 0, zipEntries_1 = zipEntries; _i < zipEntries_1.length; _i++) {
zipEntry = zipEntries_1[_i];
if (zipEntry.startsWith("__MACOSX/")) {
continue;
}
debug(zipEntry);
}
return [2, Promise.reject(err)];
case 3:
_a.trys.push([3, 5, , 6]);
return [4, zip.entryStreamPromise(rootfilePathDecoded)];
case 4:
nccZipStream_ = _a.sent();
return [3, 6];
case 5:
err_1 = _a.sent();
debug(err_1);
return [2, Promise.reject(err_1)];
case 6:
nccZipStream = nccZipStream_.stream;
_a.label = 7;
case 7:
_a.trys.push([7, 9, , 10]);
return [4, (0, BufferUtils_1.streamToBufferPromise)(nccZipStream)];
case 8:
nccZipData = _a.sent();
return [3, 10];
case 9:
err_2 = _a.sent();
debug(err_2);
return [2, Promise.reject(err_2)];
case 10:
nccStr = (0, bom_1.removeUTF8BOM)(nccZipData.toString("utf8"));
try {
nccDoc = new xmldom.DOMParser().parseFromString(nccStr, "text/html");
}
catch (err1) {
console.log("xmldom.DOMParser().parseFromString text/html ERROR1, attempting DOCTYPE fix...");
console.log(err1);
nccStr = nccStr.replace(/(/, "$1>");
try {
nccDoc = new xmldom.DOMParser().parseFromString(nccStr, "text/html");
}
catch (err2) {
console.log("xmldom.DOMParser().parseFromString text/html ERROR2, fallback to application/xml...");
console.log(err2);
nccDoc = new xmldom.DOMParser().parseFromString(nccStr, "application/xml");
}
}
metas = Array.from(nccDoc.getElementsByTagName("meta")).
reduce(function (prevVal, curVal) {
var name = curVal.getAttribute("name");
var content = curVal.getAttribute("content");
if (name && content) {
prevVal[name] = decodeHtmlAttributeValue(content.trim());
}
return prevVal;
}, {});
aElems = Array.from(nccDoc.getElementsByTagName("a"));
multimediaContent = "";
multimediaType = "";
if (metas["ncc:multimediaType"] === "audioFullText" ||
metas["ncc:multimediaType"] === "audioNcc" ||
metas["ncc:totalTime"] && (0, media_overlay_1.timeStrToSeconds)(metas["ncc:totalTime"]) > 0) {
if (metas["ncc:multimediaType"] === "audioFullText" || !metas["ncc:multimediaType"]) {
multimediaContent = "audio,text,image";
multimediaType = "audioFullText";
}
else {
multimediaContent = "audio,image";
multimediaType = "audioNCX";
}
}
else if (metas["ncc:multimediaType"] === "textNcc" ||
metas["ncc:totalTime"] && (0, media_overlay_1.timeStrToSeconds)(metas["ncc:totalTime"]) === 0) {
multimediaContent = "text,image";
multimediaType = "textNCX";
}
return [4, zip.getEntries()];
case 11:
zipEntriez = (_a.sent()).filter(function (e) {
return e && !e.endsWith("/");
});
manifestItemsBaseStr = zipEntriez.reduce(function (pv, cv, ci) {
var ext = path.extname(cv);
return "".concat(pv).concat(!cv.startsWith("__MACOSX/") && !/ncc\.html$/i.test(cv) && !/\.ent$/i.test(ext) && !/\.dtd$/i.test(ext) && !/\.smil$/i.test(ext) ? "\n <item\n href=\"".concat(encodeXmlAttributeValue(path.relative("file:///" + path.dirname(rootfilePathDecoded), "file:///" + cv).replace(/\\/g, "/")), "\"\n id=\"opf-zip-").concat(ci, "\"\n media-type=\"").concat(getMediaTypeFromFileExtension(ext), "\" />") : "");
}, "");
arrSmils = [];
manifestItemsStr = aElems.reduce(function (pv, cv, _ci) {
var href = cv.getAttribute("href");
if (!href) {
return pv;
}
if (!/\.smil(#.*)?$/i.test(href)) {
return pv;
}
var smil = href.replace(/(.+\.smil)(#.*)?$/i, "$1");
if (arrSmils.indexOf(smil) >= 0) {
return pv;
}
arrSmils.push(smil);
return "".concat(pv).concat("\n <item\n href=\"".concat(encodeXmlAttributeValue(smil), "\"\n id=\"opf-ncc-").concat(arrSmils.length - 1, "\"\n media-type=\"application/smil+xml\" />"));
}, manifestItemsBaseStr);
spineItemsStr = arrSmils.reduce(function (pv, _cv, ci) {
return "".concat(pv).concat("\n <itemref idref=\"opf-ncc-".concat(ci, "\" />"));
}, "");
playOrder = 0;
pCount = 0;
pageListStr = aElems.reduce(function (pv, cv, _ci) {
var href = cv.getAttribute("href");
if (!href) {
return pv;
}
if (!/\.smil(#.*)?$/i.test(href)) {
return pv;
}
if (!cv.parentNode) {
return pv;
}
playOrder++;
var clazz = cv.parentNode.getAttribute("class");
if (!clazz || !clazz.startsWith("page")) {
return pv;
}
var txtContent = cv.textContent ? decodeHtmlTextContent(cv.textContent.trim()) : "";
pCount++;
return "".concat(pv).concat("\n<pageTarget class=\"pagenum\" id=\"ncx-p".concat(pCount, "\" playOrder=\"").concat(playOrder, "\" type=\"normal\" value=\"").concat(pCount, "\">\n<navLabel>\n<text>").concat(txtContent ? encodeXmlTextContent(txtContent) : pCount, "</text>\n</navLabel>\n<content src=\"").concat(encodeXmlAttributeValue(href), "\"/>\n</pageTarget>\n"));
}, "");
playOrder = 0;
pCount = 0;
navMapStr = aElems.reduce(function (pv, cv, _ci) {
var href = cv.getAttribute("href");
if (!href) {
return pv;
}
if (!/\.smil(#.*)?$/i.test(href)) {
return pv;
}
if (!cv.parentNode) {
return pv;
}
playOrder++;
var name = cv.parentNode.localName;
if (!name || !name.startsWith("h")) {
return pv;
}
var level = parseInt(name.substr(1), 10);
var txtContent = cv.textContent ? decodeHtmlTextContent(cv.textContent.trim()) : "";
pCount++;
var inner = "<!-- h".concat(level - 1, "_").concat(pCount - 1, " -->");
if (pv.indexOf(inner) >= 0) {
return pv.replace(inner, "\n<navPoint class=\"".concat(name, "\" id=\"ncx-t").concat(pCount, "\" playOrder=\"").concat(playOrder, "\">\n<navLabel>\n<text>").concat(txtContent ? encodeXmlTextContent(txtContent) : "_".concat(pCount), "</text>\n</navLabel>\n<content src=\"").concat(encodeXmlAttributeValue(href), "\"/>\n<!-- ").concat(name, "_").concat(pCount, " -->\n</navPoint>\n<!-- h").concat(level - 1, "_").concat(pCount, " -->\n"));
}
else {
return "".concat(pv).concat("\n<navPoint class=\"".concat(name, "\" id=\"ncx-t").concat(pCount, "\" playOrder=\"").concat(playOrder, "\">\n<navLabel>\n<text>").concat(txtContent ? encodeXmlTextContent(txtContent) : "_".concat(pCount), "</text>\n</navLabel>\n<content src=\"").concat(encodeXmlAttributeValue(href), "\"/>\n<!-- ").concat(name, "_").concat(pCount, " -->\n</navPoint>\n"));
}
}, "");
opfStr = "xml version=\"1.0\" encoding=\"UTF-8\"?>\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>