@prose-reader/streamer 1.276.0 → 1.277.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,279 +1,653 @@
1
- import { XmlDocument as b, XmlTextNode as ae, XmlElement as ce } from "xmldoc";
2
- import { urlJoin as W, isXmlBasedMimeType as de, parseContentType as le, detectMimeTypeFromName as O } from "@prose-reader/shared";
3
- import { Subject as P, mergeMap as D, EMPTY as X, pairwise as pe, filter as R, startWith as me, from as L, tap as j, catchError as S, switchMap as T, merge as H, first as V, takeUntil as fe, map as $, ignoreElements as ue, BehaviorSubject as he, distinctUntilChanged as ge, shareReplay as ye, NEVER as _, timer as be, finalize as q, of as G, lastValueFrom as K } from "rxjs";
4
- let E = !1;
5
- const w = {
6
- enable: (e) => {
7
- E = e;
8
- },
9
- // biome-ignore lint/suspicious/noExplicitAny: TODO
10
- log: (...e) => {
11
- E && console.log("[prose-reader-streamer]", ...e);
12
- },
13
- // biome-ignore lint/suspicious/noExplicitAny: TODO
14
- debug: (...e) => {
15
- E && console.debug("[prose-reader-streamer]", ...e);
16
- },
17
- // biome-ignore lint/suspicious/noExplicitAny: TODO
18
- warn: (...e) => {
19
- E && console.warn("[prose-reader-streamer]", ...e);
20
- },
21
- // biome-ignore lint/suspicious/noExplicitAny: TODO
22
- error: (...e) => {
23
- console.error(...e);
24
- }
25
- }, we = (e) => {
26
- const t = e.descendantWithPath("head")?.childrenNamed("meta").find((i) => i.attr.name === "calibre:cover");
27
- return !!(t && t.attr.name === "calibre:cover");
28
- }, ve = (e) => e.descendantWithPath("body")?.descendantWithPath("div")?.childrenNamed("svg")?.find(
29
- (t) => t.attr.width === "100%" && t.attr.preserveAspectRatio === "none"
30
- ), $e = ({ archive: e, resourcePath: t }) => async (i) => {
31
- const r = Object.values(e.records).find(
32
- (n) => n.uri === t && !n.dir
33
- );
34
- if (r && !r.dir && r.basename.endsWith(".xhtml")) {
35
- const n = i.body ?? await r.string(), s = new b(n);
36
- if (we(s)) {
37
- const o = ve(s);
38
- return o && delete o.attr.preserveAspectRatio, {
39
- ...i,
40
- body: s?.toString()
41
- };
1
+ import { Report as se, detectMimeTypeFromName as j, isXmlBasedMimeType as ie, parseContentType as ae, urlJoin as I } from "@prose-reader/shared";
2
+ import { XmlDocument as y, XmlTextNode as ce, XmlElement as de } from "xmldoc";
3
+ import { Subject as C, mergeMap as O, EMPTY as B, pairwise as le, filter as R, startWith as pe, from as T, tap as P, catchError as W, switchMap as A, merge as X, first as V, takeUntil as me, map as v, ignoreElements as fe, BehaviorSubject as ue, distinctUntilChanged as he, shareReplay as ge, NEVER as H, timer as ye, finalize as _, of as G, lastValueFrom as q } from "rxjs";
4
+ const D = (n, e) => {
5
+ const s = n.split(/(\d+)/), r = e.split(/(\d+)/);
6
+ for (let t = 0, o = s.length; t < o; t++)
7
+ if (s[t] !== r[t])
8
+ return s[t]?.match(/\d/) ? +(s[t] || "") - +(r[t] || "") : (s[t] || "").localeCompare(r[t] || "");
9
+ return 1;
10
+ }, $ = (n) => n.substring(n.lastIndexOf("/") + 1) || n, J = (n) => n.endsWith("/") ? n.slice(0, -1) : n, be = (n) => {
11
+ const e = n.lastIndexOf("/");
12
+ return e >= 0 ? n.substring(0, e) : "";
13
+ }, it = async (n, { orderByAlpha: e, name: s } = {}) => {
14
+ let r = n;
15
+ return e && (r = r.slice().sort((t, o) => D(t.name, o.name))), {
16
+ filename: s || "",
17
+ records: r.map((t) => ({
18
+ dir: t.isDir,
19
+ basename: $(t.name),
20
+ uri: t.name,
21
+ blob: async () => new Blob([await t.data()]),
22
+ string: async () => {
23
+ const o = await t.data();
24
+ return String.fromCharCode.apply(
25
+ null,
26
+ Array.from(new Uint16Array(o))
27
+ );
28
+ },
29
+ size: t.size
30
+ })),
31
+ close: () => Promise.resolve()
32
+ };
33
+ }, we = "@prose-reader/streamer", m = se.namespace(we, !1, {
34
+ color: "#ffae42"
35
+ }), ve = (n) => {
36
+ const e = {};
37
+ for (const r of n) {
38
+ const t = r.split("/");
39
+ let o = e;
40
+ for (let i = 0; i < t.length; i++) {
41
+ const a = t[i];
42
+ a !== void 0 && (o[a] || (o[a] = {}), o = o[a]);
42
43
  }
43
44
  }
44
- return i;
45
- }, xe = ({ archive: e, resourcePath: t }) => async (i) => $e({ archive: e, resourcePath: t })(i), Fe = ({ archive: e, resourcePath: t }) => async (i) => {
46
- const r = Object.values(e.records).find(
47
- (n) => n.uri === t && !n.dir
45
+ const s = (r, t = "") => Object.keys(r).sort().map((o, i, a) => {
46
+ const l = i === a.length - 1, c = t + (l ? "└── " : "├── "), d = t + (l ? " " : "│ "), p = r[o];
47
+ return p && Object.keys(p).length > 0 ? `${c}${o}/
48
+ ${s(p, d)}` : `${c}${o}`;
49
+ }).join(`
50
+ `);
51
+ return s(e);
52
+ }, at = async (n, { orderByAlpha: e, name: s } = {}) => {
53
+ let r = Object.values(n.files);
54
+ e && (r = r.slice().sort((o, i) => D(o.name, i.name)));
55
+ const t = {
56
+ filename: s || "",
57
+ records: r.map((o) => ({
58
+ dir: o.dir,
59
+ basename: $(o.name),
60
+ uri: o.name,
61
+ blob: () => o.async("blob"),
62
+ string: () => o.async("string"),
63
+ ...o.internalStream && {
64
+ stream: o.internalStream
65
+ },
66
+ // this is private API
67
+ // @ts-expect-error
68
+ size: o._data.uncompressedSize
69
+ })),
70
+ close: () => Promise.resolve()
71
+ };
72
+ if (m.log("Generated archive", t), process.env.NODE_ENV === "development" && m.isEnabled()) {
73
+ const o = ve(r.map((i) => i.name));
74
+ m.groupCollapsed(...m.getGroupArgs("Archive folder structure")), m.log(`
75
+ ${o}`), m.groupEnd();
76
+ }
77
+ return t;
78
+ }, ct = async (n, { name: e } = {}) => {
79
+ const s = await n.getFilesArray(), r = {
80
+ close: () => n.close(),
81
+ filename: e ?? "",
82
+ records: s.map((t) => ({
83
+ dir: !1,
84
+ basename: t.file.name,
85
+ size: t.file.size,
86
+ uri: `${t.path}${t.file.name}`,
87
+ blob: async () => await t.file.extract(),
88
+ string: async () => (await t.file.extract()).text()
89
+ }))
90
+ };
91
+ return m.log("Generated archive", r), r;
92
+ }, dt = async (n, {
93
+ mimeType: e,
94
+ direction: s
95
+ } = { mimeType: "text/plain" }) => {
96
+ const r = `
97
+ <?xml version="1.0" encoding="UTF-8"?>
98
+ <package xmlns="http://www.idpf.org/2007/opf" version="3.0" xml:lang="ja" prefix="rendition: http://www.idpf.org/vocab/rendition/#"
99
+ unique-identifier="ootuya-id">
100
+ <metadata xmlns:opf="http://www.idpf.org/2007/opf" xmlns:dc="http://purl.org/dc/elements/1.1/"
101
+ xmlns:dcterms="http://purl.org/dc/terms/">
102
+ <meta property="rendition:layout">reflowable</meta>
103
+ </metadata>
104
+ <manifest>
105
+ <item id="p01" href="p01.txt" media-type="text/plain"/>
106
+ </manifest>
107
+ <spine page-progression-direction="${s ?? "ltr"}">
108
+ <itemref idref="p01" />
109
+ </spine>
110
+ </package>
111
+ `;
112
+ return {
113
+ filename: "content.txt",
114
+ records: [
115
+ {
116
+ dir: !1,
117
+ basename: $("generated.opf"),
118
+ uri: "generated.opf",
119
+ blob: async () => new Blob([r]),
120
+ string: async () => r,
121
+ size: 0
122
+ },
123
+ {
124
+ dir: !1,
125
+ basename: $("p01.txt"),
126
+ uri: "p01.txt",
127
+ blob: async () => typeof n == "string" ? new Blob([n]) : n,
128
+ string: async () => typeof n == "string" ? n : n.text(),
129
+ size: typeof n == "string" ? n.length : n.size,
130
+ encodingFormat: e
131
+ }
132
+ ],
133
+ close: () => Promise.resolve()
134
+ };
135
+ }, lt = async (n, e) => {
136
+ const s = `
137
+ <?xml version="1.0" encoding="UTF-8"?><package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="bookid">
138
+ <metadata>
139
+ <meta property="rendition:layout">${e?.useRenditionFlow ? "reflowable" : "pre-paginated"}</meta>
140
+ ${e?.useRenditionFlow ? '<meta property="rendition:flow">scrolled-continuous</meta>' : ""}
141
+ </metadata>
142
+ <manifest>
143
+ ${n.map(
144
+ (o) => `<item id="${$(o)}" href="${o}" media-type="${j(o)}"/>`
145
+ ).join(`
146
+ `)}
147
+ </manifest>
148
+ <spine>
149
+ ${n.map((o) => `<itemref idref="${$(o)}" />`).join(`
150
+ `)}
151
+ </spine>
152
+ </package>
153
+ `, r = n.map((o) => ({
154
+ dir: !1,
155
+ basename: $(o),
156
+ encodingFormat: j(o),
157
+ uri: o,
158
+ size: 100 / n.length,
159
+ blob: async () => (await fetch(o)).blob(),
160
+ string: async () => ""
161
+ }));
162
+ return {
163
+ filename: "",
164
+ records: [{
165
+ dir: !1,
166
+ basename: "content.opf",
167
+ uri: "content.opf",
168
+ size: 0,
169
+ blob: async () => new Blob(),
170
+ string: async () => s
171
+ }, ...r],
172
+ close: () => Promise.resolve()
173
+ };
174
+ }, pt = ({
175
+ enableReport: n
176
+ } = {}) => {
177
+ m.enable(!!n);
178
+ }, F = (n) => {
179
+ const s = Object.values(n.records).filter(
180
+ (r) => !r.dir
181
+ ).find((r) => r.uri.endsWith(".opf"));
182
+ return {
183
+ data: s,
184
+ basePath: s?.uri.substring(0, s.uri.lastIndexOf("/")) || ""
185
+ };
186
+ }, $e = ({ archive: n }) => async (e) => {
187
+ const s = n.records.find(
188
+ (t) => t.basename.toLowerCase() === "com.apple.ibooks.display-options.xml"
48
189
  );
49
- if (r && !r.dir && r.basename.endsWith(".css")) {
50
- const s = (i.body ?? await r.string()).replaceAll(
51
- "-webkit-writing-mode",
52
- "writing-mode"
53
- );
190
+ if (!s || s.dir)
191
+ return e;
192
+ const r = await (await s.blob()).text();
193
+ try {
194
+ const i = new y(r).childNamed("platform")?.childrenNamed("option")?.find((a) => a.attr.name === "fixed-layout")?.val || "false";
54
195
  return {
55
- ...i,
56
- body: s
196
+ ...e,
197
+ renditionLayout: i === "true" ? "pre-paginated" : e.renditionLayout
57
198
  };
199
+ } catch (t) {
200
+ return console.error(
201
+ `Unable to parse com.apple.ibooks.display-options.xml for content
202
+ `,
203
+ r
204
+ ), console.error(t), e;
58
205
  }
59
- return i;
60
- }, A = (e) => {
61
- const i = Object.values(e.records).filter(
62
- (r) => !r.dir
63
- ).find((r) => r.uri.endsWith(".opf"));
206
+ }, xe = async (n) => {
207
+ const e = {
208
+ renditionLayout: void 0
209
+ };
210
+ return await Promise.all(
211
+ n.records.map(async (s) => {
212
+ if (s.uri.endsWith("com.kobobooks.display-options.xml") && !s.dir) {
213
+ const t = new y(await s.string()).childNamed("platform")?.childNamed("option");
214
+ t?.attr?.name === "fixed-layout" && t.val === "true" && (e.renditionLayout = "pre-paginated");
215
+ }
216
+ })
217
+ ), e;
218
+ }, Fe = ({ archive: n }) => async (e) => {
219
+ const s = await xe(n);
220
+ return {
221
+ ...e,
222
+ renditionLayout: e.renditionLayout ?? s.renditionLayout
223
+ };
224
+ }, Ee = ({ archive: n, baseUrl: e }) => async () => {
225
+ const s = Object.values(n.records).filter((r) => !r.dir);
64
226
  return {
65
- data: i,
66
- basePath: i?.uri.substring(0, i.uri.lastIndexOf("/")) || ""
227
+ filename: n.filename,
228
+ title: n.records.find(({ dir: r }) => r)?.basename.replace(/\/$/, "") || n.filename,
229
+ renditionLayout: void 0,
230
+ renditionSpread: "auto",
231
+ readingDirection: "ltr",
232
+ spineItems: s.filter((r) => !r.basename.endsWith(".db")).map((r, t) => {
233
+ const o = e || (/^https?:\/\//.test(r.uri) ? "" : "file://");
234
+ return {
235
+ // some books such as cbz can have same basename inside different sub folder
236
+ // we need to make sure to have unique index
237
+ // /chap01/01.png, /chap02/01.png, etc
238
+ id: `${t}.${r.basename}`,
239
+ index: t,
240
+ href: encodeURI(`${o}${r.uri}`),
241
+ renditionLayout: void 0,
242
+ progressionWeight: 1 / s.length,
243
+ pageSpreadLeft: void 0,
244
+ pageSpreadRight: void 0,
245
+ mediaType: r.encodingFormat
246
+ };
247
+ }),
248
+ items: s.map((r, t) => ({
249
+ id: `${t}.${r.basename}`,
250
+ href: encodeURI(`${e}${r.uri}`)
251
+ }))
67
252
  };
68
- }, Q = async ({
69
- archive: e
253
+ }, Y = async ({
254
+ archive: n
70
255
  }) => {
71
- const { data: t, basePath: i } = A(e) || {}, r = await t?.string();
256
+ const { data: e, basePath: s } = F(n) || {}, r = await e?.string();
72
257
  if (!r) return [];
73
- const n = new b(r), s = n.childNamed("manifest"), a = n.childNamed("spine")?.childrenNamed("itemref").map((c) => c.attr.idref), d = s?.childrenNamed("item").filter((c) => a.includes(c.attr.id || "")) || [];
74
- return e.records.filter((c) => d.find((l) => i ? `${i}/${l.attr.href}` === c.uri : `${l.attr.href}` === c.uri));
75
- }, x = (e) => e.substring(e.lastIndexOf("/") + 1) || e, J = (e) => e.endsWith("/") ? e.slice(0, -1) : e, Ie = (e) => {
76
- const t = e.lastIndexOf("/");
77
- return t >= 0 ? e.substring(0, t) : "";
78
- }, Z = (e) => e ? e.children.map((t) => t instanceof ae ? t.text : t instanceof ce ? Z(t) : "").join("").trim() : "", ee = (e, { basePath: t, baseUrl: i }) => {
258
+ const t = new y(r), o = t.childNamed("manifest"), a = t.childNamed("spine")?.childrenNamed("itemref").map((d) => d.attr.idref), l = o?.childrenNamed("item").filter((d) => a.includes(d.attr.id || "")) || [];
259
+ return n.records.filter((d) => l.find((p) => s ? `${s}/${p.attr.href}` === d.uri : `${p.attr.href}` === d.uri));
260
+ }, Ne = (n) => {
261
+ const e = n.attr.properties?.split(" ") || [];
262
+ let s;
263
+ return e.find((r) => r === "rendition:layout-reflowable") && (s = "reflowable"), e.find((r) => r === "rendition:layout-pre-paginated") && (s = "pre-paginated"), {
264
+ renditionLayout: s,
265
+ pageSpreadLeft: e.some((r) => r === "page-spread-left") || void 0,
266
+ pageSpreadRight: e.some((r) => r === "page-spread-right") || void 0
267
+ };
268
+ }, Ae = (n, e, s) => {
269
+ const r = n.attr.href || "", t = s?.(n);
270
+ return {
271
+ href: e ? `${t}${e}/${r}` : `${t}${r}`,
272
+ id: n.attr.id || "",
273
+ mediaType: n.attr["media-type"]
274
+ };
275
+ }, Q = (n, e, s) => {
276
+ const r = n.childNamed("manifest"), { basePath: t } = F(e) || {};
277
+ return r?.childrenNamed("item")?.map((o) => Ae(o, t, s)) || [];
278
+ }, Ie = ({ archive: n, baseUrl: e }) => async (s) => {
279
+ const { data: r, basePath: t } = F(n) || {};
280
+ if (!r)
281
+ return s;
282
+ const o = await r.string();
283
+ m.groupCollapsed(...m.getGroupArgs("OPF data")), m.log("data", o), m.groupEnd();
284
+ const i = new y(o), a = i.childNamed("metadata"), l = i.childNamed("manifest"), c = i.childNamed("spine"), d = i.childNamed("guide"), p = a?.childNamed("dc:title"), g = a?.childrenNamed("meta") || [], b = g.find(
285
+ (f) => f.attr.property === "rendition:layout"
286
+ ), E = g.find(
287
+ (f) => f.attr.property === "rendition:flow"
288
+ ), u = g.find(
289
+ (f) => f.attr.property === "rendition:spread"
290
+ ), L = b?.val, h = E?.val, x = u?.val, S = p?.val || n.records.find(({ dir: f }) => f)?.basename || "", ne = c?.attr["page-progression-direction"], re = (await Y({ archive: n })).reduce(
291
+ (f, N) => N.size + f,
292
+ 0
293
+ );
294
+ return {
295
+ filename: n.filename,
296
+ renditionLayout: L,
297
+ renditionFlow: h || "auto",
298
+ renditionSpread: x,
299
+ title: S,
300
+ readingDirection: ne || "ltr",
301
+ /**
302
+ * @see https://www.w3.org/TR/epub/#sec-itemref-elem
303
+ */
304
+ spineItems: c?.childrenNamed("itemref").map((f, N) => {
305
+ const w = l?.childrenNamed("item").find((k) => k.attr.id === f?.attr.idref), M = w?.attr.href || "", oe = n.records.find((k) => k.uri.endsWith(M))?.size || 0, U = e || (/^https?:\/\//.test(M) ? "" : "file://"), z = Ne(f);
306
+ return {
307
+ ...z,
308
+ id: w?.attr.id || "",
309
+ index: N,
310
+ href: w?.attr.href?.startsWith("https://") ? w?.attr.href : t ? `${U}${t}/${w?.attr.href}` : `${U}${w?.attr.href}`,
311
+ renditionLayout: z.renditionLayout ?? L,
312
+ progressionWeight: oe / re,
313
+ // size: itemSize
314
+ mediaType: w?.attr["media-type"]
315
+ };
316
+ }) || [],
317
+ items: Q(i, n, (f) => {
318
+ const N = f.attr.href || "";
319
+ return /^https?:\/\//.test(N) ? "" : e || "file://";
320
+ }),
321
+ guide: d?.childrenNamed("reference").map((f) => ({
322
+ href: f.attr.href || "",
323
+ title: f.attr.title || "",
324
+ type: f.attr.type
325
+ }))
326
+ };
327
+ }, Te = (n) => {
328
+ const e = n.descendantWithPath("head")?.childrenNamed("meta").find((s) => s.attr.name === "viewport");
329
+ return !!(e && e.attr.name === "viewport");
330
+ }, We = (n) => n.reduce(async (e, s) => {
331
+ if (!await e || !ie({
332
+ mimeType: s.encodingFormat,
333
+ uri: s.uri
334
+ }))
335
+ return !1;
336
+ const t = s.dir ? null : await s.string();
337
+ return t ? Te(new y(t)) : !1;
338
+ }, Promise.resolve(!0)), Le = ({ archive: n }) => async (e) => {
339
+ if (e.renditionLayout === "reflowable" && e.spineItems.every((r) => r.renditionLayout === "reflowable")) {
340
+ const r = await Y({ archive: n });
341
+ if (await We(r))
342
+ return {
343
+ ...e,
344
+ spineItems: e.spineItems.map((o) => ({
345
+ ...o,
346
+ renditionLayout: "pre-paginated"
347
+ })),
348
+ renditionLayout: "pre-paginated"
349
+ };
350
+ }
351
+ return e;
352
+ }, Se = ({ archive: n }) => async (e) => {
353
+ const s = n.records.find(
354
+ (o) => o.basename.toLowerCase() === "comicinfo.xml" && !o.dir
355
+ );
356
+ if (!s || s.dir)
357
+ return e;
358
+ const r = {
359
+ ...e,
360
+ spineItems: e.spineItems.filter((o) => !o.id.toLowerCase().endsWith("comicinfo.xml")).map((o, i, a) => ({
361
+ ...o,
362
+ progressionWeight: 1 / a.length
363
+ }))
364
+ }, t = await s.string();
365
+ try {
366
+ const i = new y(t).childNamed("Manga")?.val || "unknown";
367
+ return {
368
+ ...r,
369
+ readingDirection: i === "YesAndRightToLeft" ? "rtl" : "ltr"
370
+ };
371
+ } catch (o) {
372
+ return console.error(`Unable to parse comicinfo.xml for content
373
+ `, t), console.error(o), r;
374
+ }
375
+ }, ke = (n) => n.records.some((e) => e.basename.endsWith(".opf")), Ce = ({ archive: n }) => async (e) => ke(n) ? e : {
376
+ ...e,
377
+ spineItems: e.spineItems.map((r) => {
378
+ const t = n.records.find(
379
+ (i) => decodeURI(r.href).endsWith(i.uri)
380
+ ), o = ae(t?.encodingFormat ?? "") ?? j(t?.basename ?? "");
381
+ return {
382
+ ...r,
383
+ renditionLayout: o?.startsWith("image/") ? "pre-paginated" : r.renditionLayout
384
+ };
385
+ })
386
+ }, Z = (n) => n ? n.children.map((e) => e instanceof ce ? e.text : e instanceof de ? Z(e) : "").join("").trim() : "", ee = (n, { basePath: e, baseUrl: s }) => {
79
387
  const r = {
80
388
  contents: [],
81
389
  path: "",
82
390
  href: "",
83
391
  title: ""
84
392
  };
85
- let n = e.childNamed("span") || e.childNamed("a");
86
- r.title = (n?.attr.title || n?.val.trim() || Z(n)) ?? "";
87
- let s = n?.name;
88
- s !== "a" && (n = e.descendantWithPath(`${s}.a`), n && (s = n.name.toLowerCase())), s === "a" && n?.attr.href && (r.path = W(t, n.attr.href), r.href = W(i, t, n.attr.href));
89
- const o = e.childNamed("ol");
90
- if (o) {
91
- const a = o.childrenNamed("li");
393
+ let t = n.childNamed("span") || n.childNamed("a");
394
+ r.title = (t?.attr.title || t?.val.trim() || Z(t)) ?? "";
395
+ let o = t?.name;
396
+ o !== "a" && (t = n.descendantWithPath(`${o}.a`), t && (o = t.name.toLowerCase())), o === "a" && t?.attr.href && (r.path = I(e, t.attr.href), r.href = I(s, e, t.attr.href));
397
+ const i = n.childNamed("ol");
398
+ if (i) {
399
+ const a = i.childrenNamed("li");
92
400
  a && a.length > 0 && (r.contents = a.map(
93
- (d) => ee(d, { basePath: t, baseUrl: i })
401
+ (l) => ee(l, { basePath: e, baseUrl: s })
94
402
  ));
95
403
  }
96
404
  return r;
97
- }, Ne = (e, { basePath: t, baseUrl: i }) => {
405
+ }, Re = (n, { basePath: e, baseUrl: s }) => {
98
406
  const r = [];
99
- let n;
100
- return e.descendantWithPath("body.nav.ol") ? n = e.descendantWithPath("body.nav.ol")?.children : e.descendantWithPath("body.section.nav.ol") && (n = e.descendantWithPath("body.section.nav.ol")?.children), n && n.length > 0 && n.filter((s) => s.name === "li").forEach((s) => {
101
- r.push(ee(s, { basePath: t, baseUrl: i }));
407
+ let t;
408
+ return n.descendantWithPath("body.nav.ol") ? t = n.descendantWithPath("body.nav.ol")?.children : n.descendantWithPath("body.section.nav.ol") && (t = n.descendantWithPath("body.section.nav.ol")?.children), t && t.length > 0 && t.filter((o) => o.name === "li").forEach((o) => {
409
+ r.push(ee(o, { basePath: e, baseUrl: s }));
102
410
  }), r;
103
- }, Te = async (e, t, { baseUrl: i }) => {
104
- const r = e.childNamed("manifest")?.childrenNamed("item").find((n) => n.attr.properties === "nav");
411
+ }, Pe = async (n, e, { baseUrl: s }) => {
412
+ const r = n.childNamed("manifest")?.childrenNamed("item").find((t) => t.attr.properties === "nav");
105
413
  if (r) {
106
- const n = Object.values(t.records).find(
107
- (s) => s.uri.endsWith(r.attr.href || "")
414
+ const t = Object.values(e.records).find(
415
+ (o) => o.uri.endsWith(r.attr.href || "")
108
416
  );
109
- if (n && !n.dir) {
110
- const s = new b(await n.string()), o = Ie(n.uri);
111
- return Ne(s, { basePath: o, baseUrl: i });
417
+ if (t && !t.dir) {
418
+ const o = new y(await t.string()), i = be(t.uri);
419
+ return Re(o, { basePath: i, baseUrl: s });
112
420
  }
113
421
  }
114
- }, te = (e, {
115
- opfBasePath: t,
116
- baseUrl: i,
422
+ }, te = (n, {
423
+ opfBasePath: e,
424
+ baseUrl: s,
117
425
  prefix: r
118
426
  }) => {
119
- const n = e?.childNamed(`${r}content`)?.attr.src || "", s = {
120
- title: e?.descendantWithPath(`${r}navLabel.${r}text`)?.val || "",
121
- path: W(t, n),
122
- href: W(i, t, n),
427
+ const t = n?.childNamed(`${r}content`)?.attr.src || "", o = {
428
+ title: n?.descendantWithPath(`${r}navLabel.${r}text`)?.val || "",
429
+ path: I(e, t),
430
+ href: I(s, e, t),
123
431
  contents: []
124
- }, o = e.childrenNamed(`${r}navPoint`);
125
- return o && o.length > 0 && (s.contents = o.map(
126
- (a) => te(a, { opfBasePath: t, baseUrl: i, prefix: r })
127
- )), s;
128
- }, We = (e, { opfBasePath: t, baseUrl: i }) => {
129
- const r = [], n = e.name;
130
- let s = "";
131
- return n.indexOf(":") !== -1 && (s = `${n.split(":")[0]}:`), e.childNamed(`${s}navMap`)?.childrenNamed(`${s}navPoint`).forEach((o) => {
132
- r.push(te(o, { opfBasePath: t, baseUrl: i, prefix: s }));
432
+ }, i = n.childrenNamed(`${r}navPoint`);
433
+ return i && i.length > 0 && (o.contents = i.map(
434
+ (a) => te(a, { opfBasePath: e, baseUrl: s, prefix: r })
435
+ )), o;
436
+ }, je = (n, { opfBasePath: e, baseUrl: s }) => {
437
+ const r = [], t = n.name;
438
+ let o = "";
439
+ return t.indexOf(":") !== -1 && (o = `${t.split(":")[0]}:`), n.childNamed(`${o}navMap`)?.childrenNamed(`${o}navPoint`).forEach((i) => {
440
+ r.push(te(i, { opfBasePath: e, baseUrl: s, prefix: o }));
133
441
  }), r;
134
- }, Ae = async ({
135
- opfData: e,
136
- opfBasePath: t,
137
- baseUrl: i,
442
+ }, Oe = async ({
443
+ opfData: n,
444
+ opfBasePath: e,
445
+ baseUrl: s,
138
446
  archive: r
139
447
  }) => {
140
- const s = e.childNamed("spine")?.attr.toc;
141
- if (s) {
142
- const o = e.childNamed("manifest")?.childrenNamed("item").find((a) => a.attr.id === s);
143
- if (o) {
144
- const a = `${t}${t === "" ? "" : "/"}${o.attr.href}`, d = Object.values(r.records).find(
145
- (p) => p.uri.endsWith(a)
448
+ const o = n.childNamed("spine")?.attr.toc;
449
+ if (o) {
450
+ const i = n.childNamed("manifest")?.childrenNamed("item").find((a) => a.attr.id === o);
451
+ if (i) {
452
+ const a = `${e}${e === "" ? "" : "/"}${i.attr.href}`, l = Object.values(r.records).find(
453
+ (c) => c.uri.endsWith(a)
146
454
  );
147
- if (d && !d.dir) {
148
- const p = new b(await d.string());
149
- return We(p, { opfBasePath: t, baseUrl: i });
455
+ if (l && !l.dir) {
456
+ const c = new y(await l.string());
457
+ return je(c, { opfBasePath: e, baseUrl: s });
150
458
  }
151
459
  }
152
460
  }
153
- }, Ee = async (e, t, { baseUrl: i }) => {
154
- const { basePath: r } = A(t) || {}, n = await Ae({
155
- opfData: e,
156
- opfBasePath: r,
157
- archive: t,
158
- baseUrl: i
461
+ }, De = async (n, e, { baseUrl: s }) => {
462
+ const { basePath: r } = F(e) || {}, t = await Pe(n, e, {
463
+ baseUrl: s
159
464
  });
160
- return n || await Te(e, t, {
161
- baseUrl: i
465
+ if (t)
466
+ return t;
467
+ const o = await Oe({
468
+ opfData: n,
469
+ opfBasePath: r,
470
+ archive: e,
471
+ baseUrl: s
162
472
  });
163
- }, Le = (e) => {
164
- const t = e.attr.properties?.split(" ") || [];
165
- let i;
166
- return t.find((r) => r === "rendition:layout-reflowable") && (i = "reflowable"), t.find((r) => r === "rendition:layout-pre-paginated") && (i = "pre-paginated"), {
167
- renditionLayout: i,
168
- pageSpreadLeft: t.some((r) => r === "page-spread-left") || void 0,
169
- pageSpreadRight: t.some((r) => r === "page-spread-right") || void 0
170
- };
171
- }, Se = (e, t, i) => {
172
- const r = e.attr.href || "", n = i?.(e);
173
- return {
174
- href: t ? `${n}${t}/${r}` : `${n}${r}`,
175
- id: e.attr.id || "",
176
- mediaType: e.attr["media-type"]
473
+ if (o)
474
+ return o;
475
+ }, Me = (n, { baseUrl: e }) => {
476
+ const s = [...n.records].sort(
477
+ (t, o) => D(t.uri, o.uri)
478
+ ), r = (t, o, i, a, l) => {
479
+ const c = t.find((g) => g.title === o), [d, ...p] = i;
480
+ return c ? d ? [
481
+ ...t.filter((b) => b !== c),
482
+ {
483
+ ...c,
484
+ contents: [
485
+ ...c.contents,
486
+ ...r(
487
+ c.contents,
488
+ d,
489
+ p,
490
+ a,
491
+ l
492
+ )
493
+ ]
494
+ }
495
+ ] : c.path.split("/").length > l.split("/").length ? [
496
+ ...t.filter((b) => b !== c),
497
+ {
498
+ ...c,
499
+ path: l,
500
+ href: a
501
+ }
502
+ ] : t : d ? [
503
+ ...t,
504
+ {
505
+ contents: r(
506
+ [],
507
+ d,
508
+ p,
509
+ a,
510
+ l
511
+ ),
512
+ href: a,
513
+ path: l,
514
+ title: o
515
+ }
516
+ ] : [
517
+ ...t,
518
+ {
519
+ contents: [],
520
+ href: a,
521
+ path: l,
522
+ title: o
523
+ }
524
+ ];
177
525
  };
178
- }, ne = (e, t, i) => {
179
- const r = e.childNamed("manifest"), { basePath: n } = A(t) || {};
180
- return r?.childrenNamed("item")?.map((s) => Se(s, n, i)) || [];
181
- }, ke = ({ archive: e, baseUrl: t }) => async (i) => {
182
- const { data: r, basePath: n } = A(e) || {};
183
- if (!r)
184
- return i;
185
- const s = await r.string();
186
- w.log("data", s);
187
- const o = new b(s), a = await Ee(o, e, { baseUrl: t }) || [], d = o.childNamed("metadata"), p = o.childNamed("manifest"), c = o.childNamed("spine"), l = o.childNamed("guide"), m = d?.childNamed("dc:title"), h = d?.childrenNamed("meta") || [], y = h.find(
188
- (f) => f.attr.property === "rendition:layout"
189
- ), u = h.find(
190
- (f) => f.attr.property === "rendition:flow"
191
- ), F = h.find(
192
- (f) => f.attr.property === "rendition:spread"
193
- ), g = y?.val, I = u?.val, k = F?.val, re = m?.val || e.records.find(({ dir: f }) => f)?.basename || "", ie = c?.attr["page-progression-direction"], se = (await Q({ archive: e })).reduce(
194
- (f, N) => N.size + f,
195
- 0
196
- );
197
- return {
198
- filename: e.filename,
526
+ return s.reduce((t, o) => {
527
+ if (o.dir) return t;
528
+ const i = o.uri.split("/").slice(0, -1), [a, ...l] = i;
529
+ if (!a) return t;
530
+ const c = I(e, encodeURI(o.uri)).replace(/\/$/, ""), d = o.uri.replace(/\/$/, "");
531
+ return r(t, a, l, c, d);
532
+ }, []);
533
+ }, Ue = async (n, { baseUrl: e }) => {
534
+ const { data: s } = F(n) || {};
535
+ if (s && !s.dir) {
536
+ const t = new y(await s.string());
537
+ return await De(t, n, { baseUrl: e }) || [];
538
+ }
539
+ const r = Me(n, { baseUrl: e });
540
+ if (r.length !== 0)
541
+ return r;
542
+ }, ze = ({ archive: n, baseUrl: e }) => async (s) => {
543
+ if (s.nav) return s;
544
+ const r = await Ue(n, { baseUrl: e });
545
+ return r ? {
546
+ ...s,
199
547
  nav: {
200
- toc: a
201
- },
202
- renditionLayout: g,
203
- renditionFlow: I || "auto",
204
- renditionSpread: k,
205
- title: re,
206
- readingDirection: ie || "ltr",
207
- /**
208
- * @see https://www.w3.org/TR/epub/#sec-itemref-elem
209
- */
210
- spineItems: c?.childrenNamed("itemref").map((f, N) => {
211
- const v = p?.childrenNamed("item").find((C) => C.attr.id === f?.attr.idref), U = v?.attr.href || "", oe = e.records.find((C) => C.uri.endsWith(U))?.size || 0, z = t || (/^https?:\/\//.test(U) ? "" : "file://"), B = Le(f);
212
- return {
213
- ...B,
214
- id: v?.attr.id || "",
215
- index: N,
216
- href: v?.attr.href?.startsWith("https://") ? v?.attr.href : n ? `${z}${n}/${v?.attr.href}` : `${z}${v?.attr.href}`,
217
- renditionLayout: B.renditionLayout ?? g,
218
- progressionWeight: oe / se,
219
- // size: itemSize
220
- mediaType: v?.attr["media-type"]
548
+ toc: r
549
+ }
550
+ } : s;
551
+ }, Be = async (n, { baseUrl: e = "" } = {}) => {
552
+ const s = [
553
+ Ie({ archive: n, baseUrl: e }),
554
+ Se({ archive: n }),
555
+ $e({ archive: n }),
556
+ Ce({ archive: n }),
557
+ Le({ archive: n }),
558
+ Fe({ archive: n }),
559
+ ze({ archive: n, baseUrl: e })
560
+ ];
561
+ try {
562
+ const r = Ee({ archive: n, baseUrl: e })(), t = await s.reduce(async (o, i) => await i(await o), r);
563
+ if (m.log("Generated manifest", t), process.env.NODE_ENV === "development" && m.isEnabled()) {
564
+ const o = JSON.stringify(t, null, 2);
565
+ m.groupCollapsed(...m.getGroupArgs("Generated manifest")), m.log(`
566
+ ${o}`), m.groupEnd();
567
+ }
568
+ return t;
569
+ } catch (r) {
570
+ throw m.error(r), r;
571
+ }
572
+ }, Xe = (n) => {
573
+ const e = n.descendantWithPath("head")?.childrenNamed("meta").find((s) => s.attr.name === "calibre:cover");
574
+ return !!(e && e.attr.name === "calibre:cover");
575
+ }, Ve = (n) => n.descendantWithPath("body")?.descendantWithPath("div")?.childrenNamed("svg")?.find(
576
+ (e) => e.attr.width === "100%" && e.attr.preserveAspectRatio === "none"
577
+ ), He = ({ archive: n, resourcePath: e }) => async (s) => {
578
+ const r = Object.values(n.records).find(
579
+ (t) => t.uri === e && !t.dir
580
+ );
581
+ if (r && !r.dir && r.basename.endsWith(".xhtml")) {
582
+ const t = s.body ?? await r.string(), o = new y(t);
583
+ if (Xe(o)) {
584
+ const i = Ve(o);
585
+ return i && delete i.attr.preserveAspectRatio, {
586
+ ...s,
587
+ body: o?.toString()
221
588
  };
222
- }) || [],
223
- items: ne(o, e, (f) => {
224
- const N = f.attr.href || "";
225
- return /^https?:\/\//.test(N) ? "" : t || "file://";
226
- }),
227
- guide: l?.childrenNamed("reference").map((f) => ({
228
- href: f.attr.href || "",
229
- title: f.attr.title || "",
230
- type: f.attr.type
231
- }))
232
- };
233
- }, Ce = async (e, t) => {
234
- const r = await A(e).data?.string();
589
+ }
590
+ }
591
+ return s;
592
+ }, _e = ({ archive: n, resourcePath: e }) => async (s) => He({ archive: n, resourcePath: e })(s), Ge = ({ archive: n, resourcePath: e }) => async (s) => {
593
+ const r = Object.values(n.records).find(
594
+ (t) => t.uri === e && !t.dir
595
+ );
596
+ if (r && !r.dir && r.basename.endsWith(".css")) {
597
+ const o = (s.body ?? await r.string()).replaceAll(
598
+ "-webkit-writing-mode",
599
+ "writing-mode"
600
+ );
601
+ return {
602
+ ...s,
603
+ body: o
604
+ };
605
+ }
606
+ return s;
607
+ }, qe = async (n, e) => {
608
+ const r = await F(n).data?.string();
235
609
  if (r) {
236
- const n = new b(r), s = ne(n, e, () => "");
237
- if (s.find(
238
- (a) => t.endsWith(a.href)
610
+ const t = new y(r), o = Q(t, n, () => "");
611
+ if (o.find(
612
+ (a) => e.endsWith(a.href)
239
613
  )?.mediaType)
240
614
  return {
241
- mediaType: s.find((a) => t.endsWith(a.href))?.mediaType
615
+ mediaType: o.find((a) => e.endsWith(a.href))?.mediaType
242
616
  };
243
617
  }
244
618
  return {
245
- mediaType: Pe(t)
619
+ mediaType: Je(e)
246
620
  };
247
- }, Pe = (e) => {
248
- if (e.endsWith(".css"))
621
+ }, Je = (n) => {
622
+ if (n.endsWith(".css"))
249
623
  return "text/css; charset=UTF-8";
250
- if (e.endsWith(".jpg"))
624
+ if (n.endsWith(".jpg"))
251
625
  return "image/jpg";
252
- if (e.endsWith(".xhtml"))
626
+ if (n.endsWith(".xhtml"))
253
627
  return "application/xhtml+xml";
254
- if (e.endsWith(".mp4"))
628
+ if (n.endsWith(".mp4"))
255
629
  return "video/mp4";
256
- if (e.endsWith(".svg"))
630
+ if (n.endsWith(".svg"))
257
631
  return "image/svg+xml";
258
- }, Re = ({ archive: e, resourcePath: t }) => async (i) => {
259
- const r = Object.values(e.records).find(
260
- (s) => s.uri === t && !s.dir
632
+ }, Ke = ({ archive: n, resourcePath: e }) => async (s) => {
633
+ const r = Object.values(n.records).find(
634
+ (o) => o.uri === e && !o.dir
261
635
  );
262
- if (!r || r.dir) return i;
263
- const n = await Ce(e, t);
636
+ if (!r || r.dir) return s;
637
+ const t = await qe(n, e);
264
638
  return {
265
- ...i,
639
+ ...s,
266
640
  params: {
267
- ...i.params,
641
+ ...s.params,
268
642
  ...r?.encodingFormat && {
269
643
  contentType: r.encodingFormat
270
644
  },
271
- ...n.mediaType && {
272
- contentType: n.mediaType
645
+ ...t.mediaType && {
646
+ contentType: t.mediaType
273
647
  }
274
648
  }
275
649
  };
276
- }, Y = [
650
+ }, K = [
277
651
  "div",
278
652
  "span",
279
653
  "p",
@@ -324,640 +698,282 @@ const w = {
324
698
  "canvas",
325
699
  "script",
326
700
  "style"
327
- ], je = ({ archive: e, resourcePath: t }) => async (i) => {
328
- const r = Object.values(e.records).find(
329
- (n) => n.uri === t && !n.dir
701
+ ], Ye = ({ archive: n, resourcePath: e }) => async (s) => {
702
+ const r = Object.values(n.records).find(
703
+ (t) => t.uri === e && !t.dir
330
704
  );
331
705
  if (r && !r.dir && r.basename.endsWith(".xhtml")) {
332
- const n = i.body ?? await r.string();
706
+ const t = s.body ?? await r.string();
333
707
  if (!new RegExp(
334
- `<(${Y.join("|")})[\\s/>]`,
708
+ `<(${K.join("|")})[\\s/>]`,
335
709
  "i"
336
- ).test(n))
337
- return i;
338
- const o = new RegExp(
339
- `<(${Y.join("|")})(\\s[^>]*)?\\s*/>`,
710
+ ).test(t))
711
+ return s;
712
+ const i = new RegExp(
713
+ `<(${K.join("|")})(\\s[^>]*)?\\s*/>`,
340
714
  "gi"
341
- ), a = n.replace(
342
- o,
343
- (d, p, c = "") => `<${p} ${c.trim()}></${p}>`
715
+ ), a = t.replace(
716
+ i,
717
+ (l, c, d = "") => `<${c} ${d.trim()}></${c}>`
344
718
  );
345
719
  return {
346
- ...i,
720
+ ...s,
347
721
  body: a
348
722
  };
349
723
  }
350
- return i;
351
- }, Oe = async (e, t) => {
352
- const i = Object.values(e.records).find(
353
- (s) => s.uri === t && !s.dir
724
+ return s;
725
+ }, Qe = async (n, e) => {
726
+ const s = Object.values(n.records).find(
727
+ (o) => o.uri === e && !o.dir
354
728
  );
355
- if (!i || i.dir)
356
- throw new Error(`no file found for resourcePath:${t}`);
729
+ if (!s || s.dir)
730
+ throw new Error(`no file found for resourcePath:${e}`);
357
731
  const r = {
358
732
  params: {}
359
- }, n = [
360
- Re({ archive: e, resourcePath: t }),
361
- je({ archive: e, resourcePath: t }),
362
- Fe({ archive: e, resourcePath: t }),
363
- xe({ archive: e, resourcePath: t })
733
+ }, t = [
734
+ Ke({ archive: n, resourcePath: e }),
735
+ Ye({ archive: n, resourcePath: e }),
736
+ Ge({ archive: n, resourcePath: e }),
737
+ _e({ archive: n, resourcePath: e })
364
738
  ];
365
739
  try {
366
- const s = await n.reduce(async (o, a) => await a(await o), Promise.resolve(r));
367
- return w.log("Generated resource", t, s), {
368
- ...s,
369
- body: s.body ?? await i.blob()
370
- };
371
- } catch (s) {
372
- throw w.error(s), s;
373
- }
374
- }, De = ({ archive: e }) => async (t) => {
375
- const i = e.records.find(
376
- (n) => n.basename.toLowerCase() === "com.apple.ibooks.display-options.xml"
377
- );
378
- if (!i || i.dir)
379
- return t;
380
- const r = await (await i.blob()).text();
381
- try {
382
- const o = new b(r).childNamed("platform")?.childrenNamed("option")?.find((a) => a.attr.name === "fixed-layout")?.val || "false";
383
- return {
384
- ...t,
385
- renditionLayout: o === "true" ? "pre-paginated" : t.renditionLayout
386
- };
387
- } catch (n) {
388
- return console.error(
389
- `Unable to parse com.apple.ibooks.display-options.xml for content
390
- `,
391
- r
392
- ), console.error(n), t;
393
- }
394
- }, Me = async (e) => {
395
- const t = {
396
- renditionLayout: void 0
397
- };
398
- return await Promise.all(
399
- e.records.map(async (i) => {
400
- if (i.uri.endsWith("com.kobobooks.display-options.xml") && !i.dir) {
401
- const n = new b(await i.string()).childNamed("platform")?.childNamed("option");
402
- n?.attr?.name === "fixed-layout" && n.val === "true" && (t.renditionLayout = "pre-paginated");
403
- }
404
- })
405
- ), t;
406
- }, Ue = ({ archive: e }) => async (t) => {
407
- const i = await Me(e);
408
- return {
409
- ...t,
410
- renditionLayout: t.renditionLayout ?? i.renditionLayout
411
- };
412
- }, ze = ({ archive: e, baseUrl: t }) => async () => {
413
- const i = Object.values(e.records).filter((r) => !r.dir);
414
- return {
415
- filename: e.filename,
416
- title: e.records.find(({ dir: r }) => r)?.basename.replace(/\/$/, "") || e.filename,
417
- renditionLayout: void 0,
418
- renditionSpread: "auto",
419
- readingDirection: "ltr",
420
- spineItems: i.filter((r) => !r.basename.endsWith(".db")).map((r, n) => {
421
- const s = t || (/^https?:\/\//.test(r.uri) ? "" : "file://");
422
- return {
423
- // some books such as cbz can have same basename inside different sub folder
424
- // we need to make sure to have unique index
425
- // /chap01/01.png, /chap02/01.png, etc
426
- id: `${n}.${r.basename}`,
427
- index: n,
428
- href: encodeURI(`${s}${r.uri}`),
429
- renditionLayout: void 0,
430
- progressionWeight: 1 / i.length,
431
- pageSpreadLeft: void 0,
432
- pageSpreadRight: void 0,
433
- mediaType: r.encodingFormat
434
- };
435
- }),
436
- items: i.map((r, n) => ({
437
- id: `${n}.${r.basename}`,
438
- href: encodeURI(`${t}${r.uri}`)
439
- }))
440
- };
441
- }, Be = (e) => {
442
- const t = e.descendantWithPath("head")?.childrenNamed("meta").find((i) => i.attr.name === "viewport");
443
- return !!(t && t.attr.name === "viewport");
444
- }, Xe = (e) => e.reduce(async (t, i) => {
445
- if (!await t || !de({
446
- mimeType: i.encodingFormat,
447
- uri: i.uri
448
- }))
449
- return !1;
450
- const n = i.dir ? null : await i.string();
451
- return n ? Be(new b(n)) : !1;
452
- }, Promise.resolve(!0)), He = ({ archive: e }) => async (t) => {
453
- if (t.renditionLayout === "reflowable" && t.spineItems.every((r) => r.renditionLayout === "reflowable")) {
454
- const r = await Q({ archive: e });
455
- if (await Xe(r))
456
- return {
457
- ...t,
458
- spineItems: t.spineItems.map((s) => ({
459
- ...s,
460
- renditionLayout: "pre-paginated"
461
- })),
462
- renditionLayout: "pre-paginated"
463
- };
464
- }
465
- return t;
466
- }, Ve = ({ archive: e }) => async (t) => {
467
- const i = e.records.find(
468
- (s) => s.basename.toLowerCase() === "comicinfo.xml" && !s.dir
469
- );
470
- if (!i || i.dir)
471
- return t;
472
- const r = {
473
- ...t,
474
- spineItems: t.spineItems.filter((s) => !s.id.toLowerCase().endsWith("comicinfo.xml")).map((s, o, a) => ({
475
- ...s,
476
- progressionWeight: 1 / a.length
477
- }))
478
- }, n = await i.string();
479
- try {
480
- const o = new b(n).childNamed("Manga")?.val || "unknown";
481
- return {
482
- ...r,
483
- readingDirection: o === "YesAndRightToLeft" ? "rtl" : "ltr"
484
- };
485
- } catch (s) {
486
- return console.error(`Unable to parse comicinfo.xml for content
487
- `, n), console.error(s), r;
488
- }
489
- }, M = (e, t) => {
490
- const i = e.split(/(\d+)/), r = t.split(/(\d+)/);
491
- for (let n = 0, s = i.length; n < s; n++)
492
- if (i[n] !== r[n])
493
- return i[n]?.match(/\d/) ? +(i[n] || "") - +(r[n] || "") : (i[n] || "").localeCompare(r[n] || "");
494
- return 1;
495
- }, _e = ({ archive: e, baseUrl: t }) => async (i) => {
496
- if (i.nav) return i;
497
- const r = [...e.records].sort(
498
- (a, d) => M(a.uri, d.uri)
499
- ), n = Object.values(r), s = (a, d, p, c, l) => {
500
- const m = a.find((u) => u.title === d), [h, ...y] = p;
501
- return m ? h ? [
502
- ...a.filter((F) => F !== m),
503
- {
504
- ...m,
505
- contents: [
506
- ...m.contents,
507
- ...s(
508
- m.contents,
509
- h,
510
- y,
511
- c,
512
- l
513
- )
514
- ]
515
- }
516
- ] : m.path.split("/").length > l.split("/").length ? [
517
- ...a.filter((F) => F !== m),
518
- {
519
- ...m,
520
- path: l,
521
- href: c
522
- }
523
- ] : a : h ? [
524
- ...a,
525
- {
526
- contents: s(
527
- [],
528
- h,
529
- y,
530
- c,
531
- l
532
- ),
533
- href: c,
534
- path: l,
535
- title: d
536
- }
537
- ] : [
538
- ...a,
539
- {
540
- contents: [],
541
- href: c,
542
- path: l,
543
- title: d
544
- }
545
- ];
546
- }, o = n.reduce(
547
- (a, d) => {
548
- if (d.dir) return a;
549
- const c = d.uri.split("/").slice(0, -1), [l, ...m] = c;
550
- if (l) {
551
- const h = W(t, encodeURI(d.uri)).replace(/\/$/, ""), y = d.uri.replace(/\/$/, "");
552
- return s(a, l, m, h, y);
553
- }
554
- return a;
555
- },
556
- []
557
- );
558
- return o.length === 0 ? i : {
559
- ...i,
560
- nav: {
561
- toc: o
562
- }
563
- };
564
- }, qe = (e) => e.records.some((t) => t.basename.endsWith(".opf")), Ge = ({ archive: e }) => async (t) => qe(e) ? t : {
565
- ...t,
566
- spineItems: t.spineItems.map((r) => {
567
- const n = e.records.find(
568
- (o) => decodeURI(r.href).endsWith(o.uri)
569
- ), s = le(n?.encodingFormat ?? "") ?? O(n?.basename ?? "");
570
- return {
571
- ...r,
572
- renditionLayout: s?.startsWith("image/") ? "pre-paginated" : r.renditionLayout
740
+ const o = await t.reduce(async (i, a) => await a(await i), Promise.resolve(r));
741
+ return m.log("Generated resource", e, o), {
742
+ ...o,
743
+ body: o.body ?? await s.blob()
573
744
  };
574
- })
575
- }, Ke = async (e, { baseUrl: t = "" } = {}) => {
576
- const i = [
577
- ke({ archive: e, baseUrl: t }),
578
- Ve({ archive: e }),
579
- De({ archive: e }),
580
- Ge({ archive: e }),
581
- He({ archive: e }),
582
- Ue({ archive: e }),
583
- _e({ archive: e, baseUrl: t })
584
- ];
585
- try {
586
- const r = ze({ archive: e, baseUrl: t })(), n = await i.reduce(async (s, o) => await o(await s), r);
587
- return w.log("Generated manifest", n), n;
588
- } catch (r) {
589
- throw w.error(r), r;
745
+ } catch (o) {
746
+ throw m.error(o), o;
590
747
  }
591
- }, rt = async (e, t) => {
592
- const i = `
593
- <?xml version="1.0" encoding="UTF-8"?><package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="bookid">
594
- <metadata>
595
- <meta property="rendition:layout">${t?.useRenditionFlow ? "reflowable" : "pre-paginated"}</meta>
596
- ${t?.useRenditionFlow ? '<meta property="rendition:flow">scrolled-continuous</meta>' : ""}
597
- </metadata>
598
- <manifest>
599
- ${e.map(
600
- (s) => `<item id="${x(s)}" href="${s}" media-type="${O(s)}"/>`
601
- ).join(`
602
- `)}
603
- </manifest>
604
- <spine>
605
- ${e.map((s) => `<itemref idref="${x(s)}" />`).join(`
606
- `)}
607
- </spine>
608
- </package>
609
- `, r = e.map((s) => ({
610
- dir: !1,
611
- basename: x(s),
612
- encodingFormat: O(s),
613
- uri: s,
614
- size: 100 / e.length,
615
- blob: async () => (await fetch(s)).blob(),
616
- string: async () => ""
617
- }));
618
- return {
619
- filename: "",
620
- records: [{
621
- dir: !1,
622
- basename: "content.opf",
623
- uri: "content.opf",
624
- size: 0,
625
- blob: async () => new Blob(),
626
- string: async () => i
627
- }, ...r],
628
- close: () => Promise.resolve()
629
- };
630
- }, it = async (e, {
631
- mimeType: t,
632
- direction: i
633
- } = { mimeType: "text/plain" }) => {
634
- const r = `
635
- <?xml version="1.0" encoding="UTF-8"?>
636
- <package xmlns="http://www.idpf.org/2007/opf" version="3.0" xml:lang="ja" prefix="rendition: http://www.idpf.org/vocab/rendition/#"
637
- unique-identifier="ootuya-id">
638
- <metadata xmlns:opf="http://www.idpf.org/2007/opf" xmlns:dc="http://purl.org/dc/elements/1.1/"
639
- xmlns:dcterms="http://purl.org/dc/terms/">
640
- <meta property="rendition:layout">reflowable</meta>
641
- </metadata>
642
- <manifest>
643
- <item id="p01" href="p01.txt" media-type="text/plain"/>
644
- </manifest>
645
- <spine page-progression-direction="${i ?? "ltr"}">
646
- <itemref idref="p01" />
647
- </spine>
648
- </package>
649
- `;
650
- return {
651
- filename: "content.txt",
652
- records: [
653
- {
654
- dir: !1,
655
- basename: x("generated.opf"),
656
- uri: "generated.opf",
657
- blob: async () => new Blob([r]),
658
- string: async () => r,
659
- size: 0
660
- },
661
- {
662
- dir: !1,
663
- basename: x("p01.txt"),
664
- uri: "p01.txt",
665
- blob: async () => typeof e == "string" ? new Blob([e]) : e,
666
- string: async () => typeof e == "string" ? e : e.text(),
667
- size: typeof e == "string" ? e.length : e.size,
668
- encodingFormat: t
669
- }
670
- ],
671
- close: () => Promise.resolve()
672
- };
673
- }, st = async (e, { orderByAlpha: t, name: i } = {}) => {
674
- let r = Object.values(e.files);
675
- t && (r = r.slice().sort((s, o) => M(s.name, o.name)));
676
- const n = {
677
- filename: i || "",
678
- records: r.map((s) => ({
679
- dir: s.dir,
680
- basename: x(s.name),
681
- uri: s.name,
682
- blob: () => s.async("blob"),
683
- string: () => s.async("string"),
684
- ...s.internalStream && {
685
- stream: s.internalStream
686
- },
687
- // this is private API
688
- // @ts-expect-error
689
- size: s._data.uncompressedSize
690
- })),
691
- close: () => Promise.resolve()
692
- };
693
- return w.log("Generated archive", n), n;
694
- }, ot = async (e, { name: t } = {}) => {
695
- const i = await e.getFilesArray(), r = {
696
- close: () => e.close(),
697
- filename: t ?? "",
698
- records: i.map((n) => ({
699
- dir: !1,
700
- basename: n.file.name,
701
- size: n.file.size,
702
- uri: `${n.path}${n.file.name}`,
703
- blob: async () => await n.file.extract(),
704
- string: async () => (await n.file.extract()).text()
705
- }))
706
- };
707
- return w.log("Generated archive", r), r;
708
- }, at = async (e, { orderByAlpha: t, name: i } = {}) => {
709
- let r = e;
710
- return t && (r = r.slice().sort((n, s) => M(n.name, s.name))), {
711
- filename: i || "",
712
- records: r.map((n) => ({
713
- dir: n.isDir,
714
- basename: x(n.name),
715
- uri: n.name,
716
- blob: async () => new Blob([await n.data()]),
717
- string: async () => {
718
- const s = await n.data();
719
- return String.fromCharCode.apply(
720
- null,
721
- Array.from(new Uint16Array(s))
722
- );
723
- },
724
- size: n.size
725
- })),
726
- close: () => Promise.resolve()
727
- };
728
- }, ct = ({
729
- enableReport: e
730
- } = {}) => {
731
- w.enable(!!e);
732
748
  };
733
- class Je {
734
- constructor(t) {
735
- this.cleanArchiveAfter = t, this.state$ = new he({
749
+ class Ze {
750
+ constructor(e) {
751
+ this.cleanArchiveAfter = e, this.state$ = new ue({
736
752
  status: "idle",
737
753
  locks: 0
738
754
  });
739
755
  }
740
- update(t) {
741
- this.state$.next({ ...this.state$.getValue(), ...t });
756
+ update(e) {
757
+ this.state$.next({ ...this.state$.getValue(), ...e });
742
758
  }
743
759
  get locks$() {
744
- return this.state$.pipe($(({ locks: t }) => t));
760
+ return this.state$.pipe(v(({ locks: e }) => e));
745
761
  }
746
762
  get state() {
747
763
  return this.state$.getValue();
748
764
  }
749
765
  get isUnlocked$() {
750
766
  return this.locks$.pipe(
751
- $((t) => t <= 0),
752
- ge(),
753
- ye()
767
+ v((e) => e <= 0),
768
+ he(),
769
+ ge()
754
770
  );
755
771
  }
756
772
  get overTTL$() {
757
773
  return this.isUnlocked$.pipe(
758
- T(
759
- (t) => t ? this.cleanArchiveAfter === 1 / 0 ? _ : be(this.cleanArchiveAfter) : _
774
+ A(
775
+ (e) => e ? this.cleanArchiveAfter === 1 / 0 ? H : ye(this.cleanArchiveAfter) : H
760
776
  )
761
777
  );
762
778
  }
763
779
  }
764
- const Ye = ({
765
- getArchive: e,
766
- cleanArchiveAfter: t = 300 * 1e3
780
+ const et = ({
781
+ getArchive: n,
782
+ cleanArchiveAfter: e = 300 * 1e3
767
783
  // 5mn
768
784
  }) => {
769
- const i = new P(), r = new P(), n = new P(), s = {}, o = i.pipe(
770
- D((p) => {
771
- const c = s[p];
772
- if (!c || c.state.status !== "idle") return X;
773
- let l = !1;
774
- const m = (g) => {
775
- w.debug(`Cleaning up archive with key: ${g}`);
776
- const I = s[g];
777
- delete s[g], l || (I?.state.archive?.close(), l = !0);
785
+ const s = new C(), r = new C(), t = new C(), o = {}, i = s.pipe(
786
+ O((c) => {
787
+ const d = o[c];
788
+ if (!d || d.state.status !== "idle") return B;
789
+ let p = !1;
790
+ const g = (h) => {
791
+ m.debug(`Cleaning up archive with key: ${h}`);
792
+ const x = o[h];
793
+ delete o[h], p || (x?.state.archive?.close(), p = !0);
778
794
  };
779
- c.update({
795
+ d.update({
780
796
  status: "loading"
781
797
  });
782
- const h = c.locks$, y = c.isUnlocked$, u = h.pipe(
783
- pe(),
784
- R(([g, I]) => I > g),
785
- me(!0)
798
+ const b = d.locks$, E = d.isUnlocked$, u = b.pipe(
799
+ le(),
800
+ R(([h, x]) => x > h),
801
+ pe(!0)
786
802
  );
787
- return L(e(p)).pipe(
788
- j((g) => {
789
- c.update({
790
- archive: g,
803
+ return T(n(c)).pipe(
804
+ P((h) => {
805
+ d.update({
806
+ archive: h,
791
807
  status: "success"
792
808
  });
793
809
  }),
794
- S((g) => (m(p), c.update({
810
+ W((h) => (g(c), d.update({
795
811
  status: "error",
796
- error: g
797
- }), X)),
798
- T(() => {
799
- const g = u.pipe(
800
- T(() => n),
801
- T(() => y),
802
- R((k) => k)
812
+ error: h
813
+ }), B)),
814
+ A(() => {
815
+ const h = u.pipe(
816
+ A(() => t),
817
+ A(() => E),
818
+ R((S) => S)
803
819
  );
804
- return H(g, c.overTTL$).pipe(
820
+ return X(h, d.overTTL$).pipe(
805
821
  V(),
806
- j(() => {
807
- m(p);
822
+ P(() => {
823
+ g(c);
808
824
  })
809
825
  );
810
826
  })
811
827
  );
812
828
  }),
813
- fe(r)
814
- ), a = (p) => {
815
- let c = !1;
816
- const l = s[p] ?? new Je(t);
817
- s[p] = l, l.update({
818
- locks: l.state.locks + 1
829
+ me(r)
830
+ ), a = (c) => {
831
+ let d = !1;
832
+ const p = o[c] ?? new Ze(e);
833
+ o[c] = p, p.update({
834
+ locks: p.state.locks + 1
819
835
  });
820
- const m = () => {
821
- c || (c = !0, l.update({
822
- locks: l.state.locks - 1
836
+ const g = () => {
837
+ d || (d = !0, p.update({
838
+ locks: p.state.locks - 1
823
839
  }));
824
840
  };
825
- i.next(p);
826
- const h = l.state$.pipe(
827
- $(({ archive: u }) => u),
841
+ s.next(c);
842
+ const b = p.state$.pipe(
843
+ v(({ archive: u }) => u),
828
844
  R((u) => !!u)
829
- ), y = l.state$.pipe(
830
- j(({ error: u }) => {
845
+ ), E = p.state$.pipe(
846
+ P(({ error: u }) => {
831
847
  if (u)
832
848
  throw u;
833
849
  }),
834
- ue()
850
+ fe()
835
851
  );
836
- return H(h, y).pipe(
852
+ return X(b, E).pipe(
837
853
  V(),
838
- $((u) => ({ archive: u, release: m })),
839
- S((u) => {
840
- throw m(), u;
854
+ v((u) => ({ archive: u, release: g })),
855
+ W((u) => {
856
+ throw g(), u;
841
857
  })
842
858
  );
843
- }, d = () => {
844
- n.next();
859
+ }, l = () => {
860
+ t.next();
845
861
  };
846
- return o.subscribe(), {
862
+ return i.subscribe(), {
847
863
  access: a,
848
- purge: d,
849
- _archives: s
864
+ purge: l,
865
+ _archives: o
850
866
  };
851
867
  };
852
- class Qe {
868
+ class tt {
853
869
  constructor({
854
- onError: t,
855
- onManifestSuccess: i,
870
+ onError: e,
871
+ onManifestSuccess: s,
856
872
  ...r
857
873
  }) {
858
- this.onError = (n) => (console.error(n), new Response(String(n), { status: 500 })), this.epubLoader = Ye(r), this.onManifestSuccess = i ?? (({ manifest: n }) => Promise.resolve(n)), this.onError = t ?? this.onError;
874
+ this.onError = (t) => (console.error(t), new Response(String(t), { status: 500 })), this.epubLoader = et(r), this.onManifestSuccess = s ?? (({ manifest: t }) => Promise.resolve(t)), this.onError = e ?? this.onError;
859
875
  }
860
876
  prune() {
861
877
  this.epubLoader.purge();
862
878
  }
863
- accessArchive(t) {
864
- return this.lastAccessedKey !== void 0 && this.lastAccessedKey !== t && this.epubLoader.purge(), this.lastAccessedKey = t, this.epubLoader.access(t);
879
+ accessArchive(e) {
880
+ return this.lastAccessedKey !== void 0 && this.lastAccessedKey !== e && this.epubLoader.purge(), this.lastAccessedKey = e, this.epubLoader.access(e);
865
881
  }
866
- accessArchiveWithoutLock(t) {
867
- return this.accessArchive(t).pipe(
868
- $(({ archive: i, release: r }) => (r(), i))
882
+ accessArchiveWithoutLock(e) {
883
+ return this.accessArchive(e).pipe(
884
+ v(({ archive: s, release: r }) => (r(), s))
869
885
  );
870
886
  }
871
- fetchManifest({ key: t, baseUrl: i }) {
872
- const r = this.accessArchive(t).pipe(
873
- D(({ archive: n, release: s }) => L(
874
- Ke(n, { baseUrl: i })
887
+ fetchManifest({ key: e, baseUrl: s }) {
888
+ const r = this.accessArchive(e).pipe(
889
+ O(({ archive: t, release: o }) => T(
890
+ Be(t, { baseUrl: s })
875
891
  ).pipe(
876
- T(
877
- (a) => L(this.onManifestSuccess({ manifest: a, archive: n }))
892
+ A(
893
+ (a) => T(this.onManifestSuccess({ manifest: a, archive: t }))
878
894
  ),
879
- $(
895
+ v(
880
896
  (a) => new Response(JSON.stringify(a), {
881
897
  status: 200
882
898
  })
883
899
  ),
884
- q(() => {
885
- s();
900
+ _(() => {
901
+ o();
886
902
  })
887
903
  )),
888
- S((n) => G(this.onError(n)))
904
+ W((t) => G(this.onError(t)))
889
905
  );
890
- return K(r);
906
+ return q(r);
891
907
  }
892
908
  fetchResource({
893
- key: t,
894
- resourcePath: i
909
+ key: e,
910
+ resourcePath: s
895
911
  }) {
896
- const r = this.accessArchive(t).pipe(
897
- D(({ archive: n, release: s }) => {
898
- const o = i.replaceAll("file://", "");
899
- return L(
900
- Oe(n, o)
912
+ const r = this.accessArchive(e).pipe(
913
+ O(({ archive: t, release: o }) => {
914
+ const i = s.replaceAll("file://", "");
915
+ return T(
916
+ Qe(t, i)
901
917
  ).pipe(
902
- $(
903
- (d) => new Response(d.body, {
918
+ v(
919
+ (l) => new Response(l.body, {
904
920
  status: 200,
905
921
  headers: {
906
- ...d.params.contentType && {
907
- "Content-Type": d.params.contentType
922
+ ...l.params.contentType && {
923
+ "Content-Type": l.params.contentType
908
924
  }
909
925
  }
910
926
  })
911
927
  ),
912
- q(() => {
913
- s();
928
+ _(() => {
929
+ o();
914
930
  })
915
931
  );
916
932
  }),
917
- S((n) => G(this.onError(n)))
933
+ W((t) => G(this.onError(t)))
918
934
  );
919
- return K(r);
935
+ return q(r);
920
936
  }
921
937
  }
922
- class dt extends Qe {
938
+ class mt extends tt {
923
939
  constructor({
924
- getUriInfo: t,
925
- ...i
940
+ getUriInfo: e,
941
+ ...s
926
942
  }) {
927
- super(i), this.getUriInfo = t, this.fetchEventListener = this.fetchEventListener.bind(this);
943
+ super(s), this.getUriInfo = e, this.fetchEventListener = this.fetchEventListener.bind(this);
928
944
  }
929
- fetchEventListener(t) {
945
+ fetchEventListener(e) {
930
946
  try {
931
- const i = this.getUriInfo(t);
932
- if (!i) return;
933
- const r = J(i.baseUrl), n = t.request.url.substring(
947
+ const s = this.getUriInfo(e);
948
+ if (!s) return;
949
+ const r = J(s.baseUrl), t = e.request.url.substring(
934
950
  r.length + 1
935
- ), [s = ""] = n.split("/"), o = decodeURIComponent(
936
- J(n.substring(s.length + 1))
951
+ ), [o = ""] = t.split("/"), i = decodeURIComponent(
952
+ J(t.substring(o.length + 1))
937
953
  );
938
- n.endsWith("/manifest") ? t.respondWith(
939
- this.fetchManifest({ key: s, baseUrl: `${r}/${s}/` })
940
- ) : t.respondWith(this.fetchResource({ key: s, resourcePath: o }));
941
- } catch (i) {
942
- t.respondWith(new Response(String(i), { status: 500 }));
954
+ t.endsWith("/manifest") ? e.respondWith(
955
+ this.fetchManifest({ key: o, baseUrl: `${r}/${o}/` })
956
+ ) : e.respondWith(this.fetchResource({ key: o, resourcePath: i }));
957
+ } catch (s) {
958
+ e.respondWith(new Response(String(s), { status: 500 }));
943
959
  }
944
960
  }
945
961
  }
946
962
  export {
947
- dt as ServiceWorkerStreamer,
948
- Qe as Streamer,
949
- ct as configure,
950
- at as createArchiveFromArrayBufferList,
951
- st as createArchiveFromJszip,
952
- ot as createArchiveFromLibArchive,
953
- it as createArchiveFromText,
954
- rt as createArchiveFromUrls,
955
- Ke as generateManifestFromArchive,
956
- Oe as generateResourceFromArchive,
957
- A as getArchiveOpfInfo,
958
- Ie as getUriBasePath,
959
- x as getUriBasename,
963
+ mt as ServiceWorkerStreamer,
964
+ tt as Streamer,
965
+ pt as configure,
966
+ it as createArchiveFromArrayBufferList,
967
+ at as createArchiveFromJszip,
968
+ ct as createArchiveFromLibArchive,
969
+ dt as createArchiveFromText,
970
+ lt as createArchiveFromUrls,
971
+ Be as generateManifestFromArchive,
972
+ Qe as generateResourceFromArchive,
973
+ F as getArchiveOpfInfo,
974
+ be as getUriBasePath,
975
+ $ as getUriBasename,
960
976
  J as removeTrailingSlash,
961
- M as sortByTitleComparator
977
+ D as sortByTitleComparator
962
978
  };
963
979
  //# sourceMappingURL=index.js.map