UNPKG

r2-shared-js

Version:

Readium 2 'shared' for NodeJS (TypeScript)

704 lines 30.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); var crypto = require("crypto"); var deepEqual = require("fast-deep-equal"); var fs = require("fs"); var jsonDiff = require("json-diff"); var path = require("path"); var url_1 = require("url"); var util = require("util"); var media_overlay_1 = require("../models/media-overlay"); var publication_1 = require("../models/publication"); var publication_link_1 = require("../models/publication-link"); var audiobook_1 = require("../parser/audiobook"); var daisy_1 = require("../parser/daisy"); var daisy_convert_to_epub_1 = require("../parser/daisy-convert-to-epub"); var epub_1 = require("../parser/epub"); var epub_daisy_common_1 = require("../parser/epub-daisy-common"); var publication_parser_1 = require("../parser/publication-parser"); var lcp_1 = require("r2-lcp-js/dist/es5/src/parser/epub/lcp"); var serializable_1 = require("r2-lcp-js/dist/es5/src/serializable"); var UrlUtils_1 = require("r2-utils-js/dist/es5/src/_utils/http/UrlUtils"); var BufferUtils_1 = require("r2-utils-js/dist/es5/src/_utils/stream/BufferUtils"); var transformer_1 = require("../transform/transformer"); var init_globals_1 = require("../init-globals"); var zipHasEntry_1 = require("./zipHasEntry"); (0, init_globals_1.initGlobalConverters_SHARED)(); (0, init_globals_1.initGlobalConverters_GENERIC)(); (0, lcp_1.setLcpNativePluginPath)(path.join(process.cwd(), "LCP", "lcp.node")); console.log("process.cwd():"); console.log(process.cwd()); console.log("__dirname: "); console.log(__dirname); var args = process.argv.slice(2); console.log("args:"); console.log(args); if (!args[0]) { console.log("FILEPATH ARGUMENT IS MISSING."); process.exit(1); } var argPath = args[0].trim(); var filePath = argPath; console.log(filePath); if (!(0, UrlUtils_1.isHTTP)(filePath)) { if (!fs.existsSync(filePath)) { filePath = path.join(__dirname, argPath); console.log(filePath); if (!fs.existsSync(filePath)) { filePath = path.join(process.cwd(), argPath); console.log(filePath); if (!fs.existsSync(filePath)) { console.log("FILEPATH DOES NOT EXIST."); process.exit(1); } } } var stats = fs.lstatSync(filePath); if (!stats.isFile() && !stats.isDirectory()) { console.log("FILEPATH MUST BE FILE OR DIRECTORY."); process.exit(1); } } var fileName = filePath; if ((0, UrlUtils_1.isHTTP)(filePath)) { var url = new url_1.URL(filePath); fileName = url.pathname; } fileName = fileName.replace(/META-INF[\/|\\]container.xml$/, ""); fileName = path.basename(fileName); var generateDaisyAudioManifestOnly = false; var decryptKeys; if (args[2]) { if (args[2] === "generate-daisy-audio-manifest-only") { generateDaisyAudioManifestOnly = true; } else { decryptKeys = args[2].trim().split(";"); } } var outputDirPath; if (args[1]) { var argDir = args[1].trim(); var dirPath = argDir; console.log(dirPath); if (!fs.existsSync(dirPath)) { dirPath = path.join(__dirname, argDir); console.log(dirPath); if (!fs.existsSync(dirPath)) { dirPath = path.join(process.cwd(), argDir); console.log(dirPath); if (!fs.existsSync(dirPath)) { console.log("DIRPATH DOES NOT EXIST."); process.exit(1); } else { if (!fs.lstatSync(dirPath).isDirectory()) { console.log("DIRPATH MUST BE DIRECTORY."); process.exit(1); } } } } dirPath = fs.realpathSync(dirPath); if (generateDaisyAudioManifestOnly) { outputDirPath = dirPath; console.log(outputDirPath); } else { var fileNameNoExt = fileName + "_R2_EXTRACTED"; console.log(fileNameNoExt); outputDirPath = path.join(dirPath, fileNameNoExt); console.log(outputDirPath); if (fs.existsSync(outputDirPath)) { console.log("OUTPUT FOLDER ALREADY EXISTS!"); process.exit(1); } } } (function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { var publication, err_1, isAnEPUB, isAnAudioBook, _err_1, isDaisyBook, _err_2, isFullTextAudio, err_2, err_3; var _a, _b; return tslib_1.__generator(this, function (_c) { switch (_c.label) { case 0: _c.trys.push([0, 2, , 3]); return [4, (0, publication_parser_1.PublicationParsePromise)(filePath)]; case 1: publication = _c.sent(); return [3, 3]; case 2: err_1 = _c.sent(); console.log("== Publication Parser: reject"); console.log(err_1); return [2]; case 3: isAnEPUB = (0, epub_1.isEPUBlication)(filePath); _c.label = 4; case 4: _c.trys.push([4, 6, , 7]); return [4, (0, audiobook_1.isAudioBookPublication)(filePath)]; case 5: isAnAudioBook = _c.sent(); return [3, 7]; case 6: _err_1 = _c.sent(); return [3, 7]; case 7: _c.trys.push([7, 9, , 10]); return [4, (0, daisy_1.isDaisyPublication)(filePath)]; case 8: isDaisyBook = _c.sent(); return [3, 10]; case 9: _err_2 = _c.sent(); return [3, 10]; case 10: if (!((isDaisyBook || isAnAudioBook || isAnEPUB) && outputDirPath)) return [3, 24]; _c.label = 11; case 11: _c.trys.push([11, 22, , 23]); if (!isDaisyBook) return [3, 19]; return [4, (0, daisy_convert_to_epub_1.convertDaisyToReadiumWebPub)(outputDirPath, publication, generateDaisyAudioManifestOnly ? fileName : undefined)]; case 12: _c.sent(); isFullTextAudio = ((_a = publication.Metadata) === null || _a === void 0 ? void 0 : _a.AdditionalJSON) && (publication.Metadata.AdditionalJSON["dtb:multimediaType"] === "audioFullText" || publication.Metadata.AdditionalJSON["ncc:multimediaType"] === "audioFullText" || (!publication.Metadata.AdditionalJSON["dtb:multimediaType"] && !publication.Metadata.AdditionalJSON["ncc:multimediaType"])); if (!(isFullTextAudio && !((_b = publication.Spine) === null || _b === void 0 ? void 0 : _b.length))) return [3, 18]; console.log("%%%%% FAILED audio+text DAISY convert, trying again as audio-only ..."); publication.freeDestroy(); _c.label = 13; case 13: _c.trys.push([13, 15, , 16]); return [4, (0, publication_parser_1.PublicationParsePromise)(filePath)]; case 14: publication = _c.sent(); return [3, 16]; case 15: err_2 = _c.sent(); console.log("== Publication Parser: reject"); console.log(err_2); return [2]; case 16: return [4, new Promise(function (reso) { setTimeout(function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { var _a; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: _a = reso; return [4, (0, daisy_convert_to_epub_1.convertDaisyToReadiumWebPub)(outputDirPath, publication, generateDaisyAudioManifestOnly ? fileName : undefined, true)]; case 1: _a.apply(void 0, [_b.sent()]); return [2]; } }); }); }, 500); })]; case 17: _c.sent(); _c.label = 18; case 18: return [3, 21]; case 19: return [4, extractEPUB((isAnEPUB || isDaisyBook) ? true : false, publication, outputDirPath, decryptKeys)]; case 20: _c.sent(); _c.label = 21; case 21: return [3, 23]; case 22: err_3 = _c.sent(); console.log("== Publication extract FAIL"); console.log(err_3); return [2]; case 23: return [3, 26]; case 24: return [4, dumpPublication(publication)]; case 25: _c.sent(); _c.label = 26; case 26: return [2]; } }); }); })(); function extractEPUB_ManifestJSON(pub, outDir, keys) { var manifestJson = (0, serializable_1.TaJsonSerialize)(pub); var arrLinks = []; if (manifestJson.readingOrder) { arrLinks.push.apply(arrLinks, manifestJson.readingOrder); } if (manifestJson.resources) { arrLinks.push.apply(arrLinks, manifestJson.resources); } if (keys) { arrLinks.forEach(function (link) { if (link.properties && link.properties.encrypted && link.properties.encrypted.scheme === "http://readium.org/2014/01/lcp") { delete link.properties.encrypted; var atLeastOne_1 = false; var jsonProps = Object.keys(link.properties); if (jsonProps) { jsonProps.forEach(function (jsonProp) { if (link.properties.hasOwnProperty(jsonProp)) { atLeastOne_1 = true; return false; } return true; }); } if (!atLeastOne_1) { delete link.properties; } } }); if (manifestJson.links) { var lks = manifestJson.links; var index = -1; for (var i = 0; i < lks.length; i++) { var link = lks[i]; if (link.type === "application/vnd.readium.lcp.license.v1.0+json" && link.rel === "license") { index = i; break; } } if (index >= 0) { lks.splice(index, 1); } if (lks.length === 0) { delete manifestJson.links; } } } arrLinks.forEach(function (link) { if (link.properties && link.properties.encrypted && (link.properties.encrypted.algorithm === "http://www.idpf.org/2008/embedding" || link.properties.encrypted.algorithm === "http://ns.adobe.com/pdf/enc#RC")) { delete link.properties.encrypted; var atLeastOne_2 = false; var jsonProps = Object.keys(link.properties); if (jsonProps) { jsonProps.forEach(function (jsonProp) { if (link.properties.hasOwnProperty(jsonProp)) { atLeastOne_2 = true; return false; } return true; }); } if (!atLeastOne_2) { delete link.properties; } } }); var manifestJsonStr = JSON.stringify(manifestJson, null, " "); var manifestJsonPath = path.join(outDir, "manifest.json"); fs.writeFileSync(manifestJsonPath, manifestJsonStr, "utf8"); } function extractEPUB_Check(zip, outDir) { return tslib_1.__awaiter(this, void 0, void 0, function () { var zipEntries, err_4, _i, zipEntries_1, zipEntry, expectedOutputPath; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4, zip.getEntries()]; case 1: zipEntries = _a.sent(); return [3, 3]; case 2: err_4 = _a.sent(); console.log(err_4); return [3, 3]; case 3: if (zipEntries) { for (_i = 0, zipEntries_1 = zipEntries; _i < zipEntries_1.length; _i++) { zipEntry = zipEntries_1[_i]; if (zipEntry !== "mimetype" && !zipEntry.startsWith("META-INF/") && !/\.opf$/i.test(zipEntry) && !/ncc\.html$/i.test(zipEntry) && zipEntry !== "publication.json" && zipEntry !== "license.lcpl" && !zipEntry.endsWith(".DS_Store") && !zipEntry.startsWith("__MACOSX/")) { expectedOutputPath = path.join(outDir, zipEntry); if (!fs.existsSync(expectedOutputPath)) { console.log("Zip entry not extracted??"); console.log(expectedOutputPath); } } } } return [2]; } }); }); } function extractEPUB_ProcessKeys(pub, keys) { return tslib_1.__awaiter(this, void 0, void 0, function () { var keysSha256Hex, err_5; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: if (!pub.LCP || !keys) { return [2]; } keysSha256Hex = keys.map(function (key) { console.log("@@@"); console.log(key); if (key.length === 64) { var isHex = true; for (var i = 0; i < key.length; i += 2) { var hexByte = key.substr(i, 2).toLowerCase(); var parsedInt = parseInt(hexByte, 16); if (isNaN(parsedInt)) { isHex = false; break; } } if (isHex) { return key; } } var checkSum = crypto.createHash("sha256"); checkSum.update(key); var keySha256Hex = checkSum.digest("hex"); console.log(keySha256Hex); return keySha256Hex; }); _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4, pub.LCP.tryUserKeys(keysSha256Hex)]; case 2: _a.sent(); return [3, 4]; case 3: err_5 = _a.sent(); console.log(err_5); throw Error("FAIL publication.LCP.tryUserKeys()"); case 4: return [2]; } }); }); } function extractEPUB_Link(pub, zip, outDir, link) { return tslib_1.__awaiter(this, void 0, void 0, function () { var hrefDecoded, has, zipEntries, _i, zipEntries_2, zipEntry, zipStream_, err_6, transformedStream, err_7, zipData, err_8, linkOutputPath; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: hrefDecoded = link.HrefDecoded; console.log("===== " + hrefDecoded); if (!hrefDecoded) { console.log("!?link.HrefDecoded"); return [2]; } return [4, (0, zipHasEntry_1.zipHasEntry)(zip, hrefDecoded, link.Href)]; case 1: has = _a.sent(); if (!!has) return [3, 3]; console.log("NOT IN ZIP (extractEPUB_Link): ".concat(link.Href, " --- ").concat(hrefDecoded)); return [4, zip.getEntries()]; case 2: zipEntries = _a.sent(); for (_i = 0, zipEntries_2 = zipEntries; _i < zipEntries_2.length; _i++) { zipEntry = zipEntries_2[_i]; if (zipEntry.startsWith("__MACOSX/")) { continue; } console.log(zipEntry); } return [2]; case 3: _a.trys.push([3, 5, , 6]); return [4, zip.entryStreamPromise(hrefDecoded)]; case 4: zipStream_ = _a.sent(); return [3, 6]; case 5: err_6 = _a.sent(); console.log(hrefDecoded); console.log(err_6); return [2]; case 6: _a.trys.push([6, 8, , 9]); return [4, transformer_1.Transformers.tryStream(pub, link, undefined, zipStream_, false, 0, 0, undefined)]; case 7: transformedStream = _a.sent(); return [3, 9]; case 8: err_7 = _a.sent(); console.log(hrefDecoded); console.log(err_7); return [2]; case 9: zipStream_ = transformedStream; _a.label = 10; case 10: _a.trys.push([10, 12, , 13]); return [4, (0, BufferUtils_1.streamToBufferPromise)(zipStream_.stream)]; case 11: zipData = _a.sent(); return [3, 13]; case 12: err_8 = _a.sent(); console.log(hrefDecoded); console.log(err_8); return [2]; case 13: linkOutputPath = path.join(outDir, hrefDecoded); ensureDirs(linkOutputPath); fs.writeFileSync(linkOutputPath, zipData); return [2]; } }); }); } function extractEPUB(isEPUB, pub, outDir, keys) { return tslib_1.__awaiter(this, void 0, void 0, function () { var zipInternal, zip, err_9, err_10, links, lic, has, l, _i, links_1, link, err_11, err_12; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: zipInternal = pub.findFromInternal("zip"); if (!zipInternal) { console.log("No publication zip!?"); return [2]; } zip = zipInternal.Value; _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4, extractEPUB_ProcessKeys(pub, keys)]; case 2: _a.sent(); return [3, 4]; case 3: err_9 = _a.sent(); console.log(err_9); throw err_9; case 4: ensureDirs(path.join(outDir, "DUMMY_FILE.EXT")); _a.label = 5; case 5: _a.trys.push([5, 7, , 8]); return [4, extractEPUB_MediaOverlays(pub, zip, outDir)]; case 6: _a.sent(); return [3, 8]; case 7: err_10 = _a.sent(); console.log(err_10); return [3, 8]; case 8: extractEPUB_ManifestJSON(pub, outDir, keys); links = []; if (pub.Resources) { links.push.apply(links, pub.Resources); } if (pub.Spine) { links.push.apply(links, pub.Spine); } if (!!keys) return [3, 10]; lic = (isEPUB ? "META-INF/" : "") + "license.lcpl"; return [4, (0, zipHasEntry_1.zipHasEntry)(zip, lic, undefined)]; case 9: has = _a.sent(); if (has) { l = new publication_link_1.Link(); l.setHrefDecoded(lic); links.push(l); } _a.label = 10; case 10: _i = 0, links_1 = links; _a.label = 11; case 11: if (!(_i < links_1.length)) return [3, 16]; link = links_1[_i]; _a.label = 12; case 12: _a.trys.push([12, 14, , 15]); return [4, extractEPUB_Link(pub, zip, outDir, link)]; case 13: _a.sent(); return [3, 15]; case 14: err_11 = _a.sent(); console.log(err_11); return [3, 15]; case 15: _i++; return [3, 11]; case 16: _a.trys.push([16, 18, , 19]); return [4, extractEPUB_Check(zip, outDir)]; case 17: _a.sent(); return [3, 19]; case 18: err_12 = _a.sent(); console.log(err_12); return [3, 19]; case 19: return [2]; } }); }); } function extractEPUB_MediaOverlays(pub, _zip, outDir) { return tslib_1.__awaiter(this, void 0, void 0, function () { var i, _i, _a, spineItem, mo, err_13, moJsonObj, moJsonStr, p, moJsonPath, _b, _c, altLink; return tslib_1.__generator(this, function (_d) { switch (_d.label) { case 0: if (!pub.Spine) { return [2]; } i = -1; _i = 0, _a = pub.Spine; _d.label = 1; case 1: if (!(_i < _a.length)) return [3, 7]; spineItem = _a[_i]; if (!spineItem.MediaOverlays) return [3, 6]; mo = spineItem.MediaOverlays; _d.label = 2; case 2: _d.trys.push([2, 4, , 5]); return [4, (0, epub_daisy_common_1.lazyLoadMediaOverlays)(pub, mo)]; case 3: _d.sent(); return [3, 5]; case 4: err_13 = _d.sent(); return [2, Promise.reject(err_13)]; case 5: moJsonObj = (0, serializable_1.TaJsonSerialize)(mo); moJsonStr = global.JSON.stringify(moJsonObj, null, " "); i++; p = "media-overlays_".concat(i, ".json"); moJsonPath = path.join(outDir, p); fs.writeFileSync(moJsonPath, moJsonStr, "utf8"); if (spineItem.Properties && spineItem.Properties.MediaOverlay) { spineItem.Properties.MediaOverlay = p; } if (spineItem.Alternate) { for (_b = 0, _c = spineItem.Alternate; _b < _c.length; _b++) { altLink = _c[_b]; if (altLink.TypeLink === "application/vnd.syncnarr+json") { altLink.Href = p; } } } _d.label = 6; case 6: _i++; return [3, 1]; case 7: return [2]; } }); }); } function ensureDirs(fspath) { var dirname = path.dirname(fspath); if (!fs.existsSync(dirname)) { ensureDirs(dirname); fs.mkdirSync(dirname); } } function dumpPublication(publication) { return tslib_1.__awaiter(this, void 0, void 0, function () { var publicationJsonObj, publicationJsonStr, publicationReverse, publicationJsonObjReverse, eq, _i, _a, spineItem, _b, _c, altLink, mo, err_14, moJsonObj, moJsonStr, moReverse, moJsonObjReverse, equa; return tslib_1.__generator(this, function (_d) { switch (_d.label) { case 0: console.log("#### RAW OBJECT:"); console.log(util.inspect(publication, { showHidden: false, depth: 1000, colors: true, customInspect: true })); publicationJsonObj = (0, serializable_1.TaJsonSerialize)(publication); console.log(util.inspect(publicationJsonObj, { showHidden: false, depth: 1000, colors: true, customInspect: true })); publicationJsonStr = global.JSON.stringify(publicationJsonObj, null, " "); publicationReverse = (0, serializable_1.TaJsonDeserialize)(publicationJsonObj, publication_1.Publication); publicationJsonObjReverse = (0, serializable_1.TaJsonSerialize)(publicationReverse); eq = deepEqual(publicationJsonObj, publicationJsonObjReverse); if (!eq) { console.log("#### TA-JSON SERIALIZED JSON OBJ:"); console.log(publicationJsonObj); console.log("#### STRINGIFIED JSON OBJ:"); console.log(publicationJsonStr); console.log("#### TA-JSON DESERIALIZED (REVERSE):"); console.log(util.inspect(publicationReverse, { showHidden: false, depth: 1000, colors: true, customInspect: true })); console.log("#### TA-JSON SERIALIZED JSON OBJ (REVERSE):"); console.log(publicationJsonObjReverse); console.log("#### REVERSE NOT DEEP EQUAL!\n\n"); console.log("#### REVERSE NOT DEEP EQUAL!\n\n"); console.log("#### REVERSE NOT DEEP EQUAL!\n\n"); } console.log(jsonDiff.diffString(publicationJsonObj, publicationJsonObjReverse)); if (!publication.Spine) return [3, 7]; _i = 0, _a = publication.Spine; _d.label = 1; case 1: if (!(_i < _a.length)) return [3, 7]; spineItem = _a[_i]; if (spineItem.Properties && spineItem.Properties.MediaOverlay) { console.log(spineItem.Href); console.log(spineItem.Properties.MediaOverlay); console.log(spineItem.Duration); } if (spineItem.Alternate) { for (_b = 0, _c = spineItem.Alternate; _b < _c.length; _b++) { altLink = _c[_b]; if (altLink.TypeLink === "application/vnd.syncnarr+json") { console.log(altLink.Href); console.log(altLink.TypeLink); console.log(altLink.Duration); } } } if (!spineItem.MediaOverlays) return [3, 6]; mo = spineItem.MediaOverlays; if (!mo.initialized) { console.log(util.inspect(mo, { showHidden: false, depth: 1000, colors: true, customInspect: true })); } console.log(mo.SmilPathInZip); _d.label = 2; case 2: _d.trys.push([2, 4, , 5]); return [4, (0, epub_daisy_common_1.lazyLoadMediaOverlays)(publication, mo)]; case 3: _d.sent(); return [3, 5]; case 4: err_14 = _d.sent(); return [2, Promise.reject(err_14)]; case 5: moJsonObj = (0, serializable_1.TaJsonSerialize)(mo); moJsonStr = global.JSON.stringify(moJsonObj, null, " "); console.log(moJsonStr.substr(0, 1000) + "\n...\n"); moReverse = (0, serializable_1.TaJsonDeserialize)(moJsonObj, media_overlay_1.MediaOverlayNode); moJsonObjReverse = (0, serializable_1.TaJsonSerialize)(moReverse); equa = deepEqual(moJsonObj, moJsonObjReverse); if (!equa) { console.log("#### TA-JSON SERIALIZED JSON OBJ:"); console.log(moJsonObj); console.log("#### STRINGIFIED JSON OBJ:"); console.log(moJsonStr); console.log("#### TA-JSON DESERIALIZED (REVERSE):"); console.log(util.inspect(moReverse, { showHidden: false, depth: 1000, colors: true, customInspect: true })); console.log("#### TA-JSON SERIALIZED JSON OBJ (REVERSE):"); console.log(moJsonObjReverse); console.log("#### REVERSE NOT DEEP EQUAL!\n\n"); console.log("#### REVERSE NOT DEEP EQUAL!\n\n"); console.log("#### REVERSE NOT DEEP EQUAL!\n\n"); } console.log(jsonDiff.diffString(moJsonObj, moJsonObjReverse)); _d.label = 6; case 6: _i++; return [3, 1]; case 7: return [2]; } }); }); } //# sourceMappingURL=cli.js.map