@storyteller-platform/align 0.1.27 → 0.1.28

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.
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var guidedNavigation_exports = {};
30
+ __export(guidedNavigation_exports, {
31
+ generateGuidedNavigationDocuments: () => generateGuidedNavigationDocuments,
32
+ generateGuidedNavigationManifest: () => generateGuidedNavigationManifest
33
+ });
34
+ module.exports = __toCommonJS(guidedNavigation_exports);
35
+ var import_shared = require("@readium/shared");
36
+ var import_change_case = require("change-case");
37
+ var import_itertools = require("itertools");
38
+ var import_smil_clockvalue = __toESM(require("smil-clockvalue"), 1);
39
+ var import_audiobook = require("@storyteller-platform/audiobook");
40
+ var import_epub = require("@storyteller-platform/epub");
41
+ function generateGuidedNavigationManifest(title, guidedNavDocs) {
42
+ const readingOrder = [];
43
+ for (const doc of guidedNavDocs) {
44
+ const href = doc.links?.findWithRel("self")?.href;
45
+ if (!href) continue;
46
+ const textref = doc.guided?.[0]?.textref;
47
+ if (!textref) continue;
48
+ const referencedAudioFiles = {};
49
+ const pars = flatten(doc.guided ?? []);
50
+ for (const par of pars) {
51
+ if (!par.audioFile) continue;
52
+ const range = par.audioTime;
53
+ if (!range) continue;
54
+ const [startString, endString] = range.slice(2).split(",");
55
+ const start = parseFloat(startString ?? "0");
56
+ const end = endString ? parseFloat(endString) : null;
57
+ const existing = referencedAudioFiles[par.audioFile];
58
+ if (!existing) {
59
+ referencedAudioFiles[par.audioFile] = {
60
+ start,
61
+ end
62
+ };
63
+ continue;
64
+ }
65
+ existing.end = end;
66
+ }
67
+ const audioReferences = Object.entries(referencedAudioFiles).map(
68
+ ([audioFile, { start, end }]) => ({
69
+ href: `${audioFile}#t=${start},${end}`,
70
+ type: (0, import_audiobook.lookupAudioMime)(audioFile)
71
+ })
72
+ );
73
+ readingOrder.push(
74
+ new import_shared.Link({
75
+ href,
76
+ properties: new import_shared.Properties({
77
+ references: [
78
+ {
79
+ href: textref,
80
+ type: "application/xhtml+xml"
81
+ },
82
+ ...audioReferences
83
+ ]
84
+ })
85
+ })
86
+ );
87
+ }
88
+ return new import_shared.Manifest({
89
+ metadata: new import_shared.Metadata({
90
+ title,
91
+ conformsTo: [
92
+ "https://readium.org/webpub-manifest/profiles/guided-navigation"
93
+ ]
94
+ }),
95
+ links: new import_shared.Links([
96
+ new import_shared.Link({
97
+ href: "manifest.json",
98
+ type: "application/webpub+json",
99
+ rels: /* @__PURE__ */ new Set(["self"])
100
+ })
101
+ ]),
102
+ readingOrder: new import_shared.Links(readingOrder)
103
+ });
104
+ }
105
+ async function generateGuidedNavigationDocuments(epub) {
106
+ const manifest = await epub.getManifest();
107
+ const spine = await epub.getSpineItems();
108
+ const mediaOverlays = [];
109
+ for (const item of spine) {
110
+ if (!item.mediaOverlay) continue;
111
+ const mediaOverlayItem = manifest[item.mediaOverlay];
112
+ if (!mediaOverlayItem) continue;
113
+ mediaOverlays.push(mediaOverlayItem);
114
+ }
115
+ const guidedNavDocs = [];
116
+ for (const [i, overlay] of (0, import_itertools.enumerate)(mediaOverlays)) {
117
+ const contents = await epub.readItemContents(overlay.id, "utf-8");
118
+ const xml = import_epub.Epub.xmlParser.parse(contents);
119
+ const body = import_epub.Epub.findXmlDescendantByName("body", xml);
120
+ if (!body) continue;
121
+ const links = [];
122
+ const prevOverlay = mediaOverlays[i - 1];
123
+ if (prevOverlay) {
124
+ links.push(
125
+ new import_shared.Link({
126
+ rels: /* @__PURE__ */ new Set(["prev"]),
127
+ href: `GND/${prevOverlay.id}.json`,
128
+ type: "application/guided-navigation+json"
129
+ })
130
+ );
131
+ }
132
+ links.push(
133
+ new import_shared.Link({
134
+ rels: /* @__PURE__ */ new Set(["self"]),
135
+ href: `GND/${overlay.id}.json`,
136
+ type: "application/guided-navigation+json"
137
+ })
138
+ );
139
+ const nextOverlay = mediaOverlays[i + 1];
140
+ if (nextOverlay) {
141
+ links.push(
142
+ new import_shared.Link({
143
+ rels: /* @__PURE__ */ new Set(["next"]),
144
+ href: `GND/${nextOverlay.id}.json`,
145
+ type: "application/guided-navigation+json"
146
+ })
147
+ );
148
+ }
149
+ const guidedNavDoc = new import_shared.GuidedNavigationDocument({
150
+ links: new import_shared.Links(links),
151
+ guided: await parseGuidedNavigationObjects(
152
+ epub,
153
+ overlay.href,
154
+ import_epub.Epub.getXmlChildren(body)
155
+ )
156
+ });
157
+ guidedNavDocs.push(guidedNavDoc);
158
+ }
159
+ return guidedNavDocs;
160
+ }
161
+ async function parseGuidedNavigationObjects(epub, overlayHref, xml) {
162
+ const guidedNavObjects = [];
163
+ const children = xml.filter(
164
+ (node) => !import_epub.Epub.isXmlTextNode(node) && ["seq", "par"].includes(import_epub.Epub.getXmlElementName(node))
165
+ );
166
+ for (const element of children) {
167
+ if (import_epub.Epub.getXmlElementName(element) === "par") {
168
+ const text = import_epub.Epub.findXmlChildByName("text", import_epub.Epub.getXmlChildren(element));
169
+ const audio = import_epub.Epub.findXmlChildByName(
170
+ "audio",
171
+ import_epub.Epub.getXmlChildren(element)
172
+ );
173
+ if (!text || !audio) continue;
174
+ const textSrc = import_epub.Epub.getXmlAttributes(text)["src"];
175
+ const { src: audioSrc, clipBegin, clipEnd } = import_epub.Epub.getXmlAttributes(audio);
176
+ if (!textSrc || !audioSrc || clipBegin === void 0 || clipEnd === void 0) {
177
+ continue;
178
+ }
179
+ const textref = await epub.resolveHref(textSrc, overlayHref, {
180
+ toRoot: true
181
+ });
182
+ const audioref = await epub.resolveHref(audioSrc, overlayHref, {
183
+ toRoot: true
184
+ });
185
+ const clipBeginSeconds = (0, import_smil_clockvalue.default)(clipBegin) / 1e3;
186
+ const clipEndSeconds = (0, import_smil_clockvalue.default)(clipEnd) / 1e3;
187
+ guidedNavObjects.push(
188
+ new import_shared.GuidedNavigationObject({
189
+ // Slice off the leading slash
190
+ textref,
191
+ audioref: `${audioref}#t=${clipBeginSeconds},${clipEndSeconds}`
192
+ })
193
+ );
194
+ }
195
+ if (import_epub.Epub.getXmlElementName(element) === "seq") {
196
+ const attrs = import_epub.Epub.getXmlAttributes(element);
197
+ const epubType = attrs["epub:type"];
198
+ const role = epubType && (0, import_change_case.camelCase)(epubType);
199
+ const textref = attrs["epub:textref"];
200
+ if (!textref) continue;
201
+ const children2 = await parseGuidedNavigationObjects(
202
+ epub,
203
+ overlayHref,
204
+ import_epub.Epub.getXmlChildren(element)
205
+ );
206
+ guidedNavObjects.push(
207
+ new import_shared.GuidedNavigationObject({
208
+ textref: await epub.resolveHref(textref, overlayHref, {
209
+ toRoot: true
210
+ }),
211
+ ...role && { role: /* @__PURE__ */ new Set([role]) },
212
+ children: children2
213
+ })
214
+ );
215
+ }
216
+ }
217
+ return guidedNavObjects;
218
+ }
219
+ function flatten(input) {
220
+ const pars = [];
221
+ for (const obj of input) {
222
+ if (obj.children) {
223
+ pars.push(...flatten(obj.children));
224
+ } else {
225
+ pars.push(obj);
226
+ }
227
+ }
228
+ return pars;
229
+ }
230
+ // Annotate the CommonJS export names for ESM import in node:
231
+ 0 && (module.exports = {
232
+ generateGuidedNavigationDocuments,
233
+ generateGuidedNavigationManifest
234
+ });
@@ -0,0 +1,7 @@
1
+ import { LocalizedString, GuidedNavigationDocument, Manifest } from '@readium/shared';
2
+ import { Epub } from '@storyteller-platform/epub';
3
+
4
+ declare function generateGuidedNavigationManifest(title: LocalizedString, guidedNavDocs: GuidedNavigationDocument[]): Manifest;
5
+ declare function generateGuidedNavigationDocuments(epub: Epub): Promise<GuidedNavigationDocument[]>;
6
+
7
+ export { generateGuidedNavigationDocuments, generateGuidedNavigationManifest };
@@ -0,0 +1,7 @@
1
+ import { LocalizedString, GuidedNavigationDocument, Manifest } from '@readium/shared';
2
+ import { Epub } from '@storyteller-platform/epub';
3
+
4
+ declare function generateGuidedNavigationManifest(title: LocalizedString, guidedNavDocs: GuidedNavigationDocument[]): Manifest;
5
+ declare function generateGuidedNavigationDocuments(epub: Epub): Promise<GuidedNavigationDocument[]>;
6
+
7
+ export { generateGuidedNavigationDocuments, generateGuidedNavigationManifest };
@@ -0,0 +1,210 @@
1
+ import "../chunk-BIEQXUOY.js";
2
+ import {
3
+ GuidedNavigationDocument,
4
+ GuidedNavigationObject,
5
+ Link,
6
+ Links,
7
+ Manifest,
8
+ Metadata,
9
+ Properties
10
+ } from "@readium/shared";
11
+ import { camelCase } from "change-case";
12
+ import { enumerate } from "itertools";
13
+ import clockvalue from "smil-clockvalue";
14
+ import { lookupAudioMime } from "@storyteller-platform/audiobook";
15
+ import {
16
+ Epub
17
+ } from "@storyteller-platform/epub";
18
+ function generateGuidedNavigationManifest(title, guidedNavDocs) {
19
+ const readingOrder = [];
20
+ for (const doc of guidedNavDocs) {
21
+ const href = doc.links?.findWithRel("self")?.href;
22
+ if (!href) continue;
23
+ const textref = doc.guided?.[0]?.textref;
24
+ if (!textref) continue;
25
+ const referencedAudioFiles = {};
26
+ const pars = flatten(doc.guided ?? []);
27
+ for (const par of pars) {
28
+ if (!par.audioFile) continue;
29
+ const range = par.audioTime;
30
+ if (!range) continue;
31
+ const [startString, endString] = range.slice(2).split(",");
32
+ const start = parseFloat(startString ?? "0");
33
+ const end = endString ? parseFloat(endString) : null;
34
+ const existing = referencedAudioFiles[par.audioFile];
35
+ if (!existing) {
36
+ referencedAudioFiles[par.audioFile] = {
37
+ start,
38
+ end
39
+ };
40
+ continue;
41
+ }
42
+ existing.end = end;
43
+ }
44
+ const audioReferences = Object.entries(referencedAudioFiles).map(
45
+ ([audioFile, { start, end }]) => ({
46
+ href: `${audioFile}#t=${start},${end}`,
47
+ type: lookupAudioMime(audioFile)
48
+ })
49
+ );
50
+ readingOrder.push(
51
+ new Link({
52
+ href,
53
+ properties: new Properties({
54
+ references: [
55
+ {
56
+ href: textref,
57
+ type: "application/xhtml+xml"
58
+ },
59
+ ...audioReferences
60
+ ]
61
+ })
62
+ })
63
+ );
64
+ }
65
+ return new Manifest({
66
+ metadata: new Metadata({
67
+ title,
68
+ conformsTo: [
69
+ "https://readium.org/webpub-manifest/profiles/guided-navigation"
70
+ ]
71
+ }),
72
+ links: new Links([
73
+ new Link({
74
+ href: "manifest.json",
75
+ type: "application/webpub+json",
76
+ rels: /* @__PURE__ */ new Set(["self"])
77
+ })
78
+ ]),
79
+ readingOrder: new Links(readingOrder)
80
+ });
81
+ }
82
+ async function generateGuidedNavigationDocuments(epub) {
83
+ const manifest = await epub.getManifest();
84
+ const spine = await epub.getSpineItems();
85
+ const mediaOverlays = [];
86
+ for (const item of spine) {
87
+ if (!item.mediaOverlay) continue;
88
+ const mediaOverlayItem = manifest[item.mediaOverlay];
89
+ if (!mediaOverlayItem) continue;
90
+ mediaOverlays.push(mediaOverlayItem);
91
+ }
92
+ const guidedNavDocs = [];
93
+ for (const [i, overlay] of enumerate(mediaOverlays)) {
94
+ const contents = await epub.readItemContents(overlay.id, "utf-8");
95
+ const xml = Epub.xmlParser.parse(contents);
96
+ const body = Epub.findXmlDescendantByName("body", xml);
97
+ if (!body) continue;
98
+ const links = [];
99
+ const prevOverlay = mediaOverlays[i - 1];
100
+ if (prevOverlay) {
101
+ links.push(
102
+ new Link({
103
+ rels: /* @__PURE__ */ new Set(["prev"]),
104
+ href: `GND/${prevOverlay.id}.json`,
105
+ type: "application/guided-navigation+json"
106
+ })
107
+ );
108
+ }
109
+ links.push(
110
+ new Link({
111
+ rels: /* @__PURE__ */ new Set(["self"]),
112
+ href: `GND/${overlay.id}.json`,
113
+ type: "application/guided-navigation+json"
114
+ })
115
+ );
116
+ const nextOverlay = mediaOverlays[i + 1];
117
+ if (nextOverlay) {
118
+ links.push(
119
+ new Link({
120
+ rels: /* @__PURE__ */ new Set(["next"]),
121
+ href: `GND/${nextOverlay.id}.json`,
122
+ type: "application/guided-navigation+json"
123
+ })
124
+ );
125
+ }
126
+ const guidedNavDoc = new GuidedNavigationDocument({
127
+ links: new Links(links),
128
+ guided: await parseGuidedNavigationObjects(
129
+ epub,
130
+ overlay.href,
131
+ Epub.getXmlChildren(body)
132
+ )
133
+ });
134
+ guidedNavDocs.push(guidedNavDoc);
135
+ }
136
+ return guidedNavDocs;
137
+ }
138
+ async function parseGuidedNavigationObjects(epub, overlayHref, xml) {
139
+ const guidedNavObjects = [];
140
+ const children = xml.filter(
141
+ (node) => !Epub.isXmlTextNode(node) && ["seq", "par"].includes(Epub.getXmlElementName(node))
142
+ );
143
+ for (const element of children) {
144
+ if (Epub.getXmlElementName(element) === "par") {
145
+ const text = Epub.findXmlChildByName("text", Epub.getXmlChildren(element));
146
+ const audio = Epub.findXmlChildByName(
147
+ "audio",
148
+ Epub.getXmlChildren(element)
149
+ );
150
+ if (!text || !audio) continue;
151
+ const textSrc = Epub.getXmlAttributes(text)["src"];
152
+ const { src: audioSrc, clipBegin, clipEnd } = Epub.getXmlAttributes(audio);
153
+ if (!textSrc || !audioSrc || clipBegin === void 0 || clipEnd === void 0) {
154
+ continue;
155
+ }
156
+ const textref = await epub.resolveHref(textSrc, overlayHref, {
157
+ toRoot: true
158
+ });
159
+ const audioref = await epub.resolveHref(audioSrc, overlayHref, {
160
+ toRoot: true
161
+ });
162
+ const clipBeginSeconds = clockvalue(clipBegin) / 1e3;
163
+ const clipEndSeconds = clockvalue(clipEnd) / 1e3;
164
+ guidedNavObjects.push(
165
+ new GuidedNavigationObject({
166
+ // Slice off the leading slash
167
+ textref,
168
+ audioref: `${audioref}#t=${clipBeginSeconds},${clipEndSeconds}`
169
+ })
170
+ );
171
+ }
172
+ if (Epub.getXmlElementName(element) === "seq") {
173
+ const attrs = Epub.getXmlAttributes(element);
174
+ const epubType = attrs["epub:type"];
175
+ const role = epubType && camelCase(epubType);
176
+ const textref = attrs["epub:textref"];
177
+ if (!textref) continue;
178
+ const children2 = await parseGuidedNavigationObjects(
179
+ epub,
180
+ overlayHref,
181
+ Epub.getXmlChildren(element)
182
+ );
183
+ guidedNavObjects.push(
184
+ new GuidedNavigationObject({
185
+ textref: await epub.resolveHref(textref, overlayHref, {
186
+ toRoot: true
187
+ }),
188
+ ...role && { role: /* @__PURE__ */ new Set([role]) },
189
+ children: children2
190
+ })
191
+ );
192
+ }
193
+ }
194
+ return guidedNavObjects;
195
+ }
196
+ function flatten(input) {
197
+ const pars = [];
198
+ for (const obj of input) {
199
+ if (obj.children) {
200
+ pars.push(...flatten(obj.children));
201
+ } else {
202
+ pars.push(obj);
203
+ }
204
+ }
205
+ return pars;
206
+ }
207
+ export {
208
+ generateGuidedNavigationDocuments,
209
+ generateGuidedNavigationManifest
210
+ };