@storyteller-platform/align 0.1.40 → 0.1.47

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/cli/bin.cjs CHANGED
@@ -359,13 +359,12 @@ async function main() {
359
359
  if (parsed.textRef === "id-fragment") {
360
360
  logger.info("Marking up EPUB...");
361
361
  startProgressBar();
362
- const markedup2 = parsed.markedup ?? (0, import_node_path.join)(os.tmpdir(), `stalign-markedup-${(0, import_node_crypto.randomUUID)()}.epub`);
363
362
  if (!parsed.markedup) {
364
363
  stack.defer(() => {
365
- (0, import_node_fs.rmSync)(markedup2, { recursive: true, force: true });
364
+ (0, import_node_fs.rmSync)(markedup, { recursive: true, force: true });
366
365
  });
367
366
  }
368
- const markupTiming = await (0, import_markup.markup)(input, markedup2, {
367
+ const markupTiming = await (0, import_markup.markup)(input, markedup, {
369
368
  granularity: parsed.granularity,
370
369
  primaryLocale,
371
370
  logger,
@@ -376,12 +375,12 @@ async function main() {
376
375
  }
377
376
  });
378
377
  resetProgressBar();
379
- logger.info(`Markup complete, marked up EPUB saved to ${markedup2}.`);
378
+ logger.info(`Markup complete, marked up EPUB saved to ${markedup}.`);
380
379
  if (parsed.time) {
381
380
  markupTiming.print();
382
381
  }
383
382
  } else {
384
- logger.info("Skipping markup, text-range-type set to text-fragment");
383
+ logger.info("Skipping markup, text-ref set to text-fragment");
385
384
  }
386
385
  logger.info("Aligning EPUB with audiobook...");
387
386
  startProgressBar();
package/dist/cli/bin.js CHANGED
@@ -312,13 +312,12 @@ async function main() {
312
312
  if (parsed.textRef === "id-fragment") {
313
313
  logger.info("Marking up EPUB...");
314
314
  startProgressBar();
315
- const markedup2 = parsed.markedup ?? join(os.tmpdir(), `stalign-markedup-${randomUUID()}.epub`);
316
315
  if (!parsed.markedup) {
317
316
  stack.defer(() => {
318
- rmSync(markedup2, { recursive: true, force: true });
317
+ rmSync(markedup, { recursive: true, force: true });
319
318
  });
320
319
  }
321
- const markupTiming = await markup(input, markedup2, {
320
+ const markupTiming = await markup(input, markedup, {
322
321
  granularity: parsed.granularity,
323
322
  primaryLocale,
324
323
  logger,
@@ -329,12 +328,12 @@ async function main() {
329
328
  }
330
329
  });
331
330
  resetProgressBar();
332
- logger.info(`Markup complete, marked up EPUB saved to ${markedup2}.`);
331
+ logger.info(`Markup complete, marked up EPUB saved to ${markedup}.`);
333
332
  if (parsed.time) {
334
333
  markupTiming.print();
335
334
  }
336
335
  } else {
337
- logger.info("Skipping markup, text-range-type set to text-fragment");
336
+ logger.info("Skipping markup, text-ref set to text-fragment");
338
337
  }
339
338
  logger.info("Aligning EPUB with audiobook...");
340
339
  startProgressBar();
@@ -43,14 +43,11 @@ var import_mime = require("../process/mime.cjs");
43
43
  var import_shell = require("./shell.cjs");
44
44
  const execPromise = (0, import_node_util.promisify)(import_node_child_process.exec);
45
45
  async function execCmd(command, logger, signal) {
46
- let stdout = "";
47
- let stderr = "";
48
46
  try {
49
- ;
50
- ({ stdout, stderr } = await execPromise(command, {
47
+ const { stdout } = await execPromise(command, {
51
48
  maxBuffer: 50 * 1024 * 1024,
52
49
  signal: signal ?? void 0
53
- }));
50
+ });
54
51
  return stdout;
55
52
  } catch (error) {
56
53
  if (error instanceof RangeError && error.message.includes("stdout maxBuffer length exceeded")) {
@@ -58,14 +55,16 @@ async function execCmd(command, logger, signal) {
58
55
  "stdout maxBuffer length exceeded. This likely means that youre trying to process a very large file, and the ffmpeg process is running out of memory. Maybe check the image size of your cover art."
59
56
  );
60
57
  }
58
+ const execErr = error;
61
59
  logger?.error(error);
62
- logger?.info(stdout);
63
- throw new Error(stderr);
60
+ if (execErr.stdout) logger?.info(execErr.stdout);
61
+ const errorDetail = execErr.stderr || execErr.stdout || `Command failed: ${command}`;
62
+ throw new Error(errorDetail);
64
63
  }
65
64
  }
66
65
  const getTrackInfo = (0, import_memoize.default)(async function getTrackInfo2(path, logger) {
67
66
  const stdout = await execCmd(
68
- `ffprobe -i ${(0, import_shell.quotePath)(path)} -show_format -of json`,
67
+ `ffprobe -v error -i ${(0, import_shell.quotePath)(path)} -show_format -of json`,
69
68
  logger
70
69
  );
71
70
  const info = JSON.parse(stdout);
@@ -8,14 +8,11 @@ import { areSameType } from "../process/mime.js";
8
8
  import { quotePath } from "./shell.js";
9
9
  const execPromise = promisify(exec);
10
10
  async function execCmd(command, logger, signal) {
11
- let stdout = "";
12
- let stderr = "";
13
11
  try {
14
- ;
15
- ({ stdout, stderr } = await execPromise(command, {
12
+ const { stdout } = await execPromise(command, {
16
13
  maxBuffer: 50 * 1024 * 1024,
17
14
  signal: signal ?? void 0
18
- }));
15
+ });
19
16
  return stdout;
20
17
  } catch (error) {
21
18
  if (error instanceof RangeError && error.message.includes("stdout maxBuffer length exceeded")) {
@@ -23,14 +20,16 @@ async function execCmd(command, logger, signal) {
23
20
  "stdout maxBuffer length exceeded. This likely means that youre trying to process a very large file, and the ffmpeg process is running out of memory. Maybe check the image size of your cover art."
24
21
  );
25
22
  }
23
+ const execErr = error;
26
24
  logger?.error(error);
27
- logger?.info(stdout);
28
- throw new Error(stderr);
25
+ if (execErr.stdout) logger?.info(execErr.stdout);
26
+ const errorDetail = execErr.stderr || execErr.stdout || `Command failed: ${command}`;
27
+ throw new Error(errorDetail);
29
28
  }
30
29
  }
31
30
  const getTrackInfo = memoize(async function getTrackInfo2(path, logger) {
32
31
  const stdout = await execCmd(
33
- `ffprobe -i ${quotePath(path)} -show_format -of json`,
32
+ `ffprobe -v error -i ${quotePath(path)} -show_format -of json`,
34
33
  logger
35
34
  );
36
35
  const info = JSON.parse(stdout);
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var readium_exports = {};
20
+ __export(readium_exports, {
21
+ generateGuidedNavigationDocuments: () => import_guidedNavigation.generateGuidedNavigationDocuments,
22
+ generateGuidedNavigationManifest: () => import_guidedNavigation.generateGuidedNavigationManifest,
23
+ generateReadiumManifest: () => import_manifest.generateReadiumManifest
24
+ });
25
+ module.exports = __toCommonJS(readium_exports);
26
+ var import_manifest = require("./manifest.cjs");
27
+ var import_guidedNavigation = require("./guidedNavigation.cjs");
28
+ // Annotate the CommonJS export names for ESM import in node:
29
+ 0 && (module.exports = {
30
+ generateGuidedNavigationDocuments,
31
+ generateGuidedNavigationManifest,
32
+ generateReadiumManifest
33
+ });
@@ -0,0 +1,5 @@
1
+ export { generateReadiumManifest } from './manifest.cjs';
2
+ export { ReadiumWebPublicationManifest } from './manifest.types.cjs';
3
+ export { generateGuidedNavigationDocuments, generateGuidedNavigationManifest } from './guidedNavigation.cjs';
4
+ import '@storyteller-platform/epub';
5
+ import '@readium/shared';
@@ -0,0 +1,5 @@
1
+ export { generateReadiumManifest } from './manifest.js';
2
+ export { ReadiumWebPublicationManifest } from './manifest.types.js';
3
+ export { generateGuidedNavigationDocuments, generateGuidedNavigationManifest } from './guidedNavigation.js';
4
+ import '@storyteller-platform/epub';
5
+ import '@readium/shared';
@@ -0,0 +1,11 @@
1
+ import "../chunk-BIEQXUOY.js";
2
+ import { generateReadiumManifest } from "./manifest.js";
3
+ import {
4
+ generateGuidedNavigationDocuments,
5
+ generateGuidedNavigationManifest
6
+ } from "./guidedNavigation.js";
7
+ export {
8
+ generateGuidedNavigationDocuments,
9
+ generateGuidedNavigationManifest,
10
+ generateReadiumManifest
11
+ };
@@ -28,12 +28,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var manifest_exports = {};
30
30
  __export(manifest_exports, {
31
- generateManifest: () => generateManifest
31
+ generateReadiumManifest: () => generateReadiumManifest
32
32
  });
33
33
  module.exports = __toCommonJS(manifest_exports);
34
34
  var import_shared = require("@readium/shared");
35
35
  var import_smil_clockvalue = __toESM(require("smil-clockvalue"), 1);
36
- async function generateManifest(epub) {
36
+ const BYTES_PER_PAGE = 1024;
37
+ async function generateReadiumManifest(epub, options = {}) {
37
38
  const primaryLocale = await epub.getLanguage() ?? new Intl.Locale("en-US");
38
39
  const creators = await epub.getCreators();
39
40
  const authors = creators.filter((contributor) => contributor.role === "aut").map((author) => createContributor(author, primaryLocale));
@@ -53,9 +54,13 @@ async function generateManifest(epub) {
53
54
  const dcSubjects = await epub.getSubjects();
54
55
  const subjects = dcSubjects.map((subject) => {
55
56
  if (typeof subject === "string") {
56
- return new import_shared.Subject({ name: new import_shared.LocalizedString(subject) });
57
+ return new import_shared.Subject({
58
+ // TODO: should this be in primary locale?
59
+ name: new import_shared.LocalizedString(subject)
60
+ });
57
61
  }
58
62
  return new import_shared.Subject({
63
+ // TODO: should this be in primary locale?
59
64
  name: new import_shared.LocalizedString(subject.value),
60
65
  scheme: subject.authority,
61
66
  code: subject.term
@@ -83,9 +88,19 @@ async function generateManifest(epub) {
83
88
  const dir = await epub.getBaseDirection();
84
89
  const epubMetadata = await epub.getMetadata();
85
90
  const vocab = await epub.getPackageVocabularyPrefixes();
86
- const duration = epubMetadata.find(
87
- ({ properties }) => properties["property"] === "media:duration"
88
- )?.value;
91
+ let duration = void 0;
92
+ const refinesDurationMap = /* @__PURE__ */ new Map();
93
+ for (const dur of epubMetadata) {
94
+ if (dur.properties["property"] !== "media:duration") continue;
95
+ if (!dur.properties["refines"]) {
96
+ duration = dur.value ? (0, import_smil_clockvalue.default)(dur.value) / 1e3 : void 0;
97
+ continue;
98
+ }
99
+ const value = dur.value ? (0, import_smil_clockvalue.default)(dur.value) / 1e3 : void 0;
100
+ if (value) {
101
+ refinesDurationMap.set(dur.properties["refines"], value);
102
+ }
103
+ }
89
104
  const otherMetadata = epubMetadata.filter(
90
105
  (meta) => (meta.properties["property"]?.split(":")[0] ?? "") in vocab
91
106
  ).map((meta) => {
@@ -93,6 +108,9 @@ async function generateManifest(epub) {
93
108
  const scheme = vocab[prefix];
94
109
  return [`${scheme}#${property}`, meta.value];
95
110
  });
111
+ const spine = await epub.getSpineItems();
112
+ const epubManifest = await epub.getManifest();
113
+ const numberOfPages = options.inferPageCount ? await inferPageCount(epub, spine, options.signal) : void 0;
96
114
  const metadata = new import_shared.Metadata({
97
115
  title: new import_shared.LocalizedString(title ?? ""),
98
116
  conformsTo: [import_shared.Profile.EPUB],
@@ -121,12 +139,11 @@ async function generateManifest(epub) {
121
139
  ...dir !== "auto" && {
122
140
  readingProgression: dir === "ltr" ? import_shared.ReadingProgression.ltr : import_shared.ReadingProgression.rtl
123
141
  },
124
- // TODO: is this meant to be in milliseconds (as here) or seconds?
125
- ...duration !== void 0 && { duration: (0, import_smil_clockvalue.default)(duration) },
142
+ // it's seconds
143
+ ...duration !== void 0 && { duration },
144
+ ...numberOfPages !== void 0 && { numberOfPages },
126
145
  otherMetadata: Object.fromEntries(otherMetadata)
127
146
  });
128
- const spine = await epub.getSpineItems();
129
- const epubManifest = await epub.getManifest();
130
147
  const readingOrder = await Promise.all(
131
148
  spine.map(async (item) => {
132
149
  const link = new import_shared.Link({
@@ -158,9 +175,9 @@ async function generateManifest(epub) {
158
175
  rels.add("cover");
159
176
  }
160
177
  if (item.mediaType === "application/xhtml+xml") {
161
- rels.add("content");
178
+ rels.add("contents");
162
179
  }
163
- const otherMetadata2 = epubMetadata.filter((meta) => meta.properties["refines"] === `#${item.id}`).filter(
180
+ const otherResourceMetadata = epubMetadata.filter((meta) => meta.properties["refines"] === `#${item.id}`).filter(
164
181
  (meta) => (meta.properties["property"]?.split(":")[0] ?? "") in vocab
165
182
  ).map((meta) => {
166
183
  const prefix = meta.properties["property"].split(":")[0];
@@ -171,16 +188,13 @@ async function generateManifest(epub) {
171
188
  href: await epub.resolveHref(item.href, void 0, { toRoot: true }),
172
189
  ...item.mediaType && { type: item.mediaType },
173
190
  rels,
174
- properties: new import_shared.Properties(Object.fromEntries(otherMetadata2))
191
+ properties: new import_shared.Properties(Object.fromEntries(otherResourceMetadata))
175
192
  });
176
193
  if (!item.mediaOverlay) return link;
177
194
  const mediaOverlayItem = epubManifest[item.id];
178
195
  if (!mediaOverlayItem) return link;
179
- const refinedBy = epubMetadata.find(
180
- ({ properties }) => properties["property"] === "media:duration" && properties["refines"] === `#${mediaOverlayItem.id}`
181
- );
182
- if (!refinedBy?.value) return link;
183
- const duration2 = (0, import_smil_clockvalue.default)(refinedBy.value);
196
+ const duration2 = refinesDurationMap.get(`#${item.mediaOverlay}`) || refinesDurationMap.get(`#${mediaOverlayItem.id}`);
197
+ if (!duration2) return link;
184
198
  return new import_shared.Link({
185
199
  href: link.href,
186
200
  type: link.mediaType.string,
@@ -210,7 +224,7 @@ async function generateManifest(epub) {
210
224
  })
211
225
  ]);
212
226
  }
213
- return new import_shared.Manifest({
227
+ const manifest = new import_shared.Manifest({
214
228
  context: ["https://readium.org/webpub-manifest/context.jsonld"],
215
229
  metadata,
216
230
  readingOrder: new import_shared.Links(readingOrder),
@@ -225,6 +239,25 @@ async function generateManifest(epub) {
225
239
  ...toc && { toc: new import_shared.Links(toc) },
226
240
  subcollections
227
241
  });
242
+ return manifest.serialize();
243
+ }
244
+ async function inferPageCount(epub, spine, signal) {
245
+ let total = 0;
246
+ for (const item of spine) {
247
+ if (signal?.aborted) {
248
+ throw new (signal.reason instanceof Error ? signal.reason.constructor : Error)(
249
+ signal.reason instanceof Error ? signal.reason.message : "Aborted while inferring page count"
250
+ );
251
+ }
252
+ if (item.mediaType !== "application/xhtml+xml") continue;
253
+ try {
254
+ const length = await epub.getItemArchiveLength(item.id);
255
+ total += Math.max(1, Math.ceil(length / BYTES_PER_PAGE));
256
+ } catch {
257
+ total += 1;
258
+ }
259
+ }
260
+ return total > 0 ? total : void 0;
228
261
  }
229
262
  function createContributor(dcCreator, primaryLocale) {
230
263
  return new import_shared.Contributor({
@@ -256,5 +289,5 @@ function createLinkTree(navList) {
256
289
  }
257
290
  // Annotate the CommonJS export names for ESM import in node:
258
291
  0 && (module.exports = {
259
- generateManifest
292
+ generateReadiumManifest
260
293
  });
@@ -1,6 +1,17 @@
1
- import { Manifest } from '@readium/shared';
2
- import { Epub } from '@storyteller-platform/epub';
1
+ import { EpubReader } from '@storyteller-platform/epub';
2
+ import { ReadiumWebPublicationManifest } from './manifest.types.cjs';
3
3
 
4
- declare function generateManifest(epub: Epub): Promise<Manifest>;
4
+ interface ReadiumManifestOptions {
5
+ /**
6
+ * if true, infer a `numberOfPages`
7
+ * uses the compressed size of the entries, see {@link https://github.com/readium/architecture/issues/123}
8
+ */
9
+ inferPageCount?: boolean;
10
+ signal?: AbortSignal;
11
+ }
12
+ /**
13
+ * build a Readium WebPub manifest for an EPUB
14
+ */
15
+ declare function generateReadiumManifest(epub: EpubReader, options?: ReadiumManifestOptions): Promise<ReadiumWebPublicationManifest>;
5
16
 
6
- export { generateManifest };
17
+ export { type ReadiumManifestOptions, generateReadiumManifest };
@@ -1,6 +1,17 @@
1
- import { Manifest } from '@readium/shared';
2
- import { Epub } from '@storyteller-platform/epub';
1
+ import { EpubReader } from '@storyteller-platform/epub';
2
+ import { ReadiumWebPublicationManifest } from './manifest.types.js';
3
3
 
4
- declare function generateManifest(epub: Epub): Promise<Manifest>;
4
+ interface ReadiumManifestOptions {
5
+ /**
6
+ * if true, infer a `numberOfPages`
7
+ * uses the compressed size of the entries, see {@link https://github.com/readium/architecture/issues/123}
8
+ */
9
+ inferPageCount?: boolean;
10
+ signal?: AbortSignal;
11
+ }
12
+ /**
13
+ * build a Readium WebPub manifest for an EPUB
14
+ */
15
+ declare function generateReadiumManifest(epub: EpubReader, options?: ReadiumManifestOptions): Promise<ReadiumWebPublicationManifest>;
5
16
 
6
- export { generateManifest };
17
+ export { type ReadiumManifestOptions, generateReadiumManifest };
@@ -16,7 +16,8 @@ import {
16
16
  Subjects
17
17
  } from "@readium/shared";
18
18
  import clockvalue from "smil-clockvalue";
19
- async function generateManifest(epub) {
19
+ const BYTES_PER_PAGE = 1024;
20
+ async function generateReadiumManifest(epub, options = {}) {
20
21
  const primaryLocale = await epub.getLanguage() ?? new Intl.Locale("en-US");
21
22
  const creators = await epub.getCreators();
22
23
  const authors = creators.filter((contributor) => contributor.role === "aut").map((author) => createContributor(author, primaryLocale));
@@ -36,9 +37,13 @@ async function generateManifest(epub) {
36
37
  const dcSubjects = await epub.getSubjects();
37
38
  const subjects = dcSubjects.map((subject) => {
38
39
  if (typeof subject === "string") {
39
- return new Subject({ name: new LocalizedString(subject) });
40
+ return new Subject({
41
+ // TODO: should this be in primary locale?
42
+ name: new LocalizedString(subject)
43
+ });
40
44
  }
41
45
  return new Subject({
46
+ // TODO: should this be in primary locale?
42
47
  name: new LocalizedString(subject.value),
43
48
  scheme: subject.authority,
44
49
  code: subject.term
@@ -66,9 +71,19 @@ async function generateManifest(epub) {
66
71
  const dir = await epub.getBaseDirection();
67
72
  const epubMetadata = await epub.getMetadata();
68
73
  const vocab = await epub.getPackageVocabularyPrefixes();
69
- const duration = epubMetadata.find(
70
- ({ properties }) => properties["property"] === "media:duration"
71
- )?.value;
74
+ let duration = void 0;
75
+ const refinesDurationMap = /* @__PURE__ */ new Map();
76
+ for (const dur of epubMetadata) {
77
+ if (dur.properties["property"] !== "media:duration") continue;
78
+ if (!dur.properties["refines"]) {
79
+ duration = dur.value ? clockvalue(dur.value) / 1e3 : void 0;
80
+ continue;
81
+ }
82
+ const value = dur.value ? clockvalue(dur.value) / 1e3 : void 0;
83
+ if (value) {
84
+ refinesDurationMap.set(dur.properties["refines"], value);
85
+ }
86
+ }
72
87
  const otherMetadata = epubMetadata.filter(
73
88
  (meta) => (meta.properties["property"]?.split(":")[0] ?? "") in vocab
74
89
  ).map((meta) => {
@@ -76,6 +91,9 @@ async function generateManifest(epub) {
76
91
  const scheme = vocab[prefix];
77
92
  return [`${scheme}#${property}`, meta.value];
78
93
  });
94
+ const spine = await epub.getSpineItems();
95
+ const epubManifest = await epub.getManifest();
96
+ const numberOfPages = options.inferPageCount ? await inferPageCount(epub, spine, options.signal) : void 0;
79
97
  const metadata = new Metadata({
80
98
  title: new LocalizedString(title ?? ""),
81
99
  conformsTo: [Profile.EPUB],
@@ -104,12 +122,11 @@ async function generateManifest(epub) {
104
122
  ...dir !== "auto" && {
105
123
  readingProgression: dir === "ltr" ? ReadingProgression.ltr : ReadingProgression.rtl
106
124
  },
107
- // TODO: is this meant to be in milliseconds (as here) or seconds?
108
- ...duration !== void 0 && { duration: clockvalue(duration) },
125
+ // it's seconds
126
+ ...duration !== void 0 && { duration },
127
+ ...numberOfPages !== void 0 && { numberOfPages },
109
128
  otherMetadata: Object.fromEntries(otherMetadata)
110
129
  });
111
- const spine = await epub.getSpineItems();
112
- const epubManifest = await epub.getManifest();
113
130
  const readingOrder = await Promise.all(
114
131
  spine.map(async (item) => {
115
132
  const link = new Link({
@@ -141,9 +158,9 @@ async function generateManifest(epub) {
141
158
  rels.add("cover");
142
159
  }
143
160
  if (item.mediaType === "application/xhtml+xml") {
144
- rels.add("content");
161
+ rels.add("contents");
145
162
  }
146
- const otherMetadata2 = epubMetadata.filter((meta) => meta.properties["refines"] === `#${item.id}`).filter(
163
+ const otherResourceMetadata = epubMetadata.filter((meta) => meta.properties["refines"] === `#${item.id}`).filter(
147
164
  (meta) => (meta.properties["property"]?.split(":")[0] ?? "") in vocab
148
165
  ).map((meta) => {
149
166
  const prefix = meta.properties["property"].split(":")[0];
@@ -154,16 +171,13 @@ async function generateManifest(epub) {
154
171
  href: await epub.resolveHref(item.href, void 0, { toRoot: true }),
155
172
  ...item.mediaType && { type: item.mediaType },
156
173
  rels,
157
- properties: new Properties(Object.fromEntries(otherMetadata2))
174
+ properties: new Properties(Object.fromEntries(otherResourceMetadata))
158
175
  });
159
176
  if (!item.mediaOverlay) return link;
160
177
  const mediaOverlayItem = epubManifest[item.id];
161
178
  if (!mediaOverlayItem) return link;
162
- const refinedBy = epubMetadata.find(
163
- ({ properties }) => properties["property"] === "media:duration" && properties["refines"] === `#${mediaOverlayItem.id}`
164
- );
165
- if (!refinedBy?.value) return link;
166
- const duration2 = clockvalue(refinedBy.value);
179
+ const duration2 = refinesDurationMap.get(`#${item.mediaOverlay}`) || refinesDurationMap.get(`#${mediaOverlayItem.id}`);
180
+ if (!duration2) return link;
167
181
  return new Link({
168
182
  href: link.href,
169
183
  type: link.mediaType.string,
@@ -193,7 +207,7 @@ async function generateManifest(epub) {
193
207
  })
194
208
  ]);
195
209
  }
196
- return new Manifest({
210
+ const manifest = new Manifest({
197
211
  context: ["https://readium.org/webpub-manifest/context.jsonld"],
198
212
  metadata,
199
213
  readingOrder: new Links(readingOrder),
@@ -208,6 +222,25 @@ async function generateManifest(epub) {
208
222
  ...toc && { toc: new Links(toc) },
209
223
  subcollections
210
224
  });
225
+ return manifest.serialize();
226
+ }
227
+ async function inferPageCount(epub, spine, signal) {
228
+ let total = 0;
229
+ for (const item of spine) {
230
+ if (signal?.aborted) {
231
+ throw new (signal.reason instanceof Error ? signal.reason.constructor : Error)(
232
+ signal.reason instanceof Error ? signal.reason.message : "Aborted while inferring page count"
233
+ );
234
+ }
235
+ if (item.mediaType !== "application/xhtml+xml") continue;
236
+ try {
237
+ const length = await epub.getItemArchiveLength(item.id);
238
+ total += Math.max(1, Math.ceil(length / BYTES_PER_PAGE));
239
+ } catch {
240
+ total += 1;
241
+ }
242
+ }
243
+ return total > 0 ? total : void 0;
211
244
  }
212
245
  function createContributor(dcCreator, primaryLocale) {
213
246
  return new Contributor({
@@ -238,5 +271,5 @@ function createLinkTree(navList) {
238
271
  );
239
272
  }
240
273
  export {
241
- generateManifest
274
+ generateReadiumManifest
242
275
  };
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+ var manifest_types_exports = {};
16
+ module.exports = __toCommonJS(manifest_types_exports);