UNPKG

vue-book-reader

Version:

vue-book-reader is a vue wrapper for [foliate-js](https://github.com/johnfactotum/foliate-js) - library for rendering e-books in the browser. Supports EPUB, MOBI, KF8 (AZW3), FB2, CBZ, PDF (experimental; requires PDF.js), or add support for other formats

738 lines (737 loc) 31.5 kB
var Ht = Object.defineProperty; var Dt = (r, t, e) => t in r ? Ht(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e; var Nt = (r, t, e) => (Dt(r, typeof t != "symbol" ? t + "" : t, e), e), $t = (r, t, e) => { if (!t.has(r)) throw TypeError("Cannot " + e); }; var o = (r, t, e) => ($t(r, t, "read from private field"), e ? e.call(r) : t.get(r)), b = (r, t, e) => { if (t.has(r)) throw TypeError("Cannot add the same private member more than once"); t instanceof WeakSet ? t.add(r) : t.set(r, e); }, I = (r, t, e, s) => ($t(r, t, "write to private field"), s ? s.call(r, e) : t.set(r, e), e); var Rt = (r, t, e, s) => ({ set _(n) { I(r, t, n, e); }, get _() { return o(r, t, s); } }), w = (r, t, e) => ($t(r, t, "access private method"), e); import { f as Xt, p as qt, t as Ut, a as _t } from "./index-UYMDWtcl.js"; const S = { CONTAINER: "urn:oasis:names:tc:opendocument:xmlns:container", XHTML: "http://www.w3.org/1999/xhtml", OPF: "http://www.idpf.org/2007/opf", EPUB: "http://www.idpf.org/2007/ops", DC: "http://purl.org/dc/elements/1.1/", DCTERMS: "http://purl.org/dc/terms/", ENC: "http://www.w3.org/2001/04/xmlenc#", NCX: "http://www.daisy.org/z3986/2005/ncx/", XLINK: "http://www.w3.org/1999/xlink", SMIL: "http://www.w3.org/ns/SMIL" }, N = { XML: "application/xml", NCX: "application/x-dtbncx+xml", XHTML: "application/xhtml+xml", HTML: "text/html", CSS: "text/css", SVG: "image/svg+xml", JS: /\/(x-)?(javascript|ecmascript)/ }, At = (r) => r.toLowerCase().replace(/[-:](.)/g, (t, e) => e.toUpperCase()), zt = (r) => r ? r.replace(/[\t\n\f\r ]+/g, " ").replace(/^[\t\n\f\r ]+/, "").replace(/[\t\n\f\r ]+$/, "") : "", ct = (r, t, e) => e ? (s) => { var n, c; return (c = (n = s.getAttribute(r)) == null ? void 0 : n.split(/\s/)) == null ? void 0 : c.includes(t); } : typeof t == "function" ? (s) => t(s.getAttribute(r)) : (s) => s.getAttribute(r) === t, Et = (...r) => (t) => t ? Object.fromEntries(r.map((e) => [At(e), t.getAttribute(e)])) : null, B = (r) => zt(r == null ? void 0 : r.textContent), mt = (r, t) => { const e = r.lookupNamespaceURI(null) === t || r.lookupPrefix(t), s = e ? (n, c) => (a) => a.namespaceURI === t && a.localName === c : (n, c) => (a) => a.localName === c; return { $: (n, c) => [...n.children].find(s(n, c)), $$: (n, c) => [...n.children].filter(s(n, c)), $$$: e ? (n, c) => [...n.getElementsByTagNameNS(t, c)] : (n, c) => [...n.getElementsByTagName(c)] }; }, et = (r, t) => { try { if (t.includes(":")) return new URL(r, t); const e = "https://invalid.invalid/", s = new URL(r, e + t); return s.search = "", decodeURI(s.href.replace(e, "")); } catch (e) { return console.warn(e), r; } }, Ot = (r) => /^(?!blob)\w+:/i.test(r), Gt = (r, t) => { if (!r) return t; const e = r.replace(/\/$/, "").split("/"), s = t.replace(/\/$/, "").split("/"), n = (e.length > s.length ? e : s).findIndex((c, a) => e[a] !== s[a]); return n < 0 ? "" : Array(e.length - n).fill("..").concat(s.slice(n)).join("/"); }, Vt = (r) => r.slice(0, r.lastIndexOf("/") + 1), St = async (r, t, e) => { const s = []; r.replace(t, (...c) => (s.push(c), null)); const n = []; for (const c of s) n.push(await e(...c)); return r.replace(t, () => n.shift()); }, Wt = (r) => r.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"), z = { attrs: ["dir", "xml:lang"] }, J = { name: "alternate-script", many: !0, ...z, props: ["file-as"] }, Bt = { many: !0, ...z, props: [{ name: "role", many: !0, attrs: ["scheme"] }, "file-as", J], setLegacyAttrs: (r, t) => { var e; if (!((e = r.role) != null && e.length)) { const s = t.getAttributeNS(S.OPF, "role"); s && (r.role = [{ value: s }]); } r.fileAs ?? (r.fileAs = t.getAttributeNS(S.OPF, "file-as")); } }, Jt = [ { name: "title", many: !0, ...z, props: ["title-type", "display-seq", "file-as", J] }, { name: "identifier", many: !0, props: [{ name: "identifier-type", attrs: ["scheme"] }], setLegacyAttrs: (r, t) => { if (!r.identifierType) { const e = t.getAttributeNS(S.OPF, "scheme"); e && (r.identifierType = { value: e }); } } }, { name: "language", many: !0 }, { name: "creator", ...Bt }, { name: "contributor", ...Bt }, { name: "publisher", ...z, props: ["file-as", J] }, { name: "description", ...z, props: [J] }, { name: "rights", ...z, props: [J] }, { name: "date" }, { name: "dcterms:modified", type: "meta" }, { name: "subject", many: !0, ...z, props: ["term", "authority", J], setLegacyAttrs: (r, t) => { r.term ?? (r.term = t.getAttributeNS(S.OPF, "term")), r.authority ?? (r.authority = t.getAttributeNS(S.OPF, "authority")); } }, { name: "source", many: !0 }, { name: "belongs-to-collection", type: "meta", many: !0, ...z, props: [ "collection-type", "group-position", "dcterms:identifier", "file-as", J, { name: "belongs-to-collection", recursive: !0 } ] } ], Kt = (r) => { var g, A; const { $: t, $$: e } = mt(r, S.OPF), s = t(r.documentElement, "metadata"), n = Array.from(s.children), c = (m, l) => { var _; if (!l) return null; const { props: f = [], attrs: v = [] } = m, k = B(l); if (!f.length && !v.length) return k; const x = l.getAttribute("id"), j = x ? n.filter(ct("refines", "#" + x)) : [], q = Object.fromEntries([["value", k]].concat(f.map((M) => { const { many: gt, recursive: yt } = M, W = typeof M == "string" ? M : M.name, ot = ct("property", W), at = yt ? m : M; return [At(W), gt ? j.filter(ot).map((wt) => c(at, wt)) : c(at, j.find(ot))]; })).concat(v.map((M) => [At(M), l.getAttribute(M)]))); return (_ = m.setLegacyAttrs) == null || _.call(m, q, l), q; }, a = n.filter(ct("refines", null)), u = Object.fromEntries(Jt.map((m) => { const { type: l, name: f, many: v } = m, k = l === "meta" ? (x) => x.namespaceURI === S.OPF && x.getAttribute("property") === f : (x) => x.namespaceURI === S.DC && x.localName === f; return [At(f), v ? a.filter(k).map((x) => c(m, x)) : c(m, a.find(k))]; })), i = e(s, "meta"), p = (m) => i.filter(ct("property", (l) => l == null ? void 0 : l.startsWith(m))).map((l) => [l.getAttribute("property").replace(m, ""), l]), d = Object.fromEntries(p("rendition:").map(([m, l]) => [m, B(l)])), h = { narrator: [], duration: {} }; for (const [m, l] of p("media:")) { const f = B(l); m === "duration" ? h.duration[((A = (g = l.getAttribute("refines")) == null ? void 0 : g.split("#")) == null ? void 0 : A[1]) ?? ""] = Ct(f) : m === "active-class" ? h.activeClass = f : m === "narrator" ? h.narrator.push(f) : m === "playback-active-class" && (h.playbackActiveClass = f); } return { metadata: u, rendition: d, media: h }; }, Qt = (r, t = (e) => e) => { var m; const { $: e, $$: s, $$$: n } = mt(r, S.XHTML), c = (l) => l ? decodeURI(t(l)) : null, a = (l) => (f) => { var _; const v = e(f, "a") ?? e(f, "span"), k = e(f, "ol"), x = c(v == null ? void 0 : v.getAttribute("href")), q = { label: B(v) || (v == null ? void 0 : v.getAttribute("title")), href: x, subitems: u(k) }; return l && (q.type = (_ = v == null ? void 0 : v.getAttributeNS(S.EPUB, "type")) == null ? void 0 : _.split(/\s/)), q; }, u = (l, f) => l ? s(l, "li").map(a(f)) : null, i = (l, f) => u(e(l, "ol"), f), p = n(r, "nav"); let d = null, h = null, g = null, A = []; for (const l of p) { const f = ((m = l.getAttributeNS(S.EPUB, "type")) == null ? void 0 : m.split(/\s/)) ?? []; f.includes("toc") ? d ?? (d = i(l)) : f.includes("page-list") ? h ?? (h = i(l)) : f.includes("landmarks") ? g ?? (g = i(l, !0)) : A.push({ label: B(l.firstElementChild), type: f, list: i(l) }); } return { toc: d, pageList: h, landmarks: g, others: A }; }, Yt = (r, t = (e) => e) => { const { $: e, $$: s } = mt(r, S.NCX), n = (i) => i ? decodeURI(t(i)) : null, c = (i) => { const p = e(i, "navLabel"), d = e(i, "content"), h = B(p), g = n(d.getAttribute("src")); if (i.localName === "navPoint") { const A = s(i, "navPoint"); return { label: h, href: g, subitems: A.length ? A.map(c) : null }; } return { label: h, href: g }; }, a = (i, p) => s(i, p).map(c), u = (i, p) => { const d = e(r.documentElement, i); return d ? a(d, p) : null; }; return { toc: u("navMap", "navPoint"), pageList: u("pageList", "pageTarget"), others: s(r.documentElement, "navList").map((i) => ({ label: B(e(i, "navLabel")), list: a(i, "navTarget") })) }; }, Ct = (r) => { if (!r) return; const t = r.split(":").map((a) => parseFloat(a)); if (t.length === 3) { const [a, u, i] = t; return a * 60 * 60 + u * 60 + i; } if (t.length === 2) { const [a, u] = t; return a * 60 + u; } const [e, s] = r.split(/(?=[^\d.])/), n = parseFloat(e), c = s === "h" ? 60 * 60 : s === "min" ? 60 : s === "ms" ? 1e-3 : 1; return n * c; }; var G, lt, Y, C, $, T, ht, ut, Tt, Pt, st, Lt, V, tt, F, K, pt, Mt, rt, It, H, Q; class Zt extends EventTarget { constructor(e, s) { super(); b(this, Tt); b(this, st); b(this, V); b(this, F); b(this, pt); b(this, rt); b(this, H); b(this, G, void 0); b(this, lt, void 0); b(this, Y, void 0); b(this, C, void 0); b(this, $, void 0); b(this, T, void 0); b(this, ht, 1); b(this, ut, 1); this.book = e, this.loadXML = s; } async start(e, s = () => !0) { var u; (u = o(this, T)) == null || u.pause(); const n = this.book.sections[e], c = n == null ? void 0 : n.id; if (!c) return; const { mediaOverlay: a } = n; if (!a) return this.start(e + 1); I(this, Y, e), await w(this, Tt, Pt).call(this, a); for (let i = 0; i < o(this, G).length; i++) { const { items: p } = o(this, G)[i]; for (let d = 0; d < p.length; d++) if (p[d].text.split("#")[0] === c && s(p[d], d, p)) return w(this, H, Q).call(this, i, d).catch((h) => w(this, F, K).call(this, h)); } } pause() { var e; (e = o(this, T)) == null || e.pause(); } resume() { var e; (e = o(this, T)) == null || e.play().catch((s) => w(this, F, K).call(this, s)); } prev() { o(this, $) > 0 ? w(this, H, Q).call(this, o(this, C), o(this, $) - 1) : o(this, C) > 0 ? w(this, H, Q).call(this, o(this, C) - 1, o(this, G)[o(this, C) - 1].items.length - 1) : o(this, Y) > 0 && this.start(o(this, Y) - 1, (e, s, n) => s === n.length - 1); } next() { w(this, H, Q).call(this, o(this, C), o(this, $) + 1); } setVolume(e) { I(this, ht, e), o(this, T) && (o(this, T).volume = e); } setRate(e) { I(this, ut, e), o(this, T) && (o(this, T).playbackRate = e); } } G = new WeakMap(), lt = new WeakMap(), Y = new WeakMap(), C = new WeakMap(), $ = new WeakMap(), T = new WeakMap(), ht = new WeakMap(), ut = new WeakMap(), Tt = new WeakSet(), Pt = async function(e) { if (o(this, lt) === e) return; const s = await this.loadXML(e.href), n = (u) => u ? et(u, e.href) : null, { $: c, $$$: a } = mt(s, S.SMIL); I(this, C, -1), I(this, $, -1), I(this, G, a(s, "par").reduce((u, i) => { var l; const p = n((l = c(i, "text")) == null ? void 0 : l.getAttribute("src")), d = c(i, "audio"); if (!p || !d) return u; const h = n(d.getAttribute("src")), g = Ct(d.getAttribute("clipBegin")), A = Ct(d.getAttribute("clipEnd")), m = u.at(-1); return (m == null ? void 0 : m.src) === h ? m.items.push({ text: p, begin: g, end: A }) : u.push({ src: h, items: [{ text: p, begin: g, end: A }] }), u; }, [])), I(this, lt, e); }, st = new WeakSet(), Lt = function() { return o(this, G)[o(this, C)]; }, V = new WeakSet(), tt = function() { var e, s; return (s = (e = o(this, st, Lt)) == null ? void 0 : e.items) == null ? void 0 : s[o(this, $)]; }, F = new WeakSet(), K = function(e) { console.error(e), this.dispatchEvent(new CustomEvent("error", { detail: e })); }, pt = new WeakSet(), Mt = function() { this.dispatchEvent(new CustomEvent("highlight", { detail: o(this, V, tt) })); }, rt = new WeakSet(), It = function() { this.dispatchEvent(new CustomEvent("unhighlight", { detail: o(this, V, tt) })); }, H = new WeakSet(), Q = async function(e, s) { var u; o(this, T) && (o(this, T).pause(), URL.revokeObjectURL(o(this, T).src), I(this, T, null)), I(this, C, e), I(this, $, s); const n = (u = o(this, st, Lt)) == null ? void 0 : u.src; if (!n || !o(this, V, tt)) return this.start(o(this, Y) + 1); const c = URL.createObjectURL(await this.book.loadBlob(n)), a = new Audio(c); I(this, T, a), a.addEventListener("timeupdate", () => { var h, g; if (a.paused) return; const i = a.currentTime, { items: p } = o(this, st, Lt); if (i > ((h = o(this, V, tt)) == null ? void 0 : h.end) && (w(this, rt, It).call(this), o(this, $) === p.length - 1)) { w(this, H, Q).call(this, o(this, C) + 1, 0).catch((A) => w(this, F, K).call(this, A)); return; } const d = o(this, $); for (; ((g = p[o(this, $) + 1]) == null ? void 0 : g.begin) <= i; ) Rt(this, $)._++; o(this, $) !== d && w(this, pt, Mt).call(this); }), a.addEventListener("error", () => w(this, F, K).call(this, new Error(`Failed to load ${n}`))), a.addEventListener("playing", () => w(this, pt, Mt).call(this)), a.addEventListener("pause", () => w(this, rt, It).call(this)), a.addEventListener("ended", () => { w(this, rt, It).call(this), URL.revokeObjectURL(c), I(this, T, null), w(this, H, Q).call(this, e + 1, 0).catch((i) => w(this, F, K).call(this, i)); }), a.addEventListener("canplaythrough", () => { a.currentTime = o(this, V, tt).begin ?? 0, a.volume = o(this, ht), a.playbackRate = o(this, ut), a.play().catch((i) => w(this, F, K).call(this, i)); }); }; const jt = /([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})/, te = (r) => { for (const t of r.getElementsByTagNameNS(S.DC, "identifier")) { const [e] = B(t).split(":").slice(-1); if (jt.test(e)) return e; } return ""; }, Ft = (r) => B( r.getElementById(r.documentElement.getAttribute("unique-identifier")) ?? r.getElementsByTagNameNS(S.DC, "identifier")[0] ), kt = async (r, t, e) => { const s = new Uint8Array(await e.slice(0, t).arrayBuffer()); t = Math.min(t, s.length); for (var n = 0; n < t; n++) s[n] = s[n] ^ r[n % r.length]; return new Blob([s, e.slice(t)], { type: e.type }); }, ee = async (r) => { const t = new TextEncoder().encode(r), e = await globalThis.crypto.subtle.digest("SHA-1", t); return new Uint8Array(e); }, se = (r = ee) => ({ "http://www.idpf.org/2008/embedding": { key: (t) => r(Ft(t).replaceAll(/[\u0020\u0009\u000d\u000a]/g, "")), decode: (t, e) => kt(t, 1040, e) }, "http://ns.adobe.com/pdf/enc#RC": { key: (t) => { const e = te(t).replaceAll("-", ""); return Uint8Array.from({ length: 16 }, (s, n) => parseInt(e.slice(n * 2, n * 2 + 2), 16)); }, decode: (t, e) => kt(t, 1024, e) } }); var dt, it, ft; class re { constructor(t) { b(this, dt, /* @__PURE__ */ new Map()); b(this, it, /* @__PURE__ */ new Map()); b(this, ft, void 0); I(this, ft, t); } async init(t, e) { if (!t) return; const s = Array.from( t.getElementsByTagNameNS(S.ENC, "EncryptedData"), (n) => { var c, a; return { algorithm: (c = n.getElementsByTagNameNS(S.ENC, "EncryptionMethod")[0]) == null ? void 0 : c.getAttribute("Algorithm"), uri: (a = n.getElementsByTagNameNS(S.ENC, "CipherReference")[0]) == null ? void 0 : a.getAttribute("URI") }; } ); for (const { algorithm: n, uri: c } of s) { if (!o(this, it).has(n)) { const a = o(this, ft)[n]; if (!a) { console.warn("Unknown encryption algorithm"); continue; } const u = await a.key(e); o(this, it).set(n, (i) => a.decode(u, i)); } o(this, dt).set(c, n); } } getDecoder(t) { return o(this, it).get(o(this, dt).get(t)) ?? ((e) => e); } } dt = new WeakMap(), it = new WeakMap(), ft = new WeakMap(); class ie { constructor({ opf: t, resolveHref: e }) { var d, h, g, A, m; this.opf = t; const { $: s, $$: n, $$$: c } = mt(t, S.OPF), a = s(t.documentElement, "manifest"), u = s(t.documentElement, "spine"), i = n(u, "itemref"); this.manifest = n(a, "item").map(Et("href", "id", "media-type", "properties", "media-overlay")).map((l) => { var f; return l.href = e(l.href), l.properties = (f = l.properties) == null ? void 0 : f.split(/\s/), l; }), this.spine = i.map(Et("idref", "id", "linear", "properties")).map((l) => { var f; return l.properties = (f = l.properties) == null ? void 0 : f.split(/\s/), l; }), this.pageProgressionDirection = u.getAttribute("page-progression-direction"), this.navPath = (d = this.getItemByProperty("nav")) == null ? void 0 : d.href, this.ncxPath = (h = this.getItemByID(u.getAttribute("toc")) ?? this.manifest.find((l) => l.mediaType === N.NCX)) == null ? void 0 : h.href; const p = s(t.documentElement, "guide"); p && (this.guide = n(p, "reference").map(Et("type", "title", "href")).map(({ type: l, title: f, href: v }) => ({ label: f, type: l.split(/\s/), href: e(v) }))), this.cover = this.getItemByProperty("cover-image") ?? this.getItemByID((g = c(t, "meta").find(ct("name", "cover"))) == null ? void 0 : g.getAttribute("content")) ?? this.getItemByHref((m = (A = this.guide) == null ? void 0 : A.find((l) => l.type.includes("cover"))) == null ? void 0 : m.href), this.cfis = Xt(i); } getItemByID(t) { return this.manifest.find((e) => e.id === t); } getItemByHref(t) { return this.manifest.find((e) => e.href === t); } getItemByProperty(t) { return this.manifest.find((e) => { var s; return (s = e.properties) == null ? void 0 : s.includes(t); }); } resolveCFI(t) { const e = qt(t), s = (e.parent ?? e).shift(); let n = Ut(this.opf, s); n && n.nodeName !== "idref" && (s.at(-1).id = null, n = Ut(this.opf, s)); const c = n == null ? void 0 : n.getAttribute("idref"); return { index: this.spine.findIndex((i) => i.idref === c), anchor: (i) => _t(i, e) }; } } var D, X, O; class ne { constructor({ loadText: t, loadBlob: e, resources: s }) { b(this, D, /* @__PURE__ */ new Map()); b(this, X, /* @__PURE__ */ new Map()); b(this, O, /* @__PURE__ */ new Map()); Nt(this, "allowScript", !1); this.loadText = t, this.loadBlob = e, this.manifest = s.manifest, this.assets = s.manifest; } createURL(t, e, s, n) { if (!e) return ""; const c = URL.createObjectURL(new Blob([e], { type: s })); if (o(this, D).set(t, c), o(this, O).set(t, 1), n) { const a = o(this, X).get(n); a ? a.push(t) : o(this, X).set(n, [t]); } return c; } ref(t, e) { const s = o(this, X).get(e); return s != null && s.includes(t) || (o(this, O).set(t, o(this, O).get(t) + 1), s ? s.push(t) : o(this, X).set(e, [t])), o(this, D).get(t); } unref(t) { if (!o(this, O).has(t)) return; const e = o(this, O).get(t) - 1; if (e < 1) { URL.revokeObjectURL(o(this, D).get(t)), o(this, D).delete(t), o(this, O).delete(t); const s = o(this, X).get(t); if (s) for (; s.length; ) this.unref(s.pop()); o(this, X).delete(t); } else o(this, O).set(t, e); } // load manifest item, recursively loading all resources as needed async loadItem(t, e = []) { if (!t) return null; const { href: s, mediaType: n } = t, c = N.JS.test(t.mediaType); if (c && !this.allowScript) return null; const a = e.at(-1); return o(this, D).has(s) ? this.ref(s, a) : (c || [N.XHTML, N.HTML, N.CSS, N.SVG].includes(n)) && e.every((i) => i !== s) ? this.loadReplaced(t, e) : this.createURL(s, await this.loadBlob(s), n, a); } async loadHref(t, e, s = []) { if (Ot(t)) return t; const n = et(t, e), c = this.manifest.find((a) => a.href === n); return c ? this.loadItem(c, s.concat(e)) : t; } async loadReplaced(t, e = []) { const { href: s, mediaType: n } = t, c = e.at(-1), a = await this.loadText(s); if (!a) return null; if ([N.XHTML, N.HTML, N.SVG].includes(n)) { let i = new DOMParser().parseFromString(a, n); if (n === N.XHTML && i.querySelector("parsererror") && (console.warn(i.querySelector("parsererror").innerText), t.mediaType = N.HTML, i = new DOMParser().parseFromString(a, t.mediaType)), [N.XHTML, N.SVG].includes(t.mediaType)) { let h = i.firstChild; for (; h instanceof ProcessingInstruction; ) { if (h.data) { const g = await St( h.data, /(?:^|\s*)(href\s*=\s*['"])([^'"]*)(['"])/i, (A, m, l, f) => this.loadHref(l, s, e).then((v) => `${m}${v}${f}`) ); h.replaceWith(i.createProcessingInstruction( h.target, g )); } h = h.nextSibling; } } const p = async (h, g) => h.setAttribute( g, await this.loadHref(h.getAttribute(g), s, e) ); for (const h of i.querySelectorAll("link[href]")) await p(h, "href"); for (const h of i.querySelectorAll("[src]")) await p(h, "src"); for (const h of i.querySelectorAll("[poster]")) await p(h, "poster"); for (const h of i.querySelectorAll("object[data]")) await p(h, "data"); for (const h of i.querySelectorAll("[*|href]:not([href])")) h.setAttributeNS(S.XLINK, "href", await this.loadHref( h.getAttributeNS(S.XLINK, "href"), s, e )); for (const h of i.querySelectorAll("style")) h.textContent && (h.textContent = await this.replaceCSS(h.textContent, s, e)); for (const h of i.querySelectorAll("[style]")) h.setAttribute( "style", await this.replaceCSS(h.getAttribute("style"), s, e) ); const d = new XMLSerializer().serializeToString(i); return this.createURL(s, d, t.mediaType, c); } const u = n === N.CSS ? await this.replaceCSS(a, s, e) : await this.replaceString(a, s, e); return this.createURL(s, u, n, c); } async replaceCSS(t, e, s = []) { const n = await St( t, /url\(\s*["']?([^'"\n]*?)\s*["']?\s*\)/gi, (i, p) => this.loadHref(p, e, s).then((d) => `url("${d}")`) ), c = await St( n, /@import\s*["']([^"'\n]*?)["']/gi, (i, p) => this.loadHref(p, e, s).then((d) => `@import "${d}"`) ), a = (window == null ? void 0 : window.innerWidth) ?? 800, u = (window == null ? void 0 : window.innerHeight) ?? 600; return c.replace(new RegExp("(?<=[{\\s;])-epub-", "gi"), "").replace(/(\d*\.?\d+)vw/gi, (i, p) => parseFloat(p) * a / 100 + "px").replace(/(\d*\.?\d+)vh/gi, (i, p) => parseFloat(p) * u / 100 + "px").replace(/page-break-(after|before|inside)\s*:/gi, (i, p) => `-webkit-column-break-${p}:`).replace(/break-(after|before|inside)\s*:\s*(avoid-)?page/gi, (i, p, d) => `break-${p}: ${d ?? ""}column`); } // find & replace all possible relative paths for all assets without parsing replaceString(t, e, s = []) { const n = /* @__PURE__ */ new Map(), c = this.assets.map((u) => { if (u.href === e) return; const i = Gt(Vt(e), u.href), p = encodeURI(i), d = "/" + u.href, h = encodeURI(d), g = /* @__PURE__ */ new Set([i, p, d, h]); for (const A of g) n.set(A, u); return Array.from(g); }).flat().filter((u) => u); if (!c.length) return t; const a = new RegExp(c.map(Wt).join("|"), "g"); return St(t, a, async (u) => this.loadItem( n.get(u.replace(/^\//, "")), s.concat(e) )); } unloadItem(t) { this.unref(t == null ? void 0 : t.href); } destroy() { for (const t of o(this, D).values()) URL.revokeObjectURL(t); } } D = new WeakMap(), X = new WeakMap(), O = new WeakMap(); const oe = (r, t) => r.getElementById(t) ?? r.querySelector(`[name="${CSS.escape(t)}"]`), ae = (r) => { for (const t of r) { if (t === "page-spread-left" || t === "rendition:page-spread-left") return "left"; if (t === "page-spread-right" || t === "rendition:page-spread-right") return "right"; if (t === "rendition:page-spread-center") return "center"; } }, ce = (r) => r ? { fixedLayout: B(r.querySelector('option[name="fixed-layout"]')), openToSpread: B(r.querySelector('option[name="open-to-spread"]')) } : null; var Z, nt, U, P; class ue { constructor({ loadText: t, loadBlob: e, getSize: s, sha1: n }) { b(this, U); Nt(this, "parser", new DOMParser()); b(this, Z, void 0); b(this, nt, void 0); this.loadText = t, this.loadBlob = e, this.getSize = s, I(this, nt, new re(se(n))); } async init() { var l, f, v, k, x, j, q, _, M, gt, yt, W, ot, at, wt; const t = await w(this, U, P).call(this, "META-INF/container.xml"); if (!t) throw new Error("Failed to load container file"); const e = Array.from( t.getElementsByTagNameNS(S.CONTAINER, "rootfile"), Et("full-path", "media-type") ).filter((y) => y.mediaType === "application/oebps-package+xml"); if (!e.length) throw new Error("No package document defined in container"); const s = e[0].fullPath, n = await w(this, U, P).call(this, s); if (!n) throw new Error("Failed to load package document"); const c = await w(this, U, P).call(this, "META-INF/encryption.xml"); await o(this, nt).init(c, n), this.resources = new ie({ opf: n, resolveHref: (y) => et(y, s) }), I(this, Z, new ne({ loadText: this.loadText, loadBlob: (y) => Promise.resolve(this.loadBlob(y)).then(o(this, nt).getDecoder(y)), resources: this.resources })), this.sections = this.resources.spine.map((y, E) => { const { idref: L, linear: xt, properties: bt = [] } = y, R = this.resources.getItemByID(L); return R ? { id: R.href, load: () => o(this, Z).loadItem(R), unload: () => o(this, Z).unloadItem(R), createDocument: () => this.loadDocument(R), size: this.getSize(R.href), cfi: this.resources.cfis[E], linear: xt, pageSpread: ae(bt), resolveHref: (vt) => et(vt, R.href), mediaOverlay: R.mediaOverlay ? this.resources.getItemByID(R.mediaOverlay) : null } : (console.warn(`Could not find item with ID "${L}" in manifest`), null); }).filter((y) => y); const { navPath: a, ncxPath: u } = this.resources; if (a) try { const y = (L) => et(L, a), E = Qt(await w(this, U, P).call(this, a), y); this.toc = E.toc, this.pageList = E.pageList, this.landmarks = E.landmarks; } catch (y) { console.warn(y); } if (!this.toc && u) try { const y = (L) => et(L, u), E = Yt(await w(this, U, P).call(this, u), y); this.toc = E.toc, this.pageList = E.pageList; } catch (y) { console.warn(y); } this.landmarks ?? (this.landmarks = this.resources.guide); const { metadata: i, rendition: p, media: d } = Kt(n); this.rendition = p, this.media = d, this.dir = this.resources.pageProgressionDirection; const h = ce( await w(this, U, P).call(this, "META-INF/com.apple.ibooks.display-options.xml") ?? await w(this, U, P).call(this, "META-INF/com.kobobooks.display-options.xml") ); h && (h.fixedLayout === "true" && ((l = this.rendition).layout ?? (l.layout = "pre-paginated")), h.openToSpread === "false" && ((f = this.sections.find((y) => y.linear !== "no")).pageSpread ?? (f.pageSpread = this.dir === "rtl" ? "left" : "right"))), this.parsedMetadata = i; const g = (v = i == null ? void 0 : i.title) == null ? void 0 : v[0]; this.metadata = { title: g == null ? void 0 : g.value, subtitle: (x = (k = i == null ? void 0 : i.title) == null ? void 0 : k.find((y) => y.titleType === "subtitle")) == null ? void 0 : x.value, sortAs: g == null ? void 0 : g.fileAs, language: i == null ? void 0 : i.language, identifier: Ft(n), description: (j = i == null ? void 0 : i.description) == null ? void 0 : j.value, publisher: (q = i == null ? void 0 : i.publisher) == null ? void 0 : q.value, published: i == null ? void 0 : i.date, modified: i == null ? void 0 : i.dctermsModified, subject: (M = (_ = i == null ? void 0 : i.subject) == null ? void 0 : _.filter(({ value: y, term: E }) => y || E)) == null ? void 0 : M.map(({ value: y, term: E, authority: L }) => ({ name: y, code: E, scheme: L })), rights: (gt = i == null ? void 0 : i.rights) == null ? void 0 : gt.value }; const A = { art: "artist", aut: "author", bkp: "producer", clr: "colorist", edt: "editor", ill: "illustrator", nrt: "narrator", trl: "translator", pbl: "publisher" }, m = (y) => (E) => { var bt; const L = [...new Set((bt = E.role) == null ? void 0 : bt.map(({ value: R, scheme: vt }) => (!vt || vt === "marc:relators" ? A[R] : null) ?? y))], xt = { name: E.value, sortAs: E.fileAs }; return [L != null && L.length ? L : [y], xt]; }; return (wt = (at = (yt = i == null ? void 0 : i.creator) == null ? void 0 : yt.map(m("author"))) == null ? void 0 : at.concat((ot = (W = i == null ? void 0 : i.contributor) == null ? void 0 : W.map) == null ? void 0 : ot.call(W, m("contributor")))) == null || wt.forEach(([y, E]) => y.forEach((L) => { this.metadata[L] ? this.metadata[L].push(E) : this.metadata[L] = [E]; })), this; } async loadDocument(t) { const e = await this.loadText(t.href); return this.parser.parseFromString(e, t.mediaType); } getMediaOverlay() { return new Zt(this, w(this, U, P).bind(this)); } resolveCFI(t) { return this.resources.resolveCFI(t); } resolveHref(t) { const [e, s] = t.split("#"), n = this.resources.getItemByHref(decodeURI(e)); return n ? { index: this.resources.spine.findIndex(({ idref: u }) => u === n.id), anchor: s ? (u) => oe(u, s) : () => 0 } : null; } splitTOCHref(t) { return (t == null ? void 0 : t.split("#")) ?? []; } getTOCFragment(t, e) { return t.getElementById(e) ?? t.querySelector(`[name="${CSS.escape(e)}"]`); } isExternal(t) { return Ot(t); } async getCover() { var e; const t = (e = this.resources) == null ? void 0 : e.cover; return t != null && t.href ? new Blob([await this.loadBlob(t.href)], { type: t.mediaType }) : null; } async getCalibreBookmarks() { const t = await this.loadText("META-INF/calibre_bookmarks.txt"), e = "encoding=json+base64:"; if (t != null && t.startsWith(e)) { const s = atob(t.slice(e.length)); return JSON.parse(s); } } destroy() { var t; (t = o(this, Z)) == null || t.destroy(); } } Z = new WeakMap(), nt = new WeakMap(), U = new WeakSet(), P = async function(t) { const e = await this.loadText(t); if (!e) return null; const s = this.parser.parseFromString(e, N.XML); if (s.querySelector("parsererror")) throw new Error(`XML parsing error: ${t} ${s.querySelector("parsererror").innerText}`); return s; }; export { ue as EPUB };