r2-shared-js
Version:
Readium 2 'shared' for NodeJS (TypeScript)
1,019 lines • 43.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EPUBis = exports.addCoverDimensions = exports.mediaOverlayURLParam = exports.mediaOverlayURLPath = exports.BCP47_UNKNOWN_LANG = void 0;
exports.isEPUBlication = isEPUBlication;
exports.EpubParsePromise = EpubParsePromise;
exports.getAllMediaOverlays = getAllMediaOverlays;
exports.getMediaOverlay = getMediaOverlay;
const debug_ = require("debug");
const fs = require("fs");
const image_size_1 = require("image-size");
const path = require("path");
const url_1 = require("url");
const xmldom = require("@xmldom/xmldom");
const xpath = require("xpath");
const media_overlay_1 = require("../models/media-overlay");
const metadata_1 = require("../models/metadata");
const metadata_belongsto_1 = require("../models/metadata-belongsto");
const metadata_contributor_1 = require("../models/metadata-contributor");
const metadata_properties_1 = require("../models/metadata-properties");
const publication_1 = require("../models/publication");
const publication_link_1 = require("../models/publication-link");
const metadata_encrypted_1 = require("r2-lcp-js/dist/es8-es2017/src/models/metadata-encrypted");
const lcp_1 = require("r2-lcp-js/dist/es8-es2017/src/parser/epub/lcp");
const serializable_1 = require("r2-lcp-js/dist/es8-es2017/src/serializable");
const UrlUtils_1 = require("r2-utils-js/dist/es8-es2017/src/_utils/http/UrlUtils");
const BufferUtils_1 = require("r2-utils-js/dist/es8-es2017/src/_utils/stream/BufferUtils");
const xml_js_mapper_1 = require("r2-utils-js/dist/es8-es2017/src/_utils/xml-js-mapper");
const zipFactory_1 = require("r2-utils-js/dist/es8-es2017/src/_utils/zip/zipFactory");
const bom_1 = require("r2-utils-js/dist/es8-es2017/src/_utils/bom");
const decodeURI_1 = require("../_utils/decodeURI");
const zipHasEntry_1 = require("../_utils/zipHasEntry");
const epub_daisy_common_1 = require("./epub-daisy-common");
const container_1 = require("./epub/container");
const display_options_1 = require("./epub/display-options");
const encryption_1 = require("./epub/encryption");
const debug = debug_("r2:shared#parser/epub");
exports.BCP47_UNKNOWN_LANG = epub_daisy_common_1.BCP47_UNKNOWN_LANG;
exports.mediaOverlayURLPath = epub_daisy_common_1.mediaOverlayURLPath;
exports.mediaOverlayURLParam = epub_daisy_common_1.mediaOverlayURLParam;
const addCoverDimensions = async (publication, coverLink) => {
const zipInternal = publication.findFromInternal("zip");
if (zipInternal) {
const zip = zipInternal.Value;
const coverLinkHrefDecoded = coverLink.HrefDecoded;
if (!coverLinkHrefDecoded) {
return;
}
const has = await (0, zipHasEntry_1.zipHasEntry)(zip, coverLinkHrefDecoded, coverLink.Href);
if (!has) {
debug(`NOT IN ZIP (addCoverDimensions): ${coverLink.Href} --- ${coverLinkHrefDecoded}`);
const zipEntries = await zip.getEntries();
for (const zipEntry of zipEntries) {
if (zipEntry.startsWith("__MACOSX/")) {
continue;
}
debug(zipEntry);
}
return;
}
let zipStream;
try {
zipStream = await zip.entryStreamPromise(coverLinkHrefDecoded);
}
catch (err) {
debug(coverLinkHrefDecoded);
debug(coverLink.TypeLink);
debug(err);
return;
}
let zipData;
try {
zipData = await (0, BufferUtils_1.streamToBufferPromise)(zipStream.stream);
const imageInfo = (0, image_size_1.imageSize)(zipData);
if (imageInfo && imageInfo.width && imageInfo.height) {
coverLink.Width = imageInfo.width;
coverLink.Height = imageInfo.height;
if (coverLink.TypeLink &&
coverLink.TypeLink.replace("jpeg", "jpg").replace("+xml", "")
!== ("image/" + imageInfo.type)) {
debug(`Wrong image type? ${coverLink.TypeLink} -- ${imageInfo.type}`);
}
}
}
catch (err) {
debug(coverLinkHrefDecoded);
debug(coverLink.TypeLink);
debug(err);
}
}
};
exports.addCoverDimensions = addCoverDimensions;
var EPUBis;
(function (EPUBis) {
EPUBis["LocalExploded"] = "LocalExploded";
EPUBis["LocalPacked"] = "LocalPacked";
EPUBis["RemoteExploded"] = "RemoteExploded";
EPUBis["RemotePacked"] = "RemotePacked";
})(EPUBis || (exports.EPUBis = EPUBis = {}));
function isEPUBlication(urlOrPath) {
let p = urlOrPath;
const http = (0, UrlUtils_1.isHTTP)(urlOrPath);
if (http) {
const url = new url_1.URL(urlOrPath);
p = url.pathname;
}
else if (fs.existsSync(path.join(urlOrPath, "META-INF", "container.xml"))) {
return EPUBis.LocalExploded;
}
const fileName = path.basename(p);
const ext = path.extname(fileName);
const epub = /\.epub3?$/i.test(ext);
if (epub) {
return http ? EPUBis.RemotePacked : EPUBis.LocalPacked;
}
if (/META-INF[\/|\\]container.xml$/.test(p)) {
return http ? EPUBis.RemoteExploded : EPUBis.LocalExploded;
}
return undefined;
}
async function EpubParsePromise(filePath) {
const isAnEPUB = isEPUBlication(filePath);
let filePathToLoad = filePath;
if (isAnEPUB === EPUBis.LocalExploded) {
filePathToLoad = filePathToLoad.replace(/META-INF[\/|\\]container.xml$/, "");
}
else if (isAnEPUB === EPUBis.RemoteExploded) {
const url = new url_1.URL(filePathToLoad);
url.pathname = url.pathname.replace(/META-INF[\/|\\]container.xml$/, "");
filePathToLoad = url.toString();
}
let zip;
try {
zip = await (0, zipFactory_1.zipLoadPromise)(filePathToLoad);
}
catch (err) {
debug(err);
return Promise.reject(err);
}
if (!zip.hasEntries()) {
return Promise.reject("EPUB zip empty");
}
const publication = new publication_1.Publication();
publication.Context = ["https://readium.org/webpub-manifest/context.jsonld"];
publication.Metadata = new metadata_1.Metadata();
publication.Metadata.RDFType = "http://schema.org/Book";
publication.AddToInternal("filename", path.basename(filePath));
publication.AddToInternal("type", "epub");
publication.AddToInternal("zip", zip);
let lcpl;
const lcplZipPath = "META-INF/license.lcpl";
let has = await (0, zipHasEntry_1.zipHasEntry)(zip, lcplZipPath, undefined);
if (has) {
let lcplZipStream_;
try {
lcplZipStream_ = await zip.entryStreamPromise(lcplZipPath);
}
catch (err) {
debug(err);
return Promise.reject(err);
}
const lcplZipStream = lcplZipStream_.stream;
let lcplZipData;
try {
lcplZipData = await (0, BufferUtils_1.streamToBufferPromise)(lcplZipStream);
}
catch (err) {
debug(err);
return Promise.reject(err);
}
const lcplStr = lcplZipData.toString("utf8");
const lcplJson = global.JSON.parse(lcplStr);
lcpl = (0, serializable_1.TaJsonDeserialize)(lcplJson, lcp_1.LCP);
lcpl.ZipPath = lcplZipPath;
lcpl.JsonSource = lcplStr;
lcpl.init();
publication.LCP = lcpl;
const mime = "application/vnd.readium.lcp.license.v1.0+json";
publication.AddLink(mime, ["license"], lcpl.ZipPath, undefined);
}
let encryption;
const encZipPath = "META-INF/encryption.xml";
has = await (0, zipHasEntry_1.zipHasEntry)(zip, encZipPath, undefined);
if (has) {
let encryptionXmlZipStream_;
try {
encryptionXmlZipStream_ = await zip.entryStreamPromise(encZipPath);
}
catch (err) {
debug(err);
return Promise.reject(err);
}
const encryptionXmlZipStream = encryptionXmlZipStream_.stream;
let encryptionXmlZipData;
try {
encryptionXmlZipData = await (0, BufferUtils_1.streamToBufferPromise)(encryptionXmlZipStream);
}
catch (err) {
debug(err);
return Promise.reject(err);
}
const encryptionXmlStr = (0, bom_1.removeUTF8BOM)(encryptionXmlZipData.toString("utf8"));
const encryptionXmlDoc = new xmldom.DOMParser().parseFromString(encryptionXmlStr, "application/xml");
encryption = xml_js_mapper_1.XML.deserialize(encryptionXmlDoc, encryption_1.Encryption);
encryption.ZipPath = encZipPath;
}
const containerZipPath = "META-INF/container.xml";
let containerXmlZipStream_;
try {
containerXmlZipStream_ = await zip.entryStreamPromise(containerZipPath);
}
catch (err) {
debug(err);
return Promise.reject(err);
}
const containerXmlZipStream = containerXmlZipStream_.stream;
let containerXmlZipData;
try {
containerXmlZipData = await (0, BufferUtils_1.streamToBufferPromise)(containerXmlZipStream);
}
catch (err) {
debug(err);
return Promise.reject(err);
}
const containerXmlStr = (0, bom_1.removeUTF8BOM)(containerXmlZipData.toString("utf8"));
const containerXmlDoc = new xmldom.DOMParser().parseFromString(containerXmlStr, "application/xml");
const container = xml_js_mapper_1.XML.deserialize(containerXmlDoc, container_1.Container);
container.ZipPath = containerZipPath;
const rootfile = container.Rootfile[0];
const rootfilePathDecoded = rootfile.PathDecoded;
if (!rootfilePathDecoded) {
return Promise.reject("?!rootfile.PathDecoded");
}
const opf = await (0, epub_daisy_common_1.getOpf)(zip, rootfilePathDecoded, rootfile.Path);
(0, epub_daisy_common_1.addLanguage)(publication, opf);
(0, epub_daisy_common_1.addTitle)(publication, rootfile, opf);
(0, epub_daisy_common_1.addIdentifier)(publication, opf);
(0, epub_daisy_common_1.addOtherMetadata)(publication, rootfile, opf);
(0, epub_daisy_common_1.setPublicationDirection)(publication, opf);
(0, epub_daisy_common_1.findContributorInMeta)(publication, rootfile, opf);
await addRendition(publication, opf, zip);
await (0, epub_daisy_common_1.fillSpineAndResource)(publication, rootfile, opf, zip, addLinkData);
await addCoverRel(publication, rootfile, opf, zip);
if (encryption) {
fillEncryptionInfo(publication, encryption, lcpl);
}
try {
await fillTOCFromNavDoc(publication, zip);
}
catch (ex) {
publication.TOC = [];
console.log(ex);
}
if (!publication.TOC || !publication.TOC.length) {
let ncx;
if (opf.Manifest && opf.Spine.Toc) {
const ncxManItem = opf.Manifest.find((manifestItem) => {
return manifestItem.ID === opf.Spine.Toc;
});
if (ncxManItem) {
ncx = await (0, epub_daisy_common_1.getNcx)(ncxManItem, opf, zip);
}
}
(0, epub_daisy_common_1.fillTOC)(publication, opf, ncx);
}
if (!publication.PageList && publication.Resources) {
const pageMapLink = publication.Resources.find((item) => {
return item.TypeLink === "application/oebps-page-map+xml";
});
if (pageMapLink) {
await fillPageListFromAdobePageMap(publication, zip, pageMapLink);
}
}
fillCalibreSerieInfo(publication, opf);
(0, epub_daisy_common_1.fillSubject)(publication, opf);
(0, epub_daisy_common_1.fillPublicationDate)(publication, rootfile, opf);
return publication;
}
async function getAllMediaOverlays(publication) {
const mos = [];
const links = [].
concat(publication.Spine ? publication.Spine : []).
concat(publication.Resources ? publication.Resources : []);
for (const link of links) {
if (link.MediaOverlays) {
const mo = link.MediaOverlays;
if (!mo.initialized) {
try {
await (0, epub_daisy_common_1.lazyLoadMediaOverlays)(publication, mo);
}
catch (err) {
return Promise.reject(err);
}
}
mos.push(mo);
}
}
return Promise.resolve(mos);
}
async function getMediaOverlay(publication, spineHref) {
const links = [].
concat(publication.Spine ? publication.Spine : []).
concat(publication.Resources ? publication.Resources : []);
for (const link of links) {
if (link.MediaOverlays && link.Href.indexOf(spineHref) >= 0) {
const mo = link.MediaOverlays;
if (!mo.initialized) {
try {
await (0, epub_daisy_common_1.lazyLoadMediaOverlays)(publication, mo);
}
catch (err) {
return Promise.reject(err);
}
}
return Promise.resolve(mo);
}
}
return Promise.reject(`No Media Overlays ${spineHref}`);
}
const addRelAndPropertiesToLink = async (publication, link, linkEpub, opf) => {
if (linkEpub.Properties) {
await addToLinkFromProperties(publication, link, linkEpub.Properties);
}
const spineProperties = findPropertiesInSpineForManifest(linkEpub, opf);
if (spineProperties) {
await addToLinkFromProperties(publication, link, spineProperties);
}
};
const addToLinkFromProperties = async (publication, link, propertiesString) => {
const properties = (0, epub_daisy_common_1.parseSpaceSeparatedString)(propertiesString);
const propertiesStruct = new metadata_properties_1.Properties();
for (const p of properties) {
switch (p) {
case "cover-image": {
link.AddRel("cover");
await (0, exports.addCoverDimensions)(publication, link);
break;
}
case "nav": {
link.AddRel("contents");
break;
}
case "scripted": {
if (!propertiesStruct.Contains) {
propertiesStruct.Contains = [];
}
propertiesStruct.Contains.push("js");
break;
}
case "mathml": {
if (!propertiesStruct.Contains) {
propertiesStruct.Contains = [];
}
propertiesStruct.Contains.push("mathml");
break;
}
case "onix-record": {
if (!propertiesStruct.Contains) {
propertiesStruct.Contains = [];
}
propertiesStruct.Contains.push("onix");
break;
}
case "svg": {
if (!propertiesStruct.Contains) {
propertiesStruct.Contains = [];
}
propertiesStruct.Contains.push("svg");
break;
}
case "xmp-record": {
if (!propertiesStruct.Contains) {
propertiesStruct.Contains = [];
}
propertiesStruct.Contains.push("xmp");
break;
}
case "remote-resources": {
if (!propertiesStruct.Contains) {
propertiesStruct.Contains = [];
}
propertiesStruct.Contains.push("remote-resources");
break;
}
case "rendition:page-spread-left": {
propertiesStruct.Page = metadata_properties_1.PageEnum.Left;
break;
}
case "page-spread-left": {
propertiesStruct.Page = metadata_properties_1.PageEnum.Left;
break;
}
case "rendition:page-spread-right": {
propertiesStruct.Page = metadata_properties_1.PageEnum.Right;
break;
}
case "page-spread-right": {
propertiesStruct.Page = metadata_properties_1.PageEnum.Right;
break;
}
case "rendition:page-spread-center": {
propertiesStruct.Page = metadata_properties_1.PageEnum.Center;
break;
}
case "page-spread-center": {
propertiesStruct.Page = metadata_properties_1.PageEnum.Center;
break;
}
case "rendition:spread-none": {
propertiesStruct.Spread = metadata_properties_1.SpreadEnum.None;
break;
}
case "rendition:spread-auto": {
propertiesStruct.Spread = metadata_properties_1.SpreadEnum.Auto;
break;
}
case "rendition:spread-landscape": {
propertiesStruct.Spread = metadata_properties_1.SpreadEnum.Landscape;
break;
}
case "rendition:spread-portrait": {
propertiesStruct.Spread = metadata_properties_1.SpreadEnum.Both;
break;
}
case "rendition:spread-both": {
propertiesStruct.Spread = metadata_properties_1.SpreadEnum.Both;
break;
}
case "rendition:layout-reflowable": {
propertiesStruct.Layout = metadata_properties_1.LayoutEnum.Reflowable;
break;
}
case "rendition:layout-pre-paginated": {
propertiesStruct.Layout = metadata_properties_1.LayoutEnum.Fixed;
break;
}
case "rendition:orientation-auto": {
propertiesStruct.Orientation = metadata_properties_1.OrientationEnum.Auto;
break;
}
case "rendition:orientation-landscape": {
propertiesStruct.Orientation = metadata_properties_1.OrientationEnum.Landscape;
break;
}
case "rendition:orientation-portrait": {
propertiesStruct.Orientation = metadata_properties_1.OrientationEnum.Portrait;
break;
}
case "rendition:flow-auto": {
propertiesStruct.Overflow = metadata_properties_1.OverflowEnum.Auto;
break;
}
case "rendition:flow-paginated": {
propertiesStruct.Overflow = metadata_properties_1.OverflowEnum.Paginated;
break;
}
case "rendition:flow-scrolled-continuous": {
propertiesStruct.Overflow = metadata_properties_1.OverflowEnum.ScrolledContinuous;
break;
}
case "rendition:flow-scrolled-doc": {
propertiesStruct.Overflow = metadata_properties_1.OverflowEnum.Scrolled;
break;
}
default: {
break;
}
}
if (propertiesStruct.Layout ||
propertiesStruct.Orientation ||
propertiesStruct.Overflow ||
propertiesStruct.Page ||
propertiesStruct.Spread ||
(propertiesStruct.Contains && propertiesStruct.Contains.length)) {
link.Properties = propertiesStruct;
}
}
};
const addMediaOverlay = async (link, linkEpub, opf, zip) => {
if (linkEpub.MediaOverlay) {
const meta = (0, epub_daisy_common_1.findMetaByRefineAndProperty)(opf, linkEpub.MediaOverlay, "media:duration");
if (meta) {
const dur = (0, media_overlay_1.timeStrToSeconds)(meta.Data);
if (dur !== 0) {
link.Duration = dur;
}
}
const manItemSmil = opf.Manifest.find((mi) => {
if (mi.ID === linkEpub.MediaOverlay) {
return true;
}
return false;
});
if (manItemSmil) {
await (0, epub_daisy_common_1.addMediaOverlaySMIL)(link, manItemSmil, opf, zip);
}
}
};
const addRendition = async (publication, opf, zip) => {
if (opf.Metadata && opf.Metadata.Meta && opf.Metadata.Meta.length) {
const rendition = new metadata_properties_1.Properties();
opf.Metadata.Meta.forEach((meta) => {
switch (meta.Property) {
case "rendition:layout": {
switch (meta.Data) {
case "pre-paginated": {
rendition.Layout = metadata_properties_1.LayoutEnum.Fixed;
break;
}
case "reflowable": {
rendition.Layout = metadata_properties_1.LayoutEnum.Reflowable;
break;
}
}
break;
}
case "rendition:orientation": {
switch (meta.Data) {
case "auto": {
rendition.Orientation = metadata_properties_1.OrientationEnum.Auto;
break;
}
case "landscape": {
rendition.Orientation = metadata_properties_1.OrientationEnum.Landscape;
break;
}
case "portrait": {
rendition.Orientation = metadata_properties_1.OrientationEnum.Portrait;
break;
}
}
break;
}
case "rendition:spread": {
switch (meta.Data) {
case "auto": {
rendition.Spread = metadata_properties_1.SpreadEnum.Auto;
break;
}
case "both": {
rendition.Spread = metadata_properties_1.SpreadEnum.Both;
break;
}
case "none": {
rendition.Spread = metadata_properties_1.SpreadEnum.None;
break;
}
case "landscape": {
rendition.Spread = metadata_properties_1.SpreadEnum.Landscape;
break;
}
case "portrait": {
rendition.Spread = metadata_properties_1.SpreadEnum.Both;
break;
}
}
break;
}
case "rendition:flow": {
switch (meta.Data) {
case "auto": {
rendition.Overflow = metadata_properties_1.OverflowEnum.Auto;
break;
}
case "paginated": {
rendition.Overflow = metadata_properties_1.OverflowEnum.Paginated;
break;
}
case "scrolled": {
rendition.Overflow = metadata_properties_1.OverflowEnum.Scrolled;
break;
}
case "scrolled-continuous": {
rendition.Overflow = metadata_properties_1.OverflowEnum.ScrolledContinuous;
break;
}
}
break;
}
default: {
break;
}
}
});
if (!rendition.Layout || !rendition.Orientation) {
let displayOptionsZipPath = "META-INF/com.apple.ibooks.display-options.xml";
let has = await (0, zipHasEntry_1.zipHasEntry)(zip, displayOptionsZipPath, undefined);
if (has) {
debug("Info: found iBooks display-options XML");
}
else {
displayOptionsZipPath = "META-INF/com.kobobooks.display-options.xml";
has = await (0, zipHasEntry_1.zipHasEntry)(zip, displayOptionsZipPath, undefined);
if (has) {
debug("Info: found Kobo display-options XML");
}
}
if (!has) {
debug("Info: not found iBooks or Kobo display-options XML");
}
else {
let displayOptionsZipStream_;
try {
displayOptionsZipStream_ = await zip.entryStreamPromise(displayOptionsZipPath);
}
catch (err) {
debug(err);
}
if (displayOptionsZipStream_) {
const displayOptionsZipStream = displayOptionsZipStream_.stream;
let displayOptionsZipData;
try {
displayOptionsZipData = await (0, BufferUtils_1.streamToBufferPromise)(displayOptionsZipStream);
}
catch (err) {
debug(err);
}
if (displayOptionsZipData) {
try {
const displayOptionsStr = (0, bom_1.removeUTF8BOM)(displayOptionsZipData.toString("utf8"));
const displayOptionsDoc = new xmldom.DOMParser().parseFromString(displayOptionsStr, "application/xml");
const displayOptions = xml_js_mapper_1.XML.deserialize(displayOptionsDoc, display_options_1.DisplayOptions);
displayOptions.ZipPath = displayOptionsZipPath;
if (displayOptions && displayOptions.Platforms) {
const renditionPlatformAll = new metadata_properties_1.Properties();
const renditionPlatformIpad = new metadata_properties_1.Properties();
const renditionPlatformIphone = new metadata_properties_1.Properties();
displayOptions.Platforms.forEach((platform) => {
if (platform.Options) {
platform.Options.forEach((option) => {
if (!rendition.Layout) {
if (option.Name === "fixed-layout") {
if (option.Value === "true") {
rendition.Layout = metadata_properties_1.LayoutEnum.Fixed;
}
else {
rendition.Layout = metadata_properties_1.LayoutEnum.Reflowable;
}
}
}
if (!rendition.Orientation) {
if (option.Name === "orientation-lock") {
const rend = platform.Name === "*" ? renditionPlatformAll :
(platform.Name === "ipad" ? renditionPlatformIpad :
(platform.Name === "iphone" ? renditionPlatformIphone :
renditionPlatformAll));
switch (option.Value) {
case "none": {
rend.Orientation = metadata_properties_1.OrientationEnum.Auto;
break;
}
case "landscape-only": {
rend.Orientation = metadata_properties_1.OrientationEnum.Landscape;
break;
}
case "portrait-only": {
rend.Orientation = metadata_properties_1.OrientationEnum.Portrait;
break;
}
default: {
rend.Orientation = metadata_properties_1.OrientationEnum.Auto;
break;
}
}
}
}
});
}
});
if (renditionPlatformAll.Orientation) {
rendition.Orientation = renditionPlatformAll.Orientation;
}
else if (renditionPlatformIpad.Orientation) {
rendition.Orientation = renditionPlatformIpad.Orientation;
}
else if (renditionPlatformIphone.Orientation) {
rendition.Orientation = renditionPlatformIphone.Orientation;
}
}
}
catch (err) {
debug(err);
}
}
}
}
}
if (rendition.Layout || rendition.Orientation || rendition.Overflow || rendition.Page || rendition.Spread) {
publication.Metadata.Rendition = rendition;
}
}
};
const addLinkData = async (publication, rootfile, opf, zip, linkItem, item) => {
if (rootfile) {
await addRelAndPropertiesToLink(publication, linkItem, item, opf);
}
await addMediaOverlay(linkItem, item, opf, zip);
};
const fillEncryptionInfo = (publication, encryption, lcp) => {
encryption.EncryptedData.forEach((encInfo) => {
const encrypted = new metadata_encrypted_1.Encrypted();
encrypted.Algorithm = encInfo.EncryptionMethod.Algorithm;
if (lcp &&
encrypted.Algorithm !== "http://www.idpf.org/2008/embedding" &&
encrypted.Algorithm !== "http://ns.adobe.com/pdf/enc#RC") {
encrypted.Profile = lcp.Encryption.Profile;
encrypted.Scheme = "http://readium.org/2014/01/lcp";
}
if (encInfo.EncryptionProperties && encInfo.EncryptionProperties.length) {
encInfo.EncryptionProperties.forEach((prop) => {
if (prop.Compression) {
if (prop.Compression.OriginalLength) {
encrypted.OriginalLength = parseFloat(prop.Compression.OriginalLength);
}
if (prop.Compression.Method === "8") {
encrypted.Compression = "deflate";
}
else {
encrypted.Compression = "none";
}
}
});
}
if (publication.Resources) {
publication.Resources.forEach((l) => {
const filePath = l.Href;
if (filePath === (0, decodeURI_1.tryDecodeURI)(encInfo.CipherData.CipherReference.URI)) {
if (!l.Properties) {
l.Properties = new metadata_properties_1.Properties();
}
l.Properties.Encrypted = encrypted;
}
});
}
if (publication.Spine) {
publication.Spine.forEach((l) => {
const filePath = l.Href;
if (filePath === (0, decodeURI_1.tryDecodeURI)(encInfo.CipherData.CipherReference.URI)) {
if (!l.Properties) {
l.Properties = new metadata_properties_1.Properties();
}
l.Properties.Encrypted = encrypted;
}
});
}
});
};
const fillPageListFromAdobePageMap = async (publication, zip, l) => {
if (!l.HrefDecoded) {
return;
}
let pageMapContent = await (0, epub_daisy_common_1.loadFileStrFromZipPath)(l.Href, l.HrefDecoded, zip);
if (!pageMapContent) {
return;
}
pageMapContent = (0, bom_1.removeUTF8BOM)(pageMapContent);
const pageMapXmlDoc = new xmldom.DOMParser().parseFromString(pageMapContent, "application/xml");
const pages = pageMapXmlDoc.getElementsByTagName("page");
if (pages && pages.length) {
for (let i = 0; i < pages.length; i += 1) {
const page = pages.item(i);
if (!page) {
continue;
}
const link = new publication_link_1.Link();
const href = page.getAttribute("href");
const title = page.getAttribute("name");
if (href === null || title === null) {
continue;
}
if (!publication.PageList) {
publication.PageList = [];
}
const hrefDecoded = (0, decodeURI_1.tryDecodeURI)(href);
if (!hrefDecoded) {
continue;
}
const zipPath = path.join(path.dirname(l.HrefDecoded), hrefDecoded)
.replace(/\\/g, "/");
link.setHrefDecoded(zipPath);
link.Title = title;
publication.PageList.push(link);
}
}
};
const fillCalibreSerieInfo = (publication, opf) => {
let serie;
let seriePosition;
if (opf.Metadata && opf.Metadata.Meta && opf.Metadata.Meta.length) {
opf.Metadata.Meta.forEach((m) => {
if (m.Name === "calibre:series") {
serie = m.Content;
}
if (m.Name === "calibre:series_index") {
seriePosition = parseFloat(m.Content);
}
});
}
if (serie) {
const contributor = new metadata_contributor_1.Contributor();
contributor.Name = serie;
if (seriePosition) {
contributor.Position = seriePosition;
}
if (!publication.Metadata.BelongsTo) {
publication.Metadata.BelongsTo = new metadata_belongsto_1.BelongsTo();
}
if (!publication.Metadata.BelongsTo.Series) {
publication.Metadata.BelongsTo.Series = [];
}
publication.Metadata.BelongsTo.Series.push(contributor);
}
};
const fillTOCFromNavDoc = async (publication, zip) => {
const navLink = publication.GetNavDoc();
if (!navLink) {
return;
}
const navLinkHrefDecoded = navLink.HrefDecoded;
if (!navLinkHrefDecoded) {
debug("!?navLink.HrefDecoded");
return;
}
const has = await (0, zipHasEntry_1.zipHasEntry)(zip, navLinkHrefDecoded, navLink.Href);
if (!has) {
debug(`NOT IN ZIP (fillTOCFromNavDoc): ${navLink.Href} --- ${navLinkHrefDecoded}`);
const zipEntries = await zip.getEntries();
for (const zipEntry of zipEntries) {
if (zipEntry.startsWith("__MACOSX/")) {
continue;
}
debug(zipEntry);
}
return;
}
let navDocZipStream_;
try {
navDocZipStream_ = await zip.entryStreamPromise(navLinkHrefDecoded);
}
catch (err) {
debug(err);
return Promise.reject(err);
}
const navDocZipStream = navDocZipStream_.stream;
let navDocZipData;
try {
navDocZipData = await (0, BufferUtils_1.streamToBufferPromise)(navDocZipStream);
}
catch (err) {
debug(err);
return Promise.reject(err);
}
const navDocStr = (0, bom_1.removeUTF8BOM)(navDocZipData.toString("utf8"));
const navXmlDoc = new xmldom.DOMParser().parseFromString(navDocStr, "application/xml");
const select = xpath.useNamespaces({
epub: "http://www.idpf.org/2007/ops",
xhtml: "http://www.w3.org/1999/xhtml",
});
const navs = select("/xhtml:html/xhtml:body//xhtml:nav", navXmlDoc);
if (navs && navs.length) {
navs.forEach((navElement) => {
const epubType = select("@epub:type", navElement);
if (epubType && epubType.length) {
const olElem = select("xhtml:ol", navElement);
const rolesString = epubType[0].value;
const rolesArray = (0, epub_daisy_common_1.parseSpaceSeparatedString)(rolesString);
if (rolesArray.length) {
for (const role of rolesArray) {
switch (role) {
case "toc": {
publication.TOC = [];
fillTOCFromNavDocWithOL(select, olElem, publication.TOC, navLinkHrefDecoded);
break;
}
case "page-list": {
publication.PageList = [];
fillTOCFromNavDocWithOL(select, olElem, publication.PageList, navLinkHrefDecoded);
break;
}
case "landmarks": {
publication.Landmarks = [];
fillTOCFromNavDocWithOL(select, olElem, publication.Landmarks, navLinkHrefDecoded);
break;
}
case "lot": {
publication.LOT = [];
fillTOCFromNavDocWithOL(select, olElem, publication.LOT, navLinkHrefDecoded);
break;
}
case "loa": {
publication.LOA = [];
fillTOCFromNavDocWithOL(select, olElem, publication.LOA, navLinkHrefDecoded);
break;
}
case "loi": {
publication.LOI = [];
fillTOCFromNavDocWithOL(select, olElem, publication.LOI, navLinkHrefDecoded);
break;
}
case "lov": {
publication.LOV = [];
fillTOCFromNavDocWithOL(select, olElem, publication.LOV, navLinkHrefDecoded);
break;
}
default: {
break;
}
}
}
}
}
});
}
};
const fillTOCFromNavDocWithOL = (select, olElems, children, navDocPath) => {
olElems.forEach((olElem) => {
const liElems = select("xhtml:li", olElem);
if (liElems && liElems.length) {
liElems.forEach((liElem) => {
const link = new publication_link_1.Link();
children.push(link);
const aElems = select("xhtml:a", liElem);
if (aElems && aElems.length > 0) {
const epubType = select("@epub:type", aElems[0]);
if (epubType && epubType.length) {
const rolesString = epubType[0].value;
const rolesArray = (0, epub_daisy_common_1.parseSpaceSeparatedString)(rolesString);
if (rolesArray.length) {
link.AddRels(rolesArray);
}
}
const aHref = select("@href", aElems[0]);
if (aHref && aHref.length) {
const val = aHref[0].value;
let valDecoded = (0, decodeURI_1.tryDecodeURI)(val);
if (!valDecoded) {
debug("!?valDecoded");
return;
}
if (val[0] === "#") {
valDecoded = path.basename(navDocPath) + valDecoded;
}
const zipPath = path.join(path.dirname(navDocPath), valDecoded)
.replace(/\\/g, "/");
link.setHrefDecoded(zipPath);
}
let aText = aElems[0].textContent;
if (aText && aText.length) {
aText = aText.trim();
aText = aText.replace(/\s\s+/g, " ");
link.Title = aText;
}
}
else {
const liFirstChild = select("xhtml:*[1]", liElem);
if (liFirstChild && liFirstChild.length && liFirstChild[0].textContent) {
link.Title = liFirstChild[0].textContent.trim();
}
}
const olElemsNext = select("xhtml:ol", liElem);
if (olElemsNext && olElemsNext.length) {
if (!link.Children) {
link.Children = [];
}
fillTOCFromNavDocWithOL(select, olElemsNext, link.Children, navDocPath);
}
});
}
});
};
const addCoverRel = async (publication, rootfile, opf, zip) => {
let coverID;
if (opf.Metadata && opf.Metadata.Meta && opf.Metadata.Meta.length) {
opf.Metadata.Meta.find((meta) => {
if (meta.Name === "cover") {
coverID = meta.Content;
return true;
}
return false;
});
}
if (coverID) {
let manifestInfo;
try {
manifestInfo = await (0, epub_daisy_common_1.findInManifestByID)(publication, rootfile, opf, coverID, zip, addLinkData);
}
catch (err) {
debug(err);
return;
}
if (manifestInfo && manifestInfo.Href && publication.Resources && publication.Resources.length) {
const href = manifestInfo.Href;
const linky = publication.Resources.find((item) => {
if (item.Href === href) {
return true;
}
return false;
});
if (linky) {
linky.AddRel("cover");
await (0, exports.addCoverDimensions)(publication, linky);
}
}
}
};
const findPropertiesInSpineForManifest = (linkEpub, opf) => {
if (opf.Spine && opf.Spine.Items && opf.Spine.Items.length) {
const it = opf.Spine.Items.find((item) => {
if (item.IDref === linkEpub.ID) {
return true;
}
return false;
});
if (it && it.Properties) {
return it.Properties;
}
}
return undefined;
};
//# sourceMappingURL=epub.js.map