vue-book-reader
Version:
<div align="center"> <img width=250 src="https://raw.githubusercontent.com/jinhuan138/vue--book-reader/master/public/logo.png" /> <h1>VueReader</h1> </div>
770 lines (769 loc) • 31.4 kB
JavaScript
import { f as gt, p as yt, t as pt, a as wt } from "./index-4W3UIPTc.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"
}, A = {
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)/
}, C = {
a11y: "http://www.idpf.org/epub/vocab/package/a11y/#",
dcterms: "http://purl.org/dc/terms/",
marc: "http://id.loc.gov/vocabulary/",
media: "http://www.idpf.org/epub/vocab/overlays/#",
onix: "http://www.editeur.org/ONIX/book/codelists/current.html#",
rendition: "http://www.idpf.org/vocab/rendition/#",
schema: "http://schema.org/",
xsd: "http://www.w3.org/2001/XMLSchema#",
msv: "http://www.idpf.org/epub/vocab/structure/magazine/#",
prism: "http://www.prismstandard.org/specifications/3.0/PRISM_CV_Spec_3.0.htm#"
}, bt = {
art: "artist",
aut: "author",
clr: "colorist",
edt: "editor",
ill: "illustrator",
nrt: "narrator",
trl: "translator",
pbl: "publisher"
}, vt = {
"02": "isbn",
"06": "doi",
15: "isbn",
26: "doi",
34: "issn"
}, D = (i) => i.toLowerCase().replace(/[-:](.)/g, (t, e) => e.toUpperCase()), St = (i) => i ? i.replace(/[\t\n\f\r ]+/g, " ").replace(/^[\t\n\f\r ]+/, "").replace(/[\t\n\f\r ]+$/, "") : "", Et = (i, t, e) => e ? (s) => {
var r, o;
return (o = (r = s.getAttribute(i)) == null ? void 0 : r.split(/\s/)) == null ? void 0 : o.includes(t);
} : typeof t == "function" ? (s) => t(s.getAttribute(i)) : (s) => s.getAttribute(i) === t, P = (...i) => (t) => t ? Object.fromEntries(i.map((e) => [D(e), t.getAttribute(e)])) : null, R = (i) => St(i == null ? void 0 : i.textContent), k = (i, t) => {
const e = i.lookupNamespaceURI(null) === t || i.lookupPrefix(t), s = e ? (r, o) => (a) => a.namespaceURI === t && a.localName === o : (r, o) => (a) => a.localName === o;
return {
$: (r, o) => [...r.children].find(s(r, o)),
$$: (r, o) => [...r.children].filter(s(r, o)),
$$$: e ? (r, o) => [...r.getElementsByTagNameNS(t, o)] : (r, o) => [...r.getElementsByTagName(o)]
};
}, $ = (i, t) => {
try {
if (t.includes(":"))
return new URL(i, t);
const e = "https://invalid.invalid/", s = new URL(i, e + t);
return s.search = "", decodeURI(s.href.replace(e, ""));
} catch (e) {
return console.warn(e), i;
}
}, ft = (i) => /^(?!blob)\w+:/i.test(i), It = (i, t) => {
if (!i)
return t;
const e = i.replace(/\/$/, "").split("/"), s = t.replace(/\/$/, "").split("/"), r = (e.length > s.length ? e : s).findIndex((o, a) => e[a] !== s[a]);
return r < 0 ? "" : Array(e.length - r).fill("..").concat(s.slice(r)).join("/");
}, At = (i) => i.slice(0, i.lastIndexOf("/") + 1), x = async (i, t, e) => {
const s = [];
i.replace(t, (...o) => (s.push(o), null));
const r = [];
for (const o of s)
r.push(await e(...o));
return i.replace(t, () => r.shift());
}, Lt = (i) => i.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"), X = (i) => {
for (const [e, s] of Object.entries(i))
s == null ? delete i[e] : Array.isArray(s) ? (i[e] = s.filter((r) => r).map((r) => typeof r == "object" && !Array.isArray(r) ? X(r) : r), i[e].length ? i[e].length === 1 && (i[e] = i[e][0]) : delete i[e]) : typeof s == "object" && (i[e] = X(s), Object.keys(s).length || delete i[e]);
const t = Object.keys(i);
return t.length === 1 && t[0] === "name" ? i[t[0]] : i;
}, Tt = (i) => {
const t = new Map(Object.entries(C)), e = i.documentElement.getAttributeNS(S.EPUB, "prefix") || i.documentElement.getAttribute("prefix");
if (e)
for (const [, s, r] of e.matchAll(/(.+): +(.+)[ \t\r\n]*/g))
t.set(s, r);
return t;
}, ut = (i, t) => {
if (!i)
return null;
const [e, s] = i.split(":"), r = s ? e : null, o = s || e, a = t.get(r);
return a ? a + o : null;
}, Rt = (i) => {
var j, q, _, z, V, W, G, J, K, Q, Y, Z, tt, et, st, rt, it, nt, ot, at, ct, lt, ht;
const { $: t } = k(i, S.OPF), e = t(i.documentElement, "metadata"), s = Object.groupBy(e.children, (n) => n.namespaceURI === S.DC ? "dc" : n.namespaceURI === S.OPF && n.localName === "meta" ? n.hasAttribute("name") ? "legacyMeta" : "meta" : ""), r = e.getAttribute("xml:lang") ?? i.documentElement.getAttribute("xml:lang") ?? "und", o = Tt(i), a = (n) => {
const g = n.getAttribute("property"), v = n.getAttribute("scheme");
return {
property: ut(g, o) ?? g,
scheme: ut(v, o) ?? v,
lang: n.getAttribute("xml:lang"),
value: R(n),
props: h(n),
// `opf:` attributes from EPUB 2 & EPUB 3.1 (removed in EPUB 3.2)
attrs: Object.fromEntries(Array.from(n.attributes).filter((E) => E.namespaceURI === S.OPF).map((E) => [E.localName, E.value]))
};
}, c = Map.groupBy(s.meta ?? [], (n) => n.getAttribute("refines")), h = (n) => {
const g = c.get(n ? "#" + n.getAttribute("id") : null);
return g ? Object.groupBy(g.map(a), (v) => v.property) : null;
}, p = Object.fromEntries(Object.entries(Object.groupBy(s.dc, (n) => n.localName)).map(([n, g]) => [n, g.map(a)])), d = h() ?? {}, m = Object.fromEntries(((j = s.legacyMeta) == null ? void 0 : j.map((n) => [n.getAttribute("name"), n.getAttribute("content")])) ?? []), u = (n) => {
var g;
return (g = n == null ? void 0 : n[0]) == null ? void 0 : g.value;
}, l = (n, g) => {
var v;
return u((v = n == null ? void 0 : n.props) == null ? void 0 : v[g]);
}, b = (n) => {
var I;
if (!n)
return null;
const g = ((I = n.props) == null ? void 0 : I["alternate-script"]) ?? [], v = n.attrs["alt-rep"];
if (!g.length && (!n.lang || n.lang === r) && !v)
return n.value;
const E = { [n.lang ?? r]: n.value };
v && (E[n.attrs["alt-rep-lang"]] = v);
for (const O of g)
E[O.lang] ??= O.value;
return E;
}, f = (n) => {
var g, v, E, I, O;
return n ? {
name: b(n),
sortAs: b((v = (g = n.props) == null ? void 0 : g["file-as"]) == null ? void 0 : v[0]) ?? n.attrs["file-as"],
role: ((O = (I = (E = n.props) == null ? void 0 : E.role) == null ? void 0 : I.filter((H) => H.scheme === C.marc + "relators")) == null ? void 0 : O.map((H) => H.value)) ?? [n.attrs.role],
code: l(n, "term") ?? n.attrs.term,
scheme: l(n, "authority") ?? n.attrs.authority
} : null;
}, y = (n) => {
var g;
return {
name: b(n),
// NOTE: webpub requires number but EPUB allows values like "2.2.1"
position: u((g = n.props) == null ? void 0 : g["group-position"])
};
}, w = (n) => {
var E;
const { value: g } = n;
if (/^urn:/i.test(g))
return g;
if (/^doi:/i.test(g))
return `urn:${g}`;
const v = (E = n.props) == null ? void 0 : E["identifier-type"];
if (!v) {
const I = n.attrs.scheme;
return I ? /^(doi|isbn|uuid)$/i.test(I) ? `urn:${I}:${g}` : { scheme: I, value: g } : g;
}
if (v.scheme === C.onix + "codelist5") {
const I = vt[v.value];
if (I)
return `urn:${I}:${g}`;
}
return g;
}, N = Object.groupBy(
d["belongs-to-collection"] ?? [],
(n) => l(n, "collection-type") === "series" ? "series" : "collection"
), L = ((q = p.title) == null ? void 0 : q.find((n) => l(n, "title-type") === "main")) ?? ((_ = p.title) == null ? void 0 : _[0]), T = {
identifier: mt(i),
title: b(L),
sortAs: b((V = (z = L == null ? void 0 : L.props) == null ? void 0 : z["file-as"]) == null ? void 0 : V[0]) ?? ((W = L == null ? void 0 : L.attrs) == null ? void 0 : W["file-as"]) ?? (m == null ? void 0 : m["calibre:title_sort"]),
subtitle: (J = (G = p.title) == null ? void 0 : G.find((n) => l(n, "title-type") === "subtitle")) == null ? void 0 : J.value,
language: (K = p.language) == null ? void 0 : K.map((n) => n.value),
description: u(p.description),
publisher: f((Q = p.publisher) == null ? void 0 : Q[0]),
published: ((Z = (Y = p.date) == null ? void 0 : Y.find((n) => n.attrs.event === "publication")) == null ? void 0 : Z.value) ?? u(p.date),
modified: u(d[C.dcterms + "modified"]) ?? ((et = (tt = p.date) == null ? void 0 : tt.find((n) => n.attrs.event === "modification")) == null ? void 0 : et.value),
subject: (st = p.subject) == null ? void 0 : st.map(f),
belongsTo: {
collection: (rt = N.collection) == null ? void 0 : rt.map(y),
series: ((it = N.series) == null ? void 0 : it.map(y)) ?? (m == null ? void 0 : m["calibre:series"]) ? {
name: m == null ? void 0 : m["calibre:series"],
position: parseFloat(m == null ? void 0 : m["calibre:series_index"])
} : null
},
altIdentifier: (nt = p.identifier) == null ? void 0 : nt.map(w),
source: (ot = p.source) == null ? void 0 : ot.map(w),
// NOTE: not in webpub schema
rights: u(p.rights)
// NOTE: not in webpub schema
}, M = (n) => (g) => {
var E;
const v = new Set((E = g.role) == null ? void 0 : E.map((I) => bt[I] ?? n));
return [v.size ? v : [n], g];
};
for (const [n, g] of [].concat(
((ct = (at = p.creator) == null ? void 0 : at.map(f)) == null ? void 0 : ct.map(M("author"))) ?? [],
((ht = (lt = p.contributor) == null ? void 0 : lt.map(f)) == null ? void 0 : ht.map(M("contributor"))) ?? []
))
for (const v of n)
T[v] ? T[v].push(g) : T[v] = [g];
X(T), T.altIdentifier === T.identifier && delete T.altIdentifier;
const U = {}, B = {};
for (const [n, g] of Object.entries(d))
n.startsWith(C.rendition) ? U[D(n.replace(C.rendition, ""))] = u(g) : n.startsWith(C.media) && (B[D(n.replace(C.media, ""))] = u(g));
return B.duration && (B.duration = F(B.duration)), { metadata: T, rendition: U, media: B };
}, Nt = (i, t = (e) => e) => {
var b;
const { $: e, $$: s, $$$: r } = k(i, S.XHTML), o = (f) => f ? decodeURI(t(f)) : null, a = (f) => (y) => {
var U;
const w = e(y, "a") ?? e(y, "span"), N = e(y, "ol"), L = o(w == null ? void 0 : w.getAttribute("href")), M = { label: R(w) || (w == null ? void 0 : w.getAttribute("title")), href: L, subitems: c(N) };
return f && (M.type = (U = w == null ? void 0 : w.getAttributeNS(S.EPUB, "type")) == null ? void 0 : U.split(/\s/)), M;
}, c = (f, y) => f ? s(f, "li").map(a(y)) : null, h = (f, y) => c(e(f, "ol"), y), p = r(i, "nav");
let d = null, m = null, u = null, l = [];
for (const f of p) {
const y = ((b = f.getAttributeNS(S.EPUB, "type")) == null ? void 0 : b.split(/\s/)) ?? [];
y.includes("toc") ? d ??= h(f) : y.includes("page-list") ? m ??= h(f) : y.includes("landmarks") ? u ??= h(f, !0) : l.push({
label: R(f.firstElementChild),
type: y,
list: h(f)
});
}
return { toc: d, pageList: m, landmarks: u, others: l };
}, Ct = (i, t = (e) => e) => {
const { $: e, $$: s } = k(i, S.NCX), r = (h) => h ? decodeURI(t(h)) : null, o = (h) => {
const p = e(h, "navLabel"), d = e(h, "content"), m = R(p), u = r(d.getAttribute("src"));
if (h.localName === "navPoint") {
const l = s(h, "navPoint");
return { label: m, href: u, subitems: l.length ? l.map(o) : null };
}
return { label: m, href: u };
}, a = (h, p) => s(h, p).map(o), c = (h, p) => {
const d = e(i.documentElement, h);
return d ? a(d, p) : null;
};
return {
toc: c("navMap", "navPoint"),
pageList: c("pageList", "pageTarget"),
others: s(i.documentElement, "navList").map((h) => ({
label: R(e(h, "navLabel")),
list: a(h, "navTarget")
}))
};
}, F = (i) => {
if (!i)
return;
const t = i.split(":").map((a) => parseFloat(a));
if (t.length === 3) {
const [a, c, h] = t;
return a * 60 * 60 + c * 60 + h;
}
if (t.length === 2) {
const [a, c] = t;
return a * 60 + c;
}
const [e, s] = i.split(/(?=[^\d.])/), r = parseFloat(e), o = s === "h" ? 60 * 60 : s === "min" ? 60 : s === "ms" ? 1e-3 : 1;
return r * o;
};
class $t extends EventTarget {
#e;
#s;
#t;
#n;
#i;
#r;
#d = 1;
#f = 1;
#l;
constructor(t, e) {
super(), this.book = t, this.loadXML = e;
}
async #g(t) {
if (this.#s === t)
return;
const e = await this.loadXML(t.href), s = (a) => a ? $(a, t.href) : null, { $: r, $$$: o } = k(e, S.SMIL);
this.#n = -1, this.#i = -1, this.#e = o(e, "par").reduce((a, c) => {
var b;
const h = s((b = r(c, "text")) == null ? void 0 : b.getAttribute("src")), p = r(c, "audio");
if (!h || !p)
return a;
const d = s(p.getAttribute("src")), m = F(p.getAttribute("clipBegin")), u = F(p.getAttribute("clipEnd")), l = a.at(-1);
return (l == null ? void 0 : l.src) === d ? l.items.push({ text: h, begin: m, end: u }) : a.push({ src: d, items: [{ text: h, begin: m, end: u }] }), a;
}, []), this.#s = t;
}
get #h() {
return this.#e[this.#n];
}
get #o() {
var t, e;
return (e = (t = this.#h) == null ? void 0 : t.items) == null ? void 0 : e[this.#i];
}
#a(t) {
console.error(t), this.dispatchEvent(new CustomEvent("error", { detail: t }));
}
#p() {
this.dispatchEvent(new CustomEvent("highlight", { detail: this.#o }));
}
#u() {
this.dispatchEvent(new CustomEvent("unhighlight", { detail: this.#o }));
}
async #c(t, e) {
var a;
this.#m(), this.#n = t, this.#i = e;
const s = (a = this.#h) == null ? void 0 : a.src;
if (!s || !this.#o)
return this.start(this.#t + 1);
const r = URL.createObjectURL(await this.book.loadBlob(s)), o = new Audio(r);
this.#r = o, o.volume = this.#d, o.playbackRate = this.#f, o.addEventListener("timeupdate", () => {
var d, m;
if (o.paused)
return;
const c = o.currentTime, { items: h } = this.#h;
if (c > ((d = this.#o) == null ? void 0 : d.end) && (this.#u(), this.#i === h.length - 1)) {
this.#c(this.#n + 1, 0).catch((u) => this.#a(u));
return;
}
const p = this.#i;
for (; ((m = h[this.#i + 1]) == null ? void 0 : m.begin) <= c; )
this.#i++;
this.#i !== p && this.#p();
}), o.addEventListener("error", () => this.#a(new Error(`Failed to load ${s}`))), o.addEventListener("playing", () => this.#p()), o.addEventListener("ended", () => {
this.#u(), URL.revokeObjectURL(r), this.#r = null, this.#c(t + 1, 0).catch((c) => this.#a(c));
}), this.#l === "paused" ? (this.#p(), o.currentTime = this.#o.begin ?? 0) : o.addEventListener("canplaythrough", () => {
o.currentTime = this.#o.begin ?? 0, this.#l = "playing", o.play().catch((c) => this.#a(c));
}, { once: !0 });
}
async start(t, e = () => !0) {
var a;
(a = this.#r) == null || a.pause();
const s = this.book.sections[t], r = s == null ? void 0 : s.id;
if (!r)
return;
const { mediaOverlay: o } = s;
if (!o)
return this.start(t + 1);
this.#t = t, await this.#g(o);
for (let c = 0; c < this.#e.length; c++) {
const { items: h } = this.#e[c];
for (let p = 0; p < h.length; p++)
if (h[p].text.split("#")[0] === r && e(h[p], p, h))
return this.#c(c, p).catch((d) => this.#a(d));
}
}
pause() {
var t;
this.#l = "paused", (t = this.#r) == null || t.pause();
}
resume() {
var t;
this.#l = "playing", (t = this.#r) == null || t.play().catch((e) => this.#a(e));
}
#m() {
this.#r && (this.#r.pause(), URL.revokeObjectURL(this.#r.src), this.#r = null, this.#u());
}
stop() {
this.#l = "stopped", this.#m();
}
prev() {
this.#i > 0 ? this.#c(this.#n, this.#i - 1) : this.#n > 0 ? this.#c(
this.#n - 1,
this.#e[this.#n - 1].items.length - 1
) : this.#t > 0 && this.start(this.#t - 1, (t, e, s) => e === s.length - 1);
}
next() {
this.#c(this.#n, this.#i + 1);
}
setVolume(t) {
this.#d = t, this.#r && (this.#r.volume = t);
}
setRate(t) {
this.#f = t, this.#r && (this.#r.playbackRate = t);
}
}
const Mt = /([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})/, Ut = (i) => {
for (const t of i.getElementsByTagNameNS(S.DC, "identifier")) {
const [e] = R(t).split(":").slice(-1);
if (Mt.test(e))
return e;
}
return "";
}, mt = (i) => R(
i.getElementById(i.documentElement.getAttribute("unique-identifier")) ?? i.getElementsByTagNameNS(S.DC, "identifier")[0]
), dt = async (i, t, e) => {
const s = new Uint8Array(await e.slice(0, t).arrayBuffer());
t = Math.min(t, s.length);
for (var r = 0; r < t; r++)
s[r] = s[r] ^ i[r % i.length];
return new Blob([s, e.slice(t)], { type: e.type });
}, Bt = async (i) => {
const t = new TextEncoder().encode(i), e = await globalThis.crypto.subtle.digest("SHA-1", t);
return new Uint8Array(e);
}, Ot = (i = Bt) => ({
"http://www.idpf.org/2008/embedding": {
key: (t) => i(mt(t).replaceAll(/[\u0020\u0009\u000d\u000a]/g, "")),
decode: (t, e) => dt(t, 1040, e)
},
"http://ns.adobe.com/pdf/enc#RC": {
key: (t) => {
const e = Ut(t).replaceAll("-", "");
return Uint8Array.from({ length: 16 }, (s, r) => parseInt(e.slice(r * 2, r * 2 + 2), 16));
},
decode: (t, e) => dt(t, 1024, e)
}
});
class kt {
#e = /* @__PURE__ */ new Map();
#s = /* @__PURE__ */ new Map();
#t;
constructor(t) {
this.#t = t;
}
async init(t, e) {
if (!t)
return;
const s = Array.from(
t.getElementsByTagNameNS(S.ENC, "EncryptedData"),
(r) => {
var o, a;
return {
algorithm: (o = r.getElementsByTagNameNS(S.ENC, "EncryptionMethod")[0]) == null ? void 0 : o.getAttribute("Algorithm"),
uri: (a = r.getElementsByTagNameNS(S.ENC, "CipherReference")[0]) == null ? void 0 : a.getAttribute("URI")
};
}
);
for (const { algorithm: r, uri: o } of s) {
if (!this.#s.has(r)) {
const a = this.#t[r];
if (!a) {
console.warn("Unknown encryption algorithm");
continue;
}
const c = await a.key(e);
this.#s.set(r, (h) => a.decode(c, h));
}
this.#e.set(o, r);
}
}
getDecoder(t) {
return this.#s.get(this.#e.get(t)) ?? ((e) => e);
}
}
class xt {
constructor({ opf: t, resolveHref: e }) {
var d, m, u, l, b;
this.opf = t;
const { $: s, $$: r, $$$: o } = k(t, S.OPF), a = s(t.documentElement, "manifest"), c = s(t.documentElement, "spine"), h = r(c, "itemref");
this.manifest = r(a, "item").map(P("href", "id", "media-type", "properties", "media-overlay")).map((f) => {
var y;
return f.href = e(f.href), f.properties = (y = f.properties) == null ? void 0 : y.split(/\s/), f;
}), this.manifestById = new Map(this.manifest.map((f) => [f.id, f])), this.spine = h.map(P("idref", "id", "linear", "properties")).map((f) => {
var y;
return f.properties = (y = f.properties) == null ? void 0 : y.split(/\s/), f;
}), this.pageProgressionDirection = c.getAttribute("page-progression-direction"), this.navPath = (d = this.getItemByProperty("nav")) == null ? void 0 : d.href, this.ncxPath = (m = this.getItemByID(c.getAttribute("toc")) ?? this.manifest.find((f) => f.mediaType === A.NCX)) == null ? void 0 : m.href;
const p = s(t.documentElement, "guide");
p && (this.guide = r(p, "reference").map(P("type", "title", "href")).map(({ type: f, title: y, href: w }) => ({
label: y,
type: f.split(/\s/),
href: e(w)
}))), this.cover = this.getItemByProperty("cover-image") ?? this.getItemByID((u = o(t, "meta").find(Et("name", "cover"))) == null ? void 0 : u.getAttribute("content")) ?? this.getItemByHref((b = (l = this.guide) == null ? void 0 : l.find((f) => f.type.includes("cover"))) == null ? void 0 : b.href), this.cfis = gt(h);
}
getItemByID(t) {
return this.manifestById.get(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 = yt(t), s = (e.parent ?? e).shift();
let r = pt(this.opf, s);
r && r.nodeName !== "idref" && (s.at(-1).id = null, r = pt(this.opf, s));
const o = r == null ? void 0 : r.getAttribute("idref");
return { index: this.spine.findIndex((h) => h.idref === o), anchor: (h) => wt(h, e) };
}
}
class Pt {
#e = /* @__PURE__ */ new Map();
#s = /* @__PURE__ */ new Map();
#t = /* @__PURE__ */ new Map();
eventTarget = new EventTarget();
constructor({ loadText: t, loadBlob: e, resources: s }) {
this.loadText = t, this.loadBlob = e, this.manifest = s.manifest, this.assets = s.manifest;
}
async createURL(t, e, s, r) {
if (!e)
return "";
const o = { data: e, type: s };
Object.defineProperty(o, "name", { value: t });
const a = new CustomEvent("data", { detail: o });
this.eventTarget.dispatchEvent(a);
const c = await a.detail.data, h = await a.detail.type, p = URL.createObjectURL(new Blob([c], { type: h }));
if (this.#e.set(t, p), this.#t.set(t, 1), r) {
const d = this.#s.get(r);
d ? d.push(t) : this.#s.set(r, [t]);
}
return p;
}
ref(t, e) {
const s = this.#s.get(e);
return s != null && s.includes(t) || (this.#t.set(t, this.#t.get(t) + 1), s ? s.push(t) : this.#s.set(e, [t])), this.#e.get(t);
}
unref(t) {
if (!this.#t.has(t))
return;
const e = this.#t.get(t) - 1;
if (e < 1) {
URL.revokeObjectURL(this.#e.get(t)), this.#e.delete(t), this.#t.delete(t);
const s = this.#s.get(t);
if (s)
for (; s.length; )
this.unref(s.pop());
this.#s.delete(t);
} else
this.#t.set(t, e);
}
// load manifest item, recursively loading all resources as needed
async loadItem(t, e = []) {
if (!t)
return null;
const { href: s, mediaType: r } = t, o = A.JS.test(t.mediaType), a = { type: r, isScript: o, allow: !0 }, c = new CustomEvent("load", { detail: a });
if (this.eventTarget.dispatchEvent(c), !await c.detail.allow)
return null;
const p = e.at(-1);
if (this.#e.has(s))
return this.ref(s, p);
if ((o || [A.XHTML, A.HTML, A.CSS, A.SVG].includes(r)) && e.every((u) => u !== s))
return this.loadReplaced(t, e);
const m = Promise.resolve().then(() => this.loadBlob(s));
return this.createURL(s, m, r, p);
}
async loadHref(t, e, s = []) {
if (ft(t))
return t;
const r = $(t, e), o = this.manifest.find((a) => a.href === r);
return o ? this.loadItem(o, s.concat(e)) : t;
}
async loadReplaced(t, e = []) {
var h, p;
const { href: s, mediaType: r } = t, o = e.at(-1);
let a = "";
try {
a = await this.loadText(s);
} catch (d) {
return this.createURL(s, Promise.reject(d), r, o);
}
if (!a)
return null;
if ([A.XHTML, A.HTML, A.SVG].includes(r)) {
let d = new DOMParser().parseFromString(a, r);
if (r === A.XHTML && (d.querySelector("parsererror") || !((h = d.documentElement) != null && h.namespaceURI)) && (console.warn(((p = d.querySelector("parsererror")) == null ? void 0 : p.innerText) ?? "Invalid XHTML"), t.mediaType = A.HTML, d = new DOMParser().parseFromString(a, t.mediaType)), [A.XHTML, A.SVG].includes(t.mediaType)) {
let l = d.firstChild;
for (; l instanceof ProcessingInstruction; ) {
if (l.data) {
const b = await x(
l.data,
/(?:^|\s*)(href\s*=\s*['"])([^'"]*)(['"])/i,
(f, y, w, N) => this.loadHref(w, s, e).then((L) => `${y}${L}${N}`)
);
l.replaceWith(d.createProcessingInstruction(
l.target,
b
));
}
l = l.nextSibling;
}
}
const m = async (l, b) => l.setAttribute(
b,
await this.loadHref(l.getAttribute(b), s, e)
);
for (const l of d.querySelectorAll("link[href]"))
await m(l, "href");
for (const l of d.querySelectorAll("[src]"))
await m(l, "src");
for (const l of d.querySelectorAll("[poster]"))
await m(l, "poster");
for (const l of d.querySelectorAll("object[data]"))
await m(l, "data");
for (const l of d.querySelectorAll("[*|href]:not([href])"))
l.setAttributeNS(S.XLINK, "href", await this.loadHref(
l.getAttributeNS(S.XLINK, "href"),
s,
e
));
for (const l of d.querySelectorAll("style"))
l.textContent && (l.textContent = await this.replaceCSS(l.textContent, s, e));
for (const l of d.querySelectorAll("[style]"))
l.setAttribute(
"style",
await this.replaceCSS(l.getAttribute("style"), s, e)
);
const u = new XMLSerializer().serializeToString(d);
return this.createURL(s, u, t.mediaType, o);
}
const c = r === A.CSS ? await this.replaceCSS(a, s, e) : await this.replaceString(a, s, e);
return this.createURL(s, c, r, o);
}
async replaceCSS(t, e, s = []) {
const r = await x(
t,
/url\(\s*["']?([^'"\n]*?)\s*["']?\s*\)/gi,
(o, a) => this.loadHref(a, e, s).then((c) => `url("${c}")`)
);
return x(
r,
/@import\s*["']([^"'\n]*?)["']/gi,
(o, a) => this.loadHref(a, e, s).then((c) => `@import "${c}"`)
);
}
// find & replace all possible relative paths for all assets without parsing
replaceString(t, e, s = []) {
const r = /* @__PURE__ */ new Map(), o = this.assets.map((c) => {
if (c.href === e)
return;
const h = It(At(e), c.href), p = encodeURI(h), d = "/" + c.href, m = encodeURI(d), u = /* @__PURE__ */ new Set([h, p, d, m]);
for (const l of u)
r.set(l, c);
return Array.from(u);
}).flat().filter((c) => c);
if (!o.length)
return t;
const a = new RegExp(o.map(Lt).join("|"), "g");
return x(t, a, async (c) => this.loadItem(
r.get(c.replace(/^\//, "")),
s.concat(e)
));
}
unloadItem(t) {
this.unref(t == null ? void 0 : t.href);
}
destroy() {
for (const t of this.#e.values())
URL.revokeObjectURL(t);
}
}
const Ht = (i, t) => i.getElementById(t) ?? i.querySelector(`[name="${CSS.escape(t)}"]`), Dt = (i) => {
for (const t of i) {
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";
}
}, Xt = (i) => i ? {
fixedLayout: R(i.querySelector('option[name="fixed-layout"]')),
openToSpread: R(i.querySelector('option[name="open-to-spread"]'))
} : null;
class jt {
parser = new DOMParser();
#e;
#s;
constructor({ loadText: t, loadBlob: e, getSize: s, sha1: r }) {
this.loadText = t, this.loadBlob = e, this.getSize = s, this.#s = new kt(Ot(r));
}
async #t(t) {
const e = await this.loadText(t);
if (!e)
return null;
const s = this.parser.parseFromString(e, A.XML);
if (s.querySelector("parsererror"))
throw new Error(`XML parsing error: ${t}
${s.querySelector("parsererror").innerText}`);
return s;
}
async init() {
const t = await this.#t("META-INF/container.xml");
if (!t)
throw new Error("Failed to load container file");
const e = Array.from(
t.getElementsByTagNameNS(S.CONTAINER, "rootfile"),
P("full-path", "media-type")
).filter((u) => u.mediaType === "application/oebps-package+xml");
if (!e.length)
throw new Error("No package document defined in container");
const s = e[0].fullPath, r = await this.#t(s);
if (!r)
throw new Error("Failed to load package document");
const o = await this.#t("META-INF/encryption.xml");
await this.#s.init(o, r), this.resources = new xt({
opf: r,
resolveHref: (u) => $(u, s)
}), this.#e = new Pt({
loadText: this.loadText,
loadBlob: (u) => Promise.resolve(this.loadBlob(u)).then(this.#s.getDecoder(u)),
resources: this.resources
}), this.transformTarget = this.#e.eventTarget, this.sections = this.resources.spine.map((u, l) => {
const { idref: b, linear: f, properties: y = [] } = u, w = this.resources.getItemByID(b);
return w ? {
id: w.href,
load: () => this.#e.loadItem(w),
unload: () => this.#e.unloadItem(w),
createDocument: () => this.loadDocument(w),
size: this.getSize(w.href),
cfi: this.resources.cfis[l],
linear: f,
pageSpread: Dt(y),
resolveHref: (N) => $(N, w.href),
mediaOverlay: w.mediaOverlay ? this.resources.getItemByID(w.mediaOverlay) : null
} : (console.warn(`Could not find item with ID "${b}" in manifest`), null);
}).filter((u) => u);
const { navPath: a, ncxPath: c } = this.resources;
if (a)
try {
const u = (b) => $(b, a), l = Nt(await this.#t(a), u);
this.toc = l.toc, this.pageList = l.pageList, this.landmarks = l.landmarks;
} catch (u) {
console.warn(u);
}
if (!this.toc && c)
try {
const u = (b) => $(b, c), l = Ct(await this.#t(c), u);
this.toc = l.toc, this.pageList = l.pageList;
} catch (u) {
console.warn(u);
}
this.landmarks ??= this.resources.guide;
const { metadata: h, rendition: p, media: d } = Rt(r);
this.metadata = h, this.rendition = p, this.media = d, this.dir = this.resources.pageProgressionDirection;
const m = Xt(
await this.#t("META-INF/com.apple.ibooks.display-options.xml") ?? await this.#t("META-INF/com.kobobooks.display-options.xml")
);
return m && (m.fixedLayout === "true" && (this.rendition.layout ??= "pre-paginated"), m.openToSpread === "false" && (this.sections.find((u) => u.linear !== "no").pageSpread ??= this.dir === "rtl" ? "left" : "right")), this;
}
async loadDocument(t) {
const e = await this.loadText(t.href);
return this.parser.parseFromString(e, t.mediaType);
}
getMediaOverlay() {
return new $t(this, this.#t.bind(this));
}
resolveCFI(t) {
return this.resources.resolveCFI(t);
}
resolveHref(t) {
const [e, s] = t.split("#"), r = this.resources.getItemByHref(decodeURI(e));
return r ? { index: this.resources.spine.findIndex(({ idref: c }) => c === r.id), anchor: s ? (c) => Ht(c, 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 ft(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 = this.#e) == null || t.destroy();
}
}
export {
jt as EPUB
};