@prose-reader/streamer 1.23.0 → 1.24.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/prose-streamer.js +383 -590
- package/dist/prose-streamer.js.map +1 -1
- package/dist/prose-streamer.umd.cjs +11 -716
- package/dist/prose-streamer.umd.cjs.map +1 -1
- package/package.json +3 -3
|
@@ -1,633 +1,29 @@
|
|
|
1
|
-
(function(
|
|
2
|
-
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@prose-reader/shared"), require("xmldoc")) : typeof define === "function" && define.amd ? define(["exports", "@prose-reader/shared", "xmldoc"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["prose-streamer"] = {}, global["@prose-reader/shared"], global.xmldoc));
|
|
3
|
-
})(this, function(exports2, shared, xmldoc) {
|
|
4
|
-
"use strict";
|
|
5
|
-
let enabled = false;
|
|
6
|
-
const Report = {
|
|
7
|
-
enable: (enable) => {
|
|
8
|
-
enabled = enable;
|
|
9
|
-
},
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
-
log: (...data) => {
|
|
12
|
-
if (enabled) {
|
|
13
|
-
console.log(`[prose-reader-streamer]`, ...data);
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
-
warn: (...data) => {
|
|
18
|
-
if (enabled) {
|
|
19
|
-
console.warn(`[prose-reader-streamer]`, ...data);
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
|
-
error: (...data) => {
|
|
24
|
-
console.error(...data);
|
|
25
|
-
},
|
|
26
|
-
time: (label) => {
|
|
27
|
-
if (enabled) {
|
|
28
|
-
console.time(`[prose-reader-streamer] [metric] ${label}`);
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
timeEnd: (label) => {
|
|
32
|
-
if (enabled) {
|
|
33
|
-
console.timeEnd(`[prose-reader-streamer] [metric] ${label}`);
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
metric: (performanceEntry, targetDuration = Infinity) => {
|
|
37
|
-
const duration = typeof performanceEntry === `number` ? performanceEntry : performanceEntry.duration;
|
|
38
|
-
if (enabled) {
|
|
39
|
-
if (performanceEntry.duration <= targetDuration) {
|
|
40
|
-
console.log(`[prose-reader-streamer] [metric] `, `${performanceEntry.name} took ${duration}ms`);
|
|
41
|
-
} else {
|
|
42
|
-
console.warn(
|
|
43
|
-
`[prose-reader-streamer] [metric] `,
|
|
44
|
-
`${performanceEntry.name} took ${performanceEntry.duration}ms which is above the ${targetDuration}ms target for this function`
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
|
-
measurePerformance: (name, targetDuration = 10, functionToMeasure) => {
|
|
51
|
-
return (...args) => {
|
|
52
|
-
const t0 = performance.now();
|
|
53
|
-
const response = functionToMeasure(...args);
|
|
54
|
-
if (response && response.then) {
|
|
55
|
-
return response.then((res) => {
|
|
56
|
-
const t12 = performance.now();
|
|
57
|
-
Report.metric({ name, duration: t12 - t0 }, targetDuration);
|
|
58
|
-
return res;
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
const t1 = performance.now();
|
|
62
|
-
Report.metric({ name, duration: t1 - t0 }, targetDuration);
|
|
63
|
-
return response;
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
const cssFixHook = ({ archive, resourcePath }) => async (resource) => {
|
|
68
|
-
const file = Object.values(archive.files).find((file2) => file2.uri === resourcePath);
|
|
69
|
-
if (file == null ? void 0 : file.basename.endsWith(`.css`)) {
|
|
70
|
-
const bodyToParse = resource.body ?? await file.string();
|
|
71
|
-
const newBody = bodyToParse.replaceAll(`-webkit-writing-mode`, `writing-mode`);
|
|
72
|
-
return {
|
|
73
|
-
...resource,
|
|
74
|
-
body: newBody
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
return resource;
|
|
78
|
-
};
|
|
79
|
-
const getArchiveOpfInfo = (archive) => {
|
|
80
|
-
const filesAsArray = Object.values(archive.files).filter((file2) => !file2.dir);
|
|
81
|
-
const file = filesAsArray.find((file2) => file2.uri.endsWith(`.opf`));
|
|
82
|
-
return {
|
|
83
|
-
data: file,
|
|
84
|
-
basePath: (file == null ? void 0 : file.uri.substring(0, file.uri.lastIndexOf(`/`))) || ``
|
|
85
|
-
};
|
|
86
|
-
};
|
|
87
|
-
const extractNavChapter = (li, { opfBasePath, baseUrl }) => {
|
|
88
|
-
const chp = {
|
|
89
|
-
contents: [],
|
|
90
|
-
path: ``,
|
|
91
|
-
href: ``,
|
|
92
|
-
title: ``
|
|
93
|
-
};
|
|
94
|
-
let contentNode = li.childNamed(`span`) || li.childNamed(`a`);
|
|
95
|
-
chp.title = (contentNode == null ? void 0 : contentNode.attr.title) || (contentNode == null ? void 0 : contentNode.val.trim()) || chp.title;
|
|
96
|
-
let node = contentNode == null ? void 0 : contentNode.name;
|
|
97
|
-
if (node !== `a`) {
|
|
98
|
-
contentNode = li.descendantWithPath(`${node}.a`);
|
|
99
|
-
if (contentNode) {
|
|
100
|
-
node = contentNode.name.toLowerCase();
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
if (node === `a` && (contentNode == null ? void 0 : contentNode.attr.href)) {
|
|
104
|
-
chp.path = shared.urlJoin(opfBasePath, contentNode.attr.href);
|
|
105
|
-
chp.href = shared.urlJoin(baseUrl, opfBasePath, contentNode.attr.href);
|
|
106
|
-
}
|
|
107
|
-
const sublistNode = li.childNamed(`ol`);
|
|
108
|
-
if (sublistNode) {
|
|
109
|
-
const children = sublistNode.childrenNamed(`li`);
|
|
110
|
-
if (children && children.length > 0) {
|
|
111
|
-
chp.contents = children.map((child) => extractNavChapter(child, { opfBasePath, baseUrl }));
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return chp;
|
|
115
|
-
};
|
|
116
|
-
const buildTOCFromNav = (doc, { opfBasePath, baseUrl }) => {
|
|
117
|
-
var _a, _b;
|
|
118
|
-
const toc = [];
|
|
119
|
-
let navDataChildren;
|
|
120
|
-
if (doc.descendantWithPath(`body.nav.ol`)) {
|
|
121
|
-
navDataChildren = (_a = doc.descendantWithPath(`body.nav.ol`)) == null ? void 0 : _a.children;
|
|
122
|
-
} else if (doc.descendantWithPath(`body.section.nav.ol`)) {
|
|
123
|
-
navDataChildren = (_b = doc.descendantWithPath(`body.section.nav.ol`)) == null ? void 0 : _b.children;
|
|
124
|
-
}
|
|
125
|
-
if (navDataChildren && navDataChildren.length > 0) {
|
|
126
|
-
navDataChildren.filter((li) => li.name === `li`).forEach((li) => toc.push(extractNavChapter(li, { opfBasePath, baseUrl })));
|
|
127
|
-
}
|
|
128
|
-
return toc;
|
|
129
|
-
};
|
|
130
|
-
const parseTocFromNavPath = async (opfXmlDoc, archive, { opfBasePath, baseUrl }) => {
|
|
131
|
-
var _a;
|
|
132
|
-
const navItem = (_a = opfXmlDoc.childNamed(`manifest`)) == null ? void 0 : _a.childrenNamed(`item`).find((child) => child.attr.properties === `nav`);
|
|
133
|
-
if (navItem) {
|
|
134
|
-
const tocFile = Object.values(archive.files).find((item) => item.uri.endsWith(navItem.attr.href || ``));
|
|
135
|
-
if (tocFile) {
|
|
136
|
-
const doc = new xmldoc.XmlDocument(await tocFile.string());
|
|
137
|
-
return buildTOCFromNav(doc, { opfBasePath, baseUrl });
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
const mapNcxChapter = (point, { opfBasePath, baseUrl, prefix }) => {
|
|
142
|
-
var _a, _b;
|
|
143
|
-
const src = ((_a = point == null ? void 0 : point.childNamed(`${prefix}content`)) == null ? void 0 : _a.attr.src) || ``;
|
|
144
|
-
const out = {
|
|
145
|
-
title: ((_b = point == null ? void 0 : point.descendantWithPath(`${prefix}navLabel.${prefix}text`)) == null ? void 0 : _b.val) || ``,
|
|
146
|
-
path: shared.urlJoin(opfBasePath, src),
|
|
147
|
-
href: shared.urlJoin(baseUrl, opfBasePath, src),
|
|
148
|
-
contents: []
|
|
149
|
-
};
|
|
150
|
-
const children = point.childrenNamed(`${prefix}navPoint`);
|
|
151
|
-
if (children && children.length > 0) {
|
|
152
|
-
out.contents = children.map((pt) => mapNcxChapter(pt, { opfBasePath, baseUrl, prefix }));
|
|
153
|
-
}
|
|
154
|
-
return out;
|
|
155
|
-
};
|
|
156
|
-
const buildTOCFromNCX = (ncxData, { opfBasePath, baseUrl }) => {
|
|
157
|
-
var _a;
|
|
158
|
-
const toc = [];
|
|
159
|
-
const rootTagName = ncxData.name;
|
|
160
|
-
let prefix = ``;
|
|
161
|
-
if (rootTagName.indexOf(`:`) !== -1) {
|
|
162
|
-
prefix = rootTagName.split(`:`)[0] + `:`;
|
|
163
|
-
}
|
|
164
|
-
(_a = ncxData.childNamed(`${prefix}navMap`)) == null ? void 0 : _a.childrenNamed(`${prefix}navPoint`).forEach((point) => toc.push(mapNcxChapter(point, { opfBasePath, baseUrl, prefix })));
|
|
165
|
-
return toc;
|
|
166
|
-
};
|
|
167
|
-
const parseTocFromNcx = async ({
|
|
168
|
-
opfData,
|
|
169
|
-
opfBasePath,
|
|
170
|
-
baseUrl,
|
|
171
|
-
archive
|
|
172
|
-
}) => {
|
|
173
|
-
var _a;
|
|
174
|
-
const spine = opfData.childNamed(`spine`);
|
|
175
|
-
const ncxId = spine && spine.attr.toc;
|
|
176
|
-
if (ncxId) {
|
|
177
|
-
const ncxItem = (_a = opfData.childNamed(`manifest`)) == null ? void 0 : _a.childrenNamed(`item`).find((item) => item.attr.id === ncxId);
|
|
178
|
-
if (ncxItem) {
|
|
179
|
-
const ncxPath = `${opfBasePath}${opfBasePath === `` ? `` : `/`}${ncxItem.attr.href}`;
|
|
180
|
-
const file = Object.values(archive.files).find((item) => item.uri.endsWith(ncxPath));
|
|
181
|
-
if (file) {
|
|
182
|
-
const ncxData = new xmldoc.XmlDocument(await file.string());
|
|
183
|
-
return buildTOCFromNCX(ncxData, { opfBasePath, baseUrl });
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
const parseToc = async (opfXmlDoc, archive, { baseUrl }) => {
|
|
189
|
-
const { basePath: opfBasePath } = getArchiveOpfInfo(archive) || {};
|
|
190
|
-
const tocFromNcx = await parseTocFromNcx({
|
|
191
|
-
opfData: opfXmlDoc,
|
|
192
|
-
opfBasePath,
|
|
193
|
-
archive,
|
|
194
|
-
baseUrl
|
|
195
|
-
});
|
|
196
|
-
if (tocFromNcx) {
|
|
197
|
-
return tocFromNcx;
|
|
198
|
-
}
|
|
199
|
-
return await parseTocFromNavPath(opfXmlDoc, archive, { opfBasePath, baseUrl });
|
|
200
|
-
};
|
|
201
|
-
const extractKoboInformationFromArchive = async (archive) => {
|
|
202
|
-
const koboInformation = {
|
|
203
|
-
renditionLayout: void 0
|
|
204
|
-
};
|
|
205
|
-
await Promise.all(
|
|
206
|
-
archive.files.map(async (file) => {
|
|
207
|
-
var _a, _b;
|
|
208
|
-
if (file.uri.endsWith(`com.kobobooks.display-options.xml`)) {
|
|
209
|
-
const opfXmlDoc = new xmldoc.XmlDocument(await file.string());
|
|
210
|
-
const optionElement = (_a = opfXmlDoc.childNamed(`platform`)) == null ? void 0 : _a.childNamed(`option`);
|
|
211
|
-
if (((_b = optionElement == null ? void 0 : optionElement.attr) == null ? void 0 : _b.name) === `fixed-layout` && optionElement.val === `true`) {
|
|
212
|
-
koboInformation.renditionLayout = `pre-paginated`;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
})
|
|
216
|
-
);
|
|
217
|
-
return koboInformation;
|
|
218
|
-
};
|
|
219
|
-
const getSpineItemFilesFromArchive = async ({ archive }) => {
|
|
220
|
-
const { data: opsFile, basePath: opfBasePath } = getArchiveOpfInfo(archive) || {};
|
|
221
|
-
const data = await (opsFile == null ? void 0 : opsFile.string());
|
|
222
|
-
if (!data)
|
|
223
|
-
return [];
|
|
224
|
-
const _opfXmlDoc = new xmldoc.XmlDocument(data);
|
|
225
|
-
const manifestElm = _opfXmlDoc.childNamed(`manifest`);
|
|
226
|
-
const spineElm = _opfXmlDoc.childNamed(`spine`);
|
|
227
|
-
const spineItemIds = spineElm == null ? void 0 : spineElm.childrenNamed(`itemref`).map((item) => item.attr.idref);
|
|
228
|
-
const manifestItemsFromSpine = (manifestElm == null ? void 0 : manifestElm.childrenNamed(`item`).filter((item) => spineItemIds.includes(item.attr.id || ``))) || [];
|
|
229
|
-
const archiveSpineItems = archive.files.filter((file) => {
|
|
230
|
-
return manifestItemsFromSpine.find((item) => {
|
|
231
|
-
if (!opfBasePath)
|
|
232
|
-
return `${item.attr.href}` === file.uri;
|
|
233
|
-
return `${opfBasePath}/${item.attr.href}` === file.uri;
|
|
234
|
-
});
|
|
235
|
-
});
|
|
236
|
-
return archiveSpineItems;
|
|
237
|
-
};
|
|
238
|
-
const getItemsFromDoc = (doc) => {
|
|
239
|
-
var _a;
|
|
240
|
-
const manifestElm = doc.childNamed(`manifest`);
|
|
241
|
-
return ((_a = manifestElm == null ? void 0 : manifestElm.childrenNamed(`item`)) == null ? void 0 : _a.map((el) => ({
|
|
242
|
-
href: el.attr.href || ``,
|
|
243
|
-
id: el.attr.id || ``,
|
|
244
|
-
mediaType: el.attr[`media-type`]
|
|
245
|
-
}))) || [];
|
|
246
|
-
};
|
|
247
|
-
const epubHook = ({ archive, baseUrl }) => async (manifest) => {
|
|
248
|
-
var _a;
|
|
249
|
-
const { data: opsFile, basePath: opfBasePath } = getArchiveOpfInfo(archive) || {};
|
|
250
|
-
const koboInformation = await extractKoboInformationFromArchive(archive);
|
|
251
|
-
if (!opsFile) {
|
|
252
|
-
return manifest;
|
|
253
|
-
}
|
|
254
|
-
const data = await opsFile.string();
|
|
255
|
-
Report.log(data, koboInformation);
|
|
256
|
-
const opfXmlDoc = new xmldoc.XmlDocument(data);
|
|
257
|
-
const toc = await parseToc(opfXmlDoc, archive, { baseUrl }) || [];
|
|
258
|
-
const metadataElm = opfXmlDoc.childNamed(`metadata`);
|
|
259
|
-
const manifestElm = opfXmlDoc.childNamed(`manifest`);
|
|
260
|
-
const spineElm = opfXmlDoc.childNamed(`spine`);
|
|
261
|
-
const guideElm = opfXmlDoc.childNamed(`guide`);
|
|
262
|
-
const titleElm = metadataElm == null ? void 0 : metadataElm.childNamed(`dc:title`);
|
|
263
|
-
const metaElmChildren = (metadataElm == null ? void 0 : metadataElm.childrenNamed(`meta`)) || [];
|
|
264
|
-
const metaElmWithRendition = metaElmChildren.find((meta) => meta.attr.property === `rendition:layout`);
|
|
265
|
-
const metaElmWithRenditionFlow = metaElmChildren.find((meta) => meta.attr.property === `rendition:flow`);
|
|
266
|
-
const metaElmWithRenditionSpread = metaElmChildren.find((meta) => meta.attr.property === `rendition:spread`);
|
|
267
|
-
const publisherRenditionLayout = metaElmWithRendition == null ? void 0 : metaElmWithRendition.val;
|
|
268
|
-
const publisherRenditionFlow = metaElmWithRenditionFlow == null ? void 0 : metaElmWithRenditionFlow.val;
|
|
269
|
-
const renditionSpread = metaElmWithRenditionSpread == null ? void 0 : metaElmWithRenditionSpread.val;
|
|
270
|
-
const title = (titleElm == null ? void 0 : titleElm.val) || ((_a = archive.files.find(({ dir }) => dir)) == null ? void 0 : _a.basename) || ``;
|
|
271
|
-
const pageProgressionDirection = spineElm == null ? void 0 : spineElm.attr[`page-progression-direction`];
|
|
272
|
-
const archiveSpineItems = await getSpineItemFilesFromArchive({ archive });
|
|
273
|
-
const totalSize = archiveSpineItems.reduce((size, file) => file.size + size, 0);
|
|
274
|
-
return {
|
|
275
|
-
filename: archive.filename,
|
|
276
|
-
nav: {
|
|
277
|
-
toc
|
|
278
|
-
},
|
|
279
|
-
renditionLayout: publisherRenditionLayout || koboInformation.renditionLayout || `reflowable`,
|
|
280
|
-
renditionFlow: publisherRenditionFlow || `auto`,
|
|
281
|
-
renditionSpread,
|
|
282
|
-
title,
|
|
283
|
-
readingDirection: pageProgressionDirection || `ltr`,
|
|
284
|
-
spineItems: (spineElm == null ? void 0 : spineElm.childrenNamed(`itemref`).map((itemrefElm) => {
|
|
285
|
-
var _a2, _b, _c;
|
|
286
|
-
const manifestItem = manifestElm == null ? void 0 : manifestElm.childrenNamed(`item`).find((item) => item.attr.id === (itemrefElm == null ? void 0 : itemrefElm.attr.idref));
|
|
287
|
-
const href = (manifestItem == null ? void 0 : manifestItem.attr.href) || ``;
|
|
288
|
-
const properties = ((_a2 = itemrefElm == null ? void 0 : itemrefElm.attr.properties) == null ? void 0 : _a2.split(` `)) || [];
|
|
289
|
-
const itemSize = ((_b = archive.files.find((file) => file.uri.endsWith(href))) == null ? void 0 : _b.size) || 0;
|
|
290
|
-
const hrefBaseUri = baseUrl ?? "";
|
|
291
|
-
return {
|
|
292
|
-
id: (manifestItem == null ? void 0 : manifestItem.attr.id) || ``,
|
|
293
|
-
href: ((_c = manifestItem == null ? void 0 : manifestItem.attr.href) == null ? void 0 : _c.startsWith(`https://`)) ? manifestItem == null ? void 0 : manifestItem.attr.href : opfBasePath ? `${hrefBaseUri}${opfBasePath}/${manifestItem == null ? void 0 : manifestItem.attr.href}` : `${hrefBaseUri}${manifestItem == null ? void 0 : manifestItem.attr.href}`,
|
|
294
|
-
renditionLayout: publisherRenditionLayout || `reflowable`,
|
|
295
|
-
...properties.find((property) => property === `rendition:layout-reflowable`) && {
|
|
296
|
-
renditionLayout: `reflowable`
|
|
297
|
-
},
|
|
298
|
-
progressionWeight: itemSize / totalSize,
|
|
299
|
-
pageSpreadLeft: properties.some((property) => property === `page-spread-left`) || void 0,
|
|
300
|
-
pageSpreadRight: properties.some((property) => property === `page-spread-right`) || void 0,
|
|
301
|
-
// size: itemSize
|
|
302
|
-
mediaType: manifestItem == null ? void 0 : manifestItem.attr[`media-type`]
|
|
303
|
-
};
|
|
304
|
-
})) || [],
|
|
305
|
-
items: getItemsFromDoc(opfXmlDoc),
|
|
306
|
-
guide: guideElm == null ? void 0 : guideElm.childrenNamed(`reference`).map((elm) => {
|
|
307
|
-
return {
|
|
308
|
-
href: elm.attr.href || ``,
|
|
309
|
-
title: elm.attr.title || ``,
|
|
310
|
-
type: elm.attr.type
|
|
311
|
-
};
|
|
312
|
-
})
|
|
313
|
-
};
|
|
314
|
-
};
|
|
315
|
-
const getMetadata = async (archive, resourcePath) => {
|
|
316
|
-
var _a, _b;
|
|
317
|
-
const opfInfo = getArchiveOpfInfo(archive);
|
|
318
|
-
const data = await ((_a = opfInfo.data) == null ? void 0 : _a.string());
|
|
319
|
-
if (data) {
|
|
320
|
-
const opfXmlDoc = new xmldoc.XmlDocument(data);
|
|
321
|
-
const items = getItemsFromDoc(opfXmlDoc);
|
|
322
|
-
return {
|
|
323
|
-
mediaType: (_b = items.find((item) => resourcePath.endsWith(item.href))) == null ? void 0 : _b.mediaType
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
return {
|
|
327
|
-
mediaType: getContentTypeFromExtension(resourcePath)
|
|
328
|
-
};
|
|
329
|
-
};
|
|
330
|
-
const getContentTypeFromExtension = (uri) => {
|
|
331
|
-
if (uri.endsWith(`.css`)) {
|
|
332
|
-
return `text/css; charset=UTF-8`;
|
|
333
|
-
}
|
|
334
|
-
if (uri.endsWith(`.jpg`)) {
|
|
335
|
-
return `image/jpg`;
|
|
336
|
-
}
|
|
337
|
-
if (uri.endsWith(`.xhtml`)) {
|
|
338
|
-
return `application/xhtml+xml`;
|
|
339
|
-
}
|
|
340
|
-
if (uri.endsWith(`.mp4`)) {
|
|
341
|
-
return `video/mp4`;
|
|
342
|
-
}
|
|
343
|
-
if (uri.endsWith(`.svg`)) {
|
|
344
|
-
return `image/svg+xml`;
|
|
345
|
-
}
|
|
346
|
-
};
|
|
347
|
-
const defaultHook$1 = ({ archive, resourcePath }) => async (resource) => {
|
|
348
|
-
const file = Object.values(archive.files).find((file2) => file2.uri === resourcePath);
|
|
349
|
-
if (!file)
|
|
350
|
-
return resource;
|
|
351
|
-
const metadata = await getMetadata(archive, resourcePath);
|
|
352
|
-
return {
|
|
353
|
-
...resource,
|
|
354
|
-
params: {
|
|
355
|
-
...resource.params,
|
|
356
|
-
status: 200,
|
|
357
|
-
headers: {
|
|
358
|
-
...(file == null ? void 0 : file.encodingFormat) && {
|
|
359
|
-
"Content-Type": file.encodingFormat
|
|
360
|
-
},
|
|
361
|
-
...metadata.mediaType && {
|
|
362
|
-
"Content-Type": metadata.mediaType
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
};
|
|
367
|
-
};
|
|
368
|
-
const generateResourceFromArchive = async (archive, resourcePath) => {
|
|
369
|
-
const file = Object.values(archive.files).find((file2) => file2.uri === resourcePath);
|
|
370
|
-
if (!file) {
|
|
371
|
-
throw new Error(`no file found`);
|
|
372
|
-
}
|
|
373
|
-
const defaultResource = {
|
|
374
|
-
params: {
|
|
375
|
-
status: 200
|
|
376
|
-
}
|
|
377
|
-
};
|
|
378
|
-
const hooks = [defaultHook$1({ archive, resourcePath }), cssFixHook({ archive, resourcePath })];
|
|
379
|
-
try {
|
|
380
|
-
const resource = await hooks.reduce(async (manifest, gen) => {
|
|
381
|
-
return await gen(await manifest);
|
|
382
|
-
}, Promise.resolve(defaultResource));
|
|
383
|
-
Report.log("Generated resource", resourcePath, resource);
|
|
384
|
-
return {
|
|
385
|
-
...resource,
|
|
386
|
-
body: resource.body || await file.blob()
|
|
387
|
-
};
|
|
388
|
-
} catch (e) {
|
|
389
|
-
Report.error(e);
|
|
390
|
-
throw e;
|
|
391
|
-
}
|
|
392
|
-
};
|
|
393
|
-
const generateResourceFromError = (error) => {
|
|
394
|
-
return {
|
|
395
|
-
body: `
|
|
1
|
+
(function(m,u){typeof exports=="object"&&typeof module<"u"?u(exports,require("@prose-reader/shared"),require("xmldoc")):typeof define=="function"&&define.amd?define(["exports","@prose-reader/shared","xmldoc"],u):(m=typeof globalThis<"u"?globalThis:m||self,u(m["prose-streamer"]={},m["@prose-reader/shared"],m.xmldoc))})(this,function(m,u,b){"use strict";let v=!1;const g={enable:e=>{v=e},log:(...e)=>{v&&console.log("[prose-reader-streamer]",...e)},warn:(...e)=>{v&&console.warn("[prose-reader-streamer]",...e)},error:(...e)=>{console.error(...e)},time:e=>{v&&console.time(`[prose-reader-streamer] [metric] ${e}`)},timeEnd:e=>{v&&console.timeEnd(`[prose-reader-streamer] [metric] ${e}`)},metric:(e,i=1/0)=>{const a=typeof e=="number"?e:e.duration;v&&(e.duration<=i?console.log("[prose-reader-streamer] [metric] ",`${e.name} took ${a}ms`):console.warn("[prose-reader-streamer] [metric] ",`${e.name} took ${e.duration}ms which is above the ${i}ms target for this function`))},measurePerformance:(e,i=10,a)=>(...r)=>{const t=performance.now(),n=a(...r);if(n&&n.then)return n.then(s=>{const d=performance.now();return g.metric({name:e,duration:d-t},i),s});const o=performance.now();return g.metric({name:e,duration:o-t},i),n}},X=({archive:e,resourcePath:i})=>async a=>{const r=Object.values(e.files).find(t=>t.uri===i);if(r!=null&&r.basename.endsWith(".css")){const n=(a.body??await r.string()).replaceAll("-webkit-writing-mode","writing-mode");return{...a,body:n}}return a},F=e=>{const a=Object.values(e.files).filter(r=>!r.dir).find(r=>r.uri.endsWith(".opf"));return{data:a,basePath:(a==null?void 0:a.uri.substring(0,a.uri.lastIndexOf("/")))||""}},S=(e,{opfBasePath:i,baseUrl:a})=>{const r={contents:[],path:"",href:"",title:""};let t=e.childNamed("span")||e.childNamed("a");r.title=(t==null?void 0:t.attr.title)||(t==null?void 0:t.val.trim())||r.title;let n=t==null?void 0:t.name;n!=="a"&&(t=e.descendantWithPath(`${n}.a`),t&&(n=t.name.toLowerCase())),n==="a"&&(t!=null&&t.attr.href)&&(r.path=u.urlJoin(i,t.attr.href),r.href=u.urlJoin(a,i,t.attr.href));const o=e.childNamed("ol");if(o){const s=o.childrenNamed("li");s&&s.length>0&&(r.contents=s.map(d=>S(d,{opfBasePath:i,baseUrl:a})))}return r},B=(e,{opfBasePath:i,baseUrl:a})=>{var n,o;const r=[];let t;return e.descendantWithPath("body.nav.ol")?t=(n=e.descendantWithPath("body.nav.ol"))==null?void 0:n.children:e.descendantWithPath("body.section.nav.ol")&&(t=(o=e.descendantWithPath("body.section.nav.ol"))==null?void 0:o.children),t&&t.length>0&&t.filter(s=>s.name==="li").forEach(s=>r.push(S(s,{opfBasePath:i,baseUrl:a}))),r},_=async(e,i,{opfBasePath:a,baseUrl:r})=>{var n;const t=(n=e.childNamed("manifest"))==null?void 0:n.childrenNamed("item").find(o=>o.attr.properties==="nav");if(t){const o=Object.values(i.files).find(s=>s.uri.endsWith(t.attr.href||""));if(o){const s=new b.XmlDocument(await o.string());return B(s,{opfBasePath:a,baseUrl:r})}}},L=(e,{opfBasePath:i,baseUrl:a,prefix:r})=>{var s,d;const t=((s=e==null?void 0:e.childNamed(`${r}content`))==null?void 0:s.attr.src)||"",n={title:((d=e==null?void 0:e.descendantWithPath(`${r}navLabel.${r}text`))==null?void 0:d.val)||"",path:u.urlJoin(i,t),href:u.urlJoin(a,i,t),contents:[]},o=e.childrenNamed(`${r}navPoint`);return o&&o.length>0&&(n.contents=o.map(p=>L(p,{opfBasePath:i,baseUrl:a,prefix:r}))),n},U=(e,{opfBasePath:i,baseUrl:a})=>{var o;const r=[],t=e.name;let n="";return t.indexOf(":")!==-1&&(n=t.split(":")[0]+":"),(o=e.childNamed(`${n}navMap`))==null||o.childrenNamed(`${n}navPoint`).forEach(s=>r.push(L(s,{opfBasePath:i,baseUrl:a,prefix:n}))),r},H=async({opfData:e,opfBasePath:i,baseUrl:a,archive:r})=>{var o;const t=e.childNamed("spine"),n=t&&t.attr.toc;if(n){const s=(o=e.childNamed("manifest"))==null?void 0:o.childrenNamed("item").find(d=>d.attr.id===n);if(s){const d=`${i}${i===""?"":"/"}${s.attr.href}`,p=Object.values(r.files).find(f=>f.uri.endsWith(d));if(p){const f=new b.XmlDocument(await p.string());return U(f,{opfBasePath:i,baseUrl:a})}}}},J=async(e,i,{baseUrl:a})=>{const{basePath:r}=F(i)||{},t=await H({opfData:e,opfBasePath:r,archive:i,baseUrl:a});return t||await _(e,i,{opfBasePath:r,baseUrl:a})},V=async e=>{const i={renditionLayout:void 0};return await Promise.all(e.files.map(async a=>{var r,t;if(a.uri.endsWith("com.kobobooks.display-options.xml")){const o=(r=new b.XmlDocument(await a.string()).childNamed("platform"))==null?void 0:r.childNamed("option");((t=o==null?void 0:o.attr)==null?void 0:t.name)==="fixed-layout"&&o.val==="true"&&(i.renditionLayout="pre-paginated")}})),i},R=async({archive:e})=>{const{data:i,basePath:a}=F(e)||{},r=await(i==null?void 0:i.string());if(!r)return[];const t=new b.XmlDocument(r),n=t.childNamed("manifest"),o=t.childNamed("spine"),s=o==null?void 0:o.childrenNamed("itemref").map(f=>f.attr.idref),d=(n==null?void 0:n.childrenNamed("item").filter(f=>s.includes(f.attr.id||"")))||[];return e.files.filter(f=>d.find(h=>a?`${a}/${h.attr.href}`===f.uri:`${h.attr.href}`===f.uri))},O=e=>{var a;const i=e.childNamed("manifest");return((a=i==null?void 0:i.childrenNamed("item"))==null?void 0:a.map(r=>({href:r.attr.href||"",id:r.attr.id||"",mediaType:r.attr["media-type"]})))||[]},q=({archive:e,baseUrl:i})=>async a=>{var P;const{data:r,basePath:t}=F(e)||{},n=await V(e);if(!r)return a;const o=await r.string();g.log(o,n);const s=new b.XmlDocument(o),d=await J(s,e,{baseUrl:i})||[],p=s.childNamed("metadata"),f=s.childNamed("manifest"),h=s.childNamed("spine"),T=s.childNamed("guide"),$=p==null?void 0:p.childNamed("dc:title"),x=(p==null?void 0:p.childrenNamed("meta"))||[],A=x.find(l=>l.attr.property==="rendition:layout"),I=x.find(l=>l.attr.property==="rendition:flow"),D=x.find(l=>l.attr.property==="rendition:spread"),C=A==null?void 0:A.val,pe=I==null?void 0:I.val,ue=D==null?void 0:D.val,he=($==null?void 0:$.val)||((P=e.files.find(({dir:l})=>l))==null?void 0:P.basename)||"",ge=h==null?void 0:h.attr["page-progression-direction"],ye=(await R({archive:e})).reduce((l,c)=>c.size+l,0);return{filename:e.filename,nav:{toc:d},renditionLayout:C||n.renditionLayout||"reflowable",renditionFlow:pe||"auto",renditionSpread:ue,title:he,readingDirection:ge||"ltr",spineItems:(h==null?void 0:h.childrenNamed("itemref").map(l=>{var j,z,M;const c=f==null?void 0:f.childrenNamed("item").find(y=>y.attr.id===(l==null?void 0:l.attr.idref)),be=(c==null?void 0:c.attr.href)||"",k=((j=l==null?void 0:l.attr.properties)==null?void 0:j.split(" "))||[],we=((z=e.files.find(y=>y.uri.endsWith(be)))==null?void 0:z.size)||0,W=i??"";return{id:(c==null?void 0:c.attr.id)||"",href:(M=c==null?void 0:c.attr.href)!=null&&M.startsWith("https://")?c==null?void 0:c.attr.href:t?`${W}${t}/${c==null?void 0:c.attr.href}`:`${W}${c==null?void 0:c.attr.href}`,renditionLayout:C||"reflowable",...k.find(y=>y==="rendition:layout-reflowable")&&{renditionLayout:"reflowable"},progressionWeight:we/ye,pageSpreadLeft:k.some(y=>y==="page-spread-left")||void 0,pageSpreadRight:k.some(y=>y==="page-spread-right")||void 0,mediaType:c==null?void 0:c.attr["media-type"]}}))||[],items:O(s),guide:T==null?void 0:T.childrenNamed("reference").map(l=>({href:l.attr.href||"",title:l.attr.title||"",type:l.attr.type}))}},G=async(e,i)=>{var t,n;const r=await((t=F(e).data)==null?void 0:t.string());if(r){const o=new b.XmlDocument(r);return{mediaType:(n=O(o).find(d=>i.endsWith(d.href)))==null?void 0:n.mediaType}}return{mediaType:Y(i)}},Y=e=>{if(e.endsWith(".css"))return"text/css; charset=UTF-8";if(e.endsWith(".jpg"))return"image/jpg";if(e.endsWith(".xhtml"))return"application/xhtml+xml";if(e.endsWith(".mp4"))return"video/mp4";if(e.endsWith(".svg"))return"image/svg+xml"},K=({archive:e,resourcePath:i})=>async a=>{const r=Object.values(e.files).find(n=>n.uri===i);if(!r)return a;const t=await G(e,i);return{...a,params:{...a.params,status:200,headers:{...(r==null?void 0:r.encodingFormat)&&{"Content-Type":r.encodingFormat},...t.mediaType&&{"Content-Type":t.mediaType}}}}},Q=async(e,i)=>{const a=Object.values(e.files).find(n=>n.uri===i);if(!a)throw new Error("no file found");const r={params:{status:200}},t=[K({archive:e,resourcePath:i}),X({archive:e,resourcePath:i})];try{const n=await t.reduce(async(o,s)=>await s(await o),Promise.resolve(r));return g.log("Generated resource",i,n),{...n,body:n.body||await a.blob()}}catch(n){throw g.error(n),n}},Z=e=>({body:`
|
|
396
2
|
<!DOCTYPE html>
|
|
397
3
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xml:lang="en" lang="en">
|
|
398
4
|
<head>
|
|
399
|
-
<meta name="${
|
|
5
|
+
<meta name="${u.PROSE_READER_RESOURCE_ERROR_INJECTED_META_NAME}" content="${String(e)}" />
|
|
400
6
|
</head>
|
|
401
7
|
<body>
|
|
402
|
-
<pre>${String(
|
|
8
|
+
<pre>${String(e)}</pre>
|
|
403
9
|
</body>
|
|
404
10
|
</html>
|
|
405
|
-
`,
|
|
406
|
-
params: {
|
|
407
|
-
status: 500,
|
|
408
|
-
headers: {
|
|
409
|
-
"Content-Type": "text/html;charset=UTF-8"
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
};
|
|
413
|
-
};
|
|
414
|
-
const defaultHook = ({ archive, baseUrl }) => async () => {
|
|
415
|
-
var _a;
|
|
416
|
-
const files = Object.values(archive.files).filter((file) => !file.dir);
|
|
417
|
-
return {
|
|
418
|
-
filename: archive.filename,
|
|
419
|
-
title: ((_a = archive.files.find(({ dir }) => dir)) == null ? void 0 : _a.basename.replace(/\/$/, ``)) || ``,
|
|
420
|
-
renditionLayout: `pre-paginated`,
|
|
421
|
-
renditionSpread: `auto`,
|
|
422
|
-
readingDirection: `ltr`,
|
|
423
|
-
spineItems: files.map((file, index) => ({
|
|
424
|
-
// some books such as cbz can have same basename inside different sub folder
|
|
425
|
-
// we need to make sure to have unique index
|
|
426
|
-
// /chap01/01.png, /chap02/01.png, etc
|
|
427
|
-
id: `${index}.${file.basename}`,
|
|
428
|
-
href: encodeURI(`${baseUrl}${file.uri}`),
|
|
429
|
-
renditionLayout: `pre-paginated`,
|
|
430
|
-
progressionWeight: 1 / files.length,
|
|
431
|
-
pageSpreadLeft: void 0,
|
|
432
|
-
pageSpreadRight: void 0,
|
|
433
|
-
mediaType: file.encodingFormat
|
|
434
|
-
})),
|
|
435
|
-
items: files.map((file, index) => ({
|
|
436
|
-
id: `${index}.${file.basename}`,
|
|
437
|
-
href: `${baseUrl}${file.uri}`
|
|
438
|
-
}))
|
|
439
|
-
};
|
|
440
|
-
};
|
|
441
|
-
const comicInfoHook = ({ archive, baseUrl }) => async (manifest) => {
|
|
442
|
-
var _a;
|
|
443
|
-
const comicInfoFile = archive.files.find((file) => file.basename.toLowerCase() === `comicinfo.xml`);
|
|
444
|
-
if (!comicInfoFile) {
|
|
445
|
-
return manifest;
|
|
446
|
-
}
|
|
447
|
-
const content = await comicInfoFile.string();
|
|
448
|
-
const xmlDoc = new xmldoc.XmlDocument(content);
|
|
449
|
-
const mangaVal = ((_a = xmlDoc.childNamed(`Manga`)) == null ? void 0 : _a.val) || `unknown`;
|
|
450
|
-
return {
|
|
451
|
-
...manifest,
|
|
452
|
-
spineItems: manifest.spineItems.filter((item) => item.id.toLowerCase() !== `comicinfo.xml`),
|
|
453
|
-
readingDirection: mangaVal === `YesAndRightToLeft` ? `rtl` : `ltr`
|
|
454
|
-
};
|
|
455
|
-
};
|
|
456
|
-
const hasDocMetaViewport = (doc) => {
|
|
457
|
-
var _a;
|
|
458
|
-
const metaElm = (_a = doc.descendantWithPath("head")) == null ? void 0 : _a.childrenNamed("meta").find((node) => node.attr.name === "viewport");
|
|
459
|
-
return !!(metaElm && metaElm.attr.name === "viewport");
|
|
460
|
-
};
|
|
461
|
-
const allFilesHaveViewportMeta = (files) => files.reduce(async (result, current) => {
|
|
462
|
-
const _result = await result;
|
|
463
|
-
if (!_result)
|
|
464
|
-
return false;
|
|
465
|
-
if (!shared.isXmlBasedMimeType({
|
|
466
|
-
mimeType: current.encodingFormat,
|
|
467
|
-
uri: current.uri
|
|
468
|
-
})) {
|
|
469
|
-
return false;
|
|
470
|
-
}
|
|
471
|
-
const file = await current.string();
|
|
472
|
-
if (!file)
|
|
473
|
-
return false;
|
|
474
|
-
return hasDocMetaViewport(new xmldoc.XmlDocument(file));
|
|
475
|
-
}, Promise.resolve(true));
|
|
476
|
-
const epubOptimizerHook = ({ archive, baseUrl }) => async (manifest) => {
|
|
477
|
-
const bookIsFullReflowable = manifest.renditionLayout === "reflowable" && manifest.spineItems.every((item) => item.renditionLayout === "reflowable");
|
|
478
|
-
if (bookIsFullReflowable) {
|
|
479
|
-
const files = await getSpineItemFilesFromArchive({ archive });
|
|
480
|
-
const hasAllViewport = await allFilesHaveViewportMeta(files);
|
|
481
|
-
if (hasAllViewport) {
|
|
482
|
-
return {
|
|
483
|
-
...manifest,
|
|
484
|
-
spineItems: manifest.spineItems.map((item) => ({
|
|
485
|
-
...item,
|
|
486
|
-
renditionLayout: "pre-paginated"
|
|
487
|
-
})),
|
|
488
|
-
renditionLayout: "pre-paginated"
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
return manifest;
|
|
493
|
-
};
|
|
494
|
-
const sortByTitleComparator = (a, b) => {
|
|
495
|
-
var _a;
|
|
496
|
-
const alist = a.split(/(\d+)/);
|
|
497
|
-
const blist = b.split(/(\d+)/);
|
|
498
|
-
for (let i = 0, len = alist.length; i < len; i++) {
|
|
499
|
-
if (alist[i] !== blist[i]) {
|
|
500
|
-
if ((_a = alist[i]) == null ? void 0 : _a.match(/\d/)) {
|
|
501
|
-
return +(alist[i] || ``) - +(blist[i] || ``);
|
|
502
|
-
} else {
|
|
503
|
-
return (alist[i] || ``).localeCompare(blist[i] || ``);
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
return 1;
|
|
508
|
-
};
|
|
509
|
-
const navigationFallbackHook = ({ archive, baseUrl }) => async (manifest) => {
|
|
510
|
-
if (manifest.nav)
|
|
511
|
-
return manifest;
|
|
512
|
-
const filesSortedByAlpha = [...archive.files].sort((a, b) => sortByTitleComparator(a.uri, b.uri));
|
|
513
|
-
const toc = Object.values(filesSortedByAlpha).reduce((acc, file) => {
|
|
514
|
-
const parts = file.uri.split("/");
|
|
515
|
-
const isFileUnderFolder = !file.dir && parts.length > 1;
|
|
516
|
-
if (isFileUnderFolder) {
|
|
517
|
-
parts.forEach((part, level) => {
|
|
518
|
-
const partIsFileName = level === parts.length - 1;
|
|
519
|
-
if (partIsFileName)
|
|
520
|
-
return;
|
|
521
|
-
const existingTocItem = acc.find(({ title }) => title === part);
|
|
522
|
-
if (existingTocItem)
|
|
523
|
-
;
|
|
524
|
-
else {
|
|
525
|
-
acc.push({
|
|
526
|
-
contents: [],
|
|
527
|
-
href: shared.urlJoin(baseUrl, encodeURI(file.uri)).replace(/\/$/, ""),
|
|
528
|
-
path: file.uri.replace(/\/$/, ""),
|
|
529
|
-
title: parts[0] ?? ""
|
|
530
|
-
});
|
|
531
|
-
}
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
return acc;
|
|
535
|
-
}, []);
|
|
536
|
-
if (toc.length === 0)
|
|
537
|
-
return manifest;
|
|
538
|
-
return {
|
|
539
|
-
...manifest,
|
|
540
|
-
nav: {
|
|
541
|
-
toc
|
|
542
|
-
}
|
|
543
|
-
};
|
|
544
|
-
};
|
|
545
|
-
const baseManifest = {
|
|
546
|
-
filename: ``,
|
|
547
|
-
items: [],
|
|
548
|
-
nav: {
|
|
549
|
-
toc: []
|
|
550
|
-
},
|
|
551
|
-
readingDirection: `ltr`,
|
|
552
|
-
renditionLayout: `pre-paginated`,
|
|
553
|
-
renditionSpread: `auto`,
|
|
554
|
-
spineItems: [],
|
|
555
|
-
title: ``
|
|
556
|
-
};
|
|
557
|
-
const generateManifestFromArchive = async (archive, { baseUrl = `` } = {}) => {
|
|
558
|
-
const hooks = [
|
|
559
|
-
defaultHook({ archive, baseUrl }),
|
|
560
|
-
epubHook({ archive, baseUrl }),
|
|
561
|
-
epubOptimizerHook({ archive, baseUrl }),
|
|
562
|
-
comicInfoHook({ archive, baseUrl }),
|
|
563
|
-
navigationFallbackHook({ archive, baseUrl })
|
|
564
|
-
];
|
|
565
|
-
try {
|
|
566
|
-
const manifest = await hooks.reduce(async (manifest2, gen) => {
|
|
567
|
-
return await gen(await manifest2);
|
|
568
|
-
}, Promise.resolve(baseManifest));
|
|
569
|
-
Report.log("Generated manifest", manifest);
|
|
570
|
-
return manifest;
|
|
571
|
-
} catch (e) {
|
|
572
|
-
Report.error(e);
|
|
573
|
-
throw e;
|
|
574
|
-
}
|
|
575
|
-
};
|
|
576
|
-
const getUriBasename = (uri) => uri.substring(uri.lastIndexOf(`/`) + 1) || uri;
|
|
577
|
-
const createArchiveFromUrls = async (urls, options) => {
|
|
578
|
-
const opfFileData = `
|
|
11
|
+
`,params:{status:500,headers:{"Content-Type":"text/html;charset=UTF-8"}}}),E=({archive:e,baseUrl:i})=>async()=>{var r;const a=Object.values(e.files).filter(t=>!t.dir);return{filename:e.filename,title:((r=e.files.find(({dir:t})=>t))==null?void 0:r.basename.replace(/\/$/,""))||"",renditionLayout:"pre-paginated",renditionSpread:"auto",readingDirection:"ltr",spineItems:a.map((t,n)=>({id:`${n}.${t.basename}`,href:encodeURI(`${i}${t.uri}`),renditionLayout:"pre-paginated",progressionWeight:1/a.length,pageSpreadLeft:void 0,pageSpreadRight:void 0,mediaType:t.encodingFormat})),items:a.map((t,n)=>({id:`${n}.${t.basename}`,href:`${i}${t.uri}`}))}},ee=({archive:e,baseUrl:i})=>async a=>{var s;const r=e.files.find(d=>d.basename.toLowerCase()==="comicinfo.xml");if(!r)return a;const t=await r.string(),o=((s=new b.XmlDocument(t).childNamed("Manga"))==null?void 0:s.val)||"unknown";return{...a,spineItems:a.spineItems.filter(d=>d.id.toLowerCase()!=="comicinfo.xml"),readingDirection:o==="YesAndRightToLeft"?"rtl":"ltr"}},te=e=>{var a;const i=(a=e.descendantWithPath("head"))==null?void 0:a.childrenNamed("meta").find(r=>r.attr.name==="viewport");return!!(i&&i.attr.name==="viewport")},ne=e=>e.reduce(async(i,a)=>{if(!await i||!u.isXmlBasedMimeType({mimeType:a.encodingFormat,uri:a.uri}))return!1;const t=await a.string();return t?te(new b.XmlDocument(t)):!1},Promise.resolve(!0)),re=({archive:e,baseUrl:i})=>async a=>{if(a.renditionLayout==="reflowable"&&a.spineItems.every(t=>t.renditionLayout==="reflowable")){const t=await R({archive:e});if(await ne(t))return{...a,spineItems:a.spineItems.map(o=>({...o,renditionLayout:"pre-paginated"})),renditionLayout:"pre-paginated"}}return a},N=(e,i)=>{var t;const a=e.split(/(\d+)/),r=i.split(/(\d+)/);for(let n=0,o=a.length;n<o;n++)if(a[n]!==r[n])return(t=a[n])!=null&&t.match(/\d/)?+(a[n]||"")-+(r[n]||""):(a[n]||"").localeCompare(r[n]||"");return 1},ae=({archive:e,baseUrl:i})=>async a=>{if(a.nav)return a;const r=[...e.files].sort((n,o)=>N(n.uri,o.uri)),t=Object.values(r).reduce((n,o)=>{const s=o.uri.split("/");return!o.dir&&s.length>1&&s.forEach((p,f)=>{if(f===s.length-1)return;n.find(({title:$})=>$===p)||n.push({contents:[],href:u.urlJoin(i,encodeURI(o.uri)).replace(/\/$/,""),path:o.uri.replace(/\/$/,""),title:s[0]??""})}),n},[]);return t.length===0?a:{...a,nav:{toc:t}}},ie={filename:"",items:[],nav:{toc:[]},readingDirection:"ltr",renditionLayout:"pre-paginated",renditionSpread:"auto",spineItems:[],title:""},oe=async(e,{baseUrl:i=""}={})=>{const a=[E({archive:e,baseUrl:i}),q({archive:e,baseUrl:i}),re({archive:e,baseUrl:i}),ee({archive:e,baseUrl:i}),ae({archive:e,baseUrl:i})];try{const r=await a.reduce(async(t,n)=>await n(await t),Promise.resolve(ie));return g.log("Generated manifest",r),r}catch(r){throw g.error(r),r}},w=e=>e.substring(e.lastIndexOf("/")+1)||e,se=async(e,i)=>{const a=`
|
|
579
12
|
<?xml version="1.0" encoding="UTF-8"?><package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="bookid">
|
|
580
13
|
<metadata>
|
|
581
|
-
<meta property="rendition:layout">${
|
|
582
|
-
${
|
|
14
|
+
<meta property="rendition:layout">${i!=null&&i.useRenditionFlow?"reflowable":"pre-paginated"}</meta>
|
|
15
|
+
${i!=null&&i.useRenditionFlow?'<meta property="rendition:flow">scrolled-continuous</meta>':""}
|
|
583
16
|
</metadata>
|
|
584
17
|
<manifest>
|
|
585
|
-
${
|
|
18
|
+
${e.map(n=>`<item id="${w(n)}" href="${n}" media-type="${u.detectMimeTypeFromName(n)}"/>`).join(`
|
|
586
19
|
`)}
|
|
587
20
|
</manifest>
|
|
588
21
|
<spine>
|
|
589
|
-
${
|
|
22
|
+
${e.map(n=>`<itemref idref="${w(n)}" />`).join(`
|
|
590
23
|
`)}
|
|
591
24
|
</spine>
|
|
592
25
|
</package>
|
|
593
|
-
|
|
594
|
-
const filesFromUrl = urls.map((url) => ({
|
|
595
|
-
dir: false,
|
|
596
|
-
basename: getUriBasename(url),
|
|
597
|
-
encodingFormat: shared.detectMimeTypeFromName(url),
|
|
598
|
-
uri: url,
|
|
599
|
-
size: 100 / urls.length,
|
|
600
|
-
base64: async () => ``,
|
|
601
|
-
blob: async () => new Blob(),
|
|
602
|
-
string: async () => ``
|
|
603
|
-
}));
|
|
604
|
-
const opfFile = {
|
|
605
|
-
dir: false,
|
|
606
|
-
basename: `content.opf`,
|
|
607
|
-
uri: `content.opf`,
|
|
608
|
-
size: 0,
|
|
609
|
-
base64: async () => opfFileData,
|
|
610
|
-
blob: async () => new Blob(),
|
|
611
|
-
string: async () => opfFileData
|
|
612
|
-
};
|
|
613
|
-
return {
|
|
614
|
-
filename: ``,
|
|
615
|
-
files: [opfFile, ...filesFromUrl]
|
|
616
|
-
};
|
|
617
|
-
};
|
|
618
|
-
const blobToBase64 = async (blob) => new Promise((resolve) => {
|
|
619
|
-
const reader = new FileReader();
|
|
620
|
-
reader.readAsDataURL(blob);
|
|
621
|
-
reader.onloadend = function() {
|
|
622
|
-
const base64data = reader.result;
|
|
623
|
-
resolve(base64data);
|
|
624
|
-
};
|
|
625
|
-
});
|
|
626
|
-
const createArchiveFromText = async (content, {
|
|
627
|
-
mimeType,
|
|
628
|
-
direction
|
|
629
|
-
} = { mimeType: "text/plain" }) => {
|
|
630
|
-
const txtOpfContent = `
|
|
26
|
+
`,r=e.map(n=>({dir:!1,basename:w(n),encodingFormat:u.detectMimeTypeFromName(n),uri:n,size:100/e.length,base64:async()=>"",blob:async()=>new Blob,string:async()=>""}));return{filename:"",files:[{dir:!1,basename:"content.opf",uri:"content.opf",size:0,base64:async()=>a,blob:async()=>new Blob,string:async()=>a},...r]}},ce=async e=>new Promise(i=>{const a=new FileReader;a.readAsDataURL(e),a.onloadend=function(){const r=a.result;i(r)}}),de=async(e,{mimeType:i,direction:a}={mimeType:"text/plain"})=>{const r=`
|
|
631
27
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
632
28
|
<package xmlns="http://www.idpf.org/2007/opf" version="3.0" xml:lang="ja" prefix="rendition: http://www.idpf.org/vocab/rendition/#"
|
|
633
29
|
unique-identifier="ootuya-id">
|
|
@@ -638,110 +34,9 @@
|
|
|
638
34
|
<manifest>
|
|
639
35
|
<item id="p01" href="p01.txt" media-type="text/plain"/>
|
|
640
36
|
</manifest>
|
|
641
|
-
<spine page-progression-direction="${
|
|
37
|
+
<spine page-progression-direction="${a??"ltr"}">
|
|
642
38
|
<itemref idref="p01" />
|
|
643
39
|
</spine>
|
|
644
40
|
</package>
|
|
645
|
-
`;
|
|
646
|
-
const archive = {
|
|
647
|
-
filename: `content.txt`,
|
|
648
|
-
files: [
|
|
649
|
-
{
|
|
650
|
-
dir: false,
|
|
651
|
-
basename: getUriBasename(`generated.opf`),
|
|
652
|
-
uri: `generated.opf`,
|
|
653
|
-
blob: async () => new Blob([txtOpfContent]),
|
|
654
|
-
string: async () => txtOpfContent,
|
|
655
|
-
base64: async () => btoa(txtOpfContent),
|
|
656
|
-
size: 0
|
|
657
|
-
},
|
|
658
|
-
{
|
|
659
|
-
dir: false,
|
|
660
|
-
basename: getUriBasename(`p01.txt`),
|
|
661
|
-
uri: `p01.txt`,
|
|
662
|
-
blob: async () => {
|
|
663
|
-
if (typeof content === `string`)
|
|
664
|
-
return new Blob([content]);
|
|
665
|
-
return content;
|
|
666
|
-
},
|
|
667
|
-
string: async () => {
|
|
668
|
-
if (typeof content === `string`)
|
|
669
|
-
return content;
|
|
670
|
-
return content.text();
|
|
671
|
-
},
|
|
672
|
-
base64: async () => {
|
|
673
|
-
if (typeof content === `string`)
|
|
674
|
-
return btoa(content);
|
|
675
|
-
return blobToBase64(content);
|
|
676
|
-
},
|
|
677
|
-
size: typeof content === `string` ? content.length : content.size,
|
|
678
|
-
encodingFormat: mimeType
|
|
679
|
-
}
|
|
680
|
-
]
|
|
681
|
-
};
|
|
682
|
-
return archive;
|
|
683
|
-
};
|
|
684
|
-
const createArchiveFromJszip = async (jszip, { orderByAlpha, name } = {}) => {
|
|
685
|
-
let files = Object.values(jszip.files);
|
|
686
|
-
if (orderByAlpha) {
|
|
687
|
-
files = files.sort((a, b) => sortByTitleComparator(a.name, b.name));
|
|
688
|
-
}
|
|
689
|
-
const archive = {
|
|
690
|
-
filename: name || ``,
|
|
691
|
-
files: files.map((file) => ({
|
|
692
|
-
dir: file.dir,
|
|
693
|
-
basename: getUriBasename(file.name),
|
|
694
|
-
uri: file.name,
|
|
695
|
-
blob: () => file.async(`blob`),
|
|
696
|
-
string: () => file.async(`string`),
|
|
697
|
-
base64: () => file.async(`base64`),
|
|
698
|
-
...file.internalStream && {
|
|
699
|
-
stream: file.internalStream
|
|
700
|
-
},
|
|
701
|
-
// this is private API
|
|
702
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
703
|
-
// @ts-ignore
|
|
704
|
-
size: file._data.uncompressedSize
|
|
705
|
-
}))
|
|
706
|
-
};
|
|
707
|
-
Report.log("Generated archive", archive);
|
|
708
|
-
return archive;
|
|
709
|
-
};
|
|
710
|
-
const createArchiveFromArrayBufferList = async (list, { orderByAlpha, name } = {}) => {
|
|
711
|
-
let files = list;
|
|
712
|
-
if (orderByAlpha) {
|
|
713
|
-
files = files.sort((a, b) => sortByTitleComparator(a.name, b.name));
|
|
714
|
-
}
|
|
715
|
-
return {
|
|
716
|
-
filename: name || ``,
|
|
717
|
-
files: files.map((file) => ({
|
|
718
|
-
dir: file.isDir,
|
|
719
|
-
basename: getUriBasename(file.name),
|
|
720
|
-
uri: file.name,
|
|
721
|
-
blob: async () => new Blob([await file.data()]),
|
|
722
|
-
string: async () => {
|
|
723
|
-
const data = await file.data();
|
|
724
|
-
return String.fromCharCode.apply(null, Array.from(new Uint16Array(data)));
|
|
725
|
-
},
|
|
726
|
-
base64: async () => {
|
|
727
|
-
return ``;
|
|
728
|
-
},
|
|
729
|
-
size: file.size
|
|
730
|
-
}))
|
|
731
|
-
};
|
|
732
|
-
};
|
|
733
|
-
const configure = ({ enableReport } = {}) => {
|
|
734
|
-
Report.enable(!!enableReport);
|
|
735
|
-
};
|
|
736
|
-
exports2.configure = configure;
|
|
737
|
-
exports2.createArchiveFromArrayBufferList = createArchiveFromArrayBufferList;
|
|
738
|
-
exports2.createArchiveFromJszip = createArchiveFromJszip;
|
|
739
|
-
exports2.createArchiveFromText = createArchiveFromText;
|
|
740
|
-
exports2.createArchiveFromUrls = createArchiveFromUrls;
|
|
741
|
-
exports2.generateManifestFromArchive = generateManifestFromArchive;
|
|
742
|
-
exports2.generateResourceFromArchive = generateResourceFromArchive;
|
|
743
|
-
exports2.generateResourceFromError = generateResourceFromError;
|
|
744
|
-
exports2.getArchiveOpfInfo = getArchiveOpfInfo;
|
|
745
|
-
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
|
|
746
|
-
});
|
|
41
|
+
`;return{filename:"content.txt",files:[{dir:!1,basename:w("generated.opf"),uri:"generated.opf",blob:async()=>new Blob([r]),string:async()=>r,base64:async()=>btoa(r),size:0},{dir:!1,basename:w("p01.txt"),uri:"p01.txt",blob:async()=>typeof e=="string"?new Blob([e]):e,string:async()=>typeof e=="string"?e:e.text(),base64:async()=>typeof e=="string"?btoa(e):ce(e),size:typeof e=="string"?e.length:e.size,encodingFormat:i}]}},le=async(e,{orderByAlpha:i,name:a}={})=>{let r=Object.values(e.files);i&&(r=r.sort((n,o)=>N(n.name,o.name)));const t={filename:a||"",files:r.map(n=>({dir:n.dir,basename:w(n.name),uri:n.name,blob:()=>n.async("blob"),string:()=>n.async("string"),base64:()=>n.async("base64"),...n.internalStream&&{stream:n.internalStream},size:n._data.uncompressedSize}))};return g.log("Generated archive",t),t},me=async(e,{orderByAlpha:i,name:a}={})=>{let r=e;return i&&(r=r.sort((t,n)=>N(t.name,n.name))),{filename:a||"",files:r.map(t=>({dir:t.isDir,basename:w(t.name),uri:t.name,blob:async()=>new Blob([await t.data()]),string:async()=>{const n=await t.data();return String.fromCharCode.apply(null,Array.from(new Uint16Array(n)))},base64:async()=>"",size:t.size}))}},fe=({enableReport:e}={})=>{g.enable(!!e)};m.configure=fe,m.createArchiveFromArrayBufferList=me,m.createArchiveFromJszip=le,m.createArchiveFromText=de,m.createArchiveFromUrls=se,m.generateManifestFromArchive=oe,m.generateResourceFromArchive=Q,m.generateResourceFromError=Z,m.getArchiveOpfInfo=F,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"})});
|
|
747
42
|
//# sourceMappingURL=prose-streamer.umd.cjs.map
|