@storyteller-platform/align 0.1.17 → 0.1.19

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.
@@ -258,7 +258,8 @@ class Aligner {
258
258
  matchedSentence: chapterSentences[endSentence],
259
259
  nextSentence: chapterSentences[endSentence + 1] ?? null
260
260
  },
261
- chapterSentenceCount: sentenceRanges.length,
261
+ chapterSentenceCount: chapterSentences.length,
262
+ alignedSentenceCount: sentenceRanges.length,
262
263
  audioFiles: sentenceRanges.reduce((acc, range) => {
263
264
  const existing = acc.find(
264
265
  (context) => context.filepath === range.audiofile
@@ -347,7 +348,6 @@ class Aligner {
347
348
  return narrowed;
348
349
  }
349
350
  async alignBook(onProgress) {
350
- var _a, _b, _c, _d, _e, _f;
351
351
  const locale = this.languageOverride ?? await this.epub.getLanguage() ?? new Intl.Locale("en-US");
352
352
  this.timing.setMetadata("language", locale.toString());
353
353
  this.timing.setMetadata("granularity", this.granularity);
@@ -358,13 +358,13 @@ class Aligner {
358
358
  locale
359
359
  );
360
360
  for (let index = 0; index < spine.length; index++) {
361
- onProgress == null ? void 0 : onProgress(index / spine.length);
361
+ onProgress?.(index / spine.length);
362
362
  const spineItem = spine[index];
363
- (_a = this.logger) == null ? void 0 : _a.info(
363
+ this.logger?.info(
364
364
  `Aligning epub item #${index} : ${(0, import_posix.basename)(spineItem.href)}`
365
365
  );
366
366
  const chapterId = spineItem.id;
367
- if ((_c = (_b = manifest[chapterId]) == null ? void 0 : _b.properties) == null ? void 0 : _c.includes("nav")) {
367
+ if (manifest[chapterId]?.properties?.includes("nav")) {
368
368
  continue;
369
369
  }
370
370
  const chapterSentences = await this.getChapterSentences(chapterId);
@@ -375,12 +375,12 @@ class Aligner {
375
375
  );
376
376
  }
377
377
  if (chapterSentences.length === 0) {
378
- (_d = this.logger) == null ? void 0 : _d.info(`Chapter #${index} has no text; skipping`);
378
+ this.logger?.info(`Chapter #${index} has no text; skipping`);
379
379
  continue;
380
380
  }
381
381
  if (chapterSentences.length < 2 && // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
382
382
  chapterSentences[0].split(" ").length < 4) {
383
- (_e = this.logger) == null ? void 0 : _e.info(
383
+ this.logger?.info(
384
384
  `Chapter #${index} is fewer than four words; skipping`
385
385
  );
386
386
  continue;
@@ -390,7 +390,7 @@ class Aligner {
390
390
  transcriptionText
391
391
  );
392
392
  if (!boundaries) {
393
- (_f = this.logger) == null ? void 0 : _f.info(
393
+ this.logger?.info(
394
394
  `Could not find chapter #${index} in the transcripton`
395
395
  );
396
396
  continue;
@@ -29,6 +29,7 @@ interface ChapterReport {
29
29
  nextSentence: string | null;
30
30
  };
31
31
  chapterSentenceCount: number;
32
+ alignedSentenceCount: number;
32
33
  audioFiles: AudioFileContext[];
33
34
  }
34
35
  interface Report {
@@ -29,6 +29,7 @@ interface ChapterReport {
29
29
  nextSentence: string | null;
30
30
  };
31
31
  chapterSentenceCount: number;
32
+ alignedSentenceCount: number;
32
33
  audioFiles: AudioFileContext[];
33
34
  }
34
35
  interface Report {
@@ -192,7 +192,8 @@ class Aligner {
192
192
  matchedSentence: chapterSentences[endSentence],
193
193
  nextSentence: chapterSentences[endSentence + 1] ?? null
194
194
  },
195
- chapterSentenceCount: sentenceRanges.length,
195
+ chapterSentenceCount: chapterSentences.length,
196
+ alignedSentenceCount: sentenceRanges.length,
196
197
  audioFiles: sentenceRanges.reduce((acc, range) => {
197
198
  const existing = acc.find(
198
199
  (context) => context.filepath === range.audiofile
@@ -281,7 +282,6 @@ class Aligner {
281
282
  return narrowed;
282
283
  }
283
284
  async alignBook(onProgress) {
284
- var _a, _b, _c, _d, _e, _f;
285
285
  const locale = this.languageOverride ?? await this.epub.getLanguage() ?? new Intl.Locale("en-US");
286
286
  this.timing.setMetadata("language", locale.toString());
287
287
  this.timing.setMetadata("granularity", this.granularity);
@@ -292,13 +292,13 @@ class Aligner {
292
292
  locale
293
293
  );
294
294
  for (let index = 0; index < spine.length; index++) {
295
- onProgress == null ? void 0 : onProgress(index / spine.length);
295
+ onProgress?.(index / spine.length);
296
296
  const spineItem = spine[index];
297
- (_a = this.logger) == null ? void 0 : _a.info(
297
+ this.logger?.info(
298
298
  `Aligning epub item #${index} : ${basename(spineItem.href)}`
299
299
  );
300
300
  const chapterId = spineItem.id;
301
- if ((_c = (_b = manifest[chapterId]) == null ? void 0 : _b.properties) == null ? void 0 : _c.includes("nav")) {
301
+ if (manifest[chapterId]?.properties?.includes("nav")) {
302
302
  continue;
303
303
  }
304
304
  const chapterSentences = await this.getChapterSentences(chapterId);
@@ -309,12 +309,12 @@ class Aligner {
309
309
  );
310
310
  }
311
311
  if (chapterSentences.length === 0) {
312
- (_d = this.logger) == null ? void 0 : _d.info(`Chapter #${index} has no text; skipping`);
312
+ this.logger?.info(`Chapter #${index} has no text; skipping`);
313
313
  continue;
314
314
  }
315
315
  if (chapterSentences.length < 2 && // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
316
316
  chapterSentences[0].split(" ").length < 4) {
317
- (_e = this.logger) == null ? void 0 : _e.info(
317
+ this.logger?.info(
318
318
  `Chapter #${index} is fewer than four words; skipping`
319
319
  );
320
320
  continue;
@@ -324,7 +324,7 @@ class Aligner {
324
324
  transcriptionText
325
325
  );
326
326
  if (!boundaries) {
327
- (_f = this.logger) == null ? void 0 : _f.info(
327
+ this.logger?.info(
328
328
  `Could not find chapter #${index} in the transcripton`
329
329
  );
330
330
  continue;
package/dist/cli/bin.cjs CHANGED
@@ -137,7 +137,7 @@ async function main() {
137
137
  const controller = new AbortController();
138
138
  let progressBar;
139
139
  function resetProgressBar() {
140
- progressBar == null ? void 0 : progressBar.stop();
140
+ progressBar?.stop();
141
141
  progressBar = new import_cli_progress.SingleBar(
142
142
  { etaBuffer: 4, hideCursor: null, noTTYOutput: !process.stderr.isTTY },
143
143
  import_cli_progress.Presets.shades_classic
package/dist/cli/bin.js CHANGED
@@ -23,7 +23,7 @@ import { run } from "@optique/run";
23
23
  import { path } from "@optique/run/valueparser";
24
24
  import { Presets, SingleBar } from "cli-progress";
25
25
  import { Epub } from "@storyteller-platform/epub";
26
- import packageJson from "../../package.json";
26
+ import packageJson from "../../package.json" with { type: "json" };
27
27
  import { align } from "../align/align.js";
28
28
  import { alignCommand, alignParser } from "../align/parse.js";
29
29
  import { createLogger } from "../common/logging.js";
@@ -88,7 +88,7 @@ async function main() {
88
88
  const controller = new AbortController();
89
89
  let progressBar;
90
90
  function resetProgressBar() {
91
- progressBar == null ? void 0 : progressBar.stop();
91
+ progressBar?.stop();
92
92
  progressBar = new SingleBar(
93
93
  { etaBuffer: 4, hideCursor: null, noTTYOutput: !process.stderr.isTTY },
94
94
  Presets.shades_classic
@@ -58,8 +58,8 @@ async function execCmd(command, logger, signal) {
58
58
  "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
59
  );
60
60
  }
61
- logger == null ? void 0 : logger.error(error);
62
- logger == null ? void 0 : logger.info(stdout);
61
+ logger?.error(error);
62
+ logger?.info(stdout);
63
63
  throw new Error(stderr);
64
64
  }
65
65
  }
@@ -157,8 +157,8 @@ function commonFfmpegArguments(sourceExtension, destExtension, codec, bitrate) {
157
157
  }
158
158
  async function splitFile(input, output, start, end, encoding, signal, logger) {
159
159
  if (start === end) return false;
160
- logger == null ? void 0 : logger.info(
161
- `Splitting ${input} start: ${start} end: ${end}${(encoding == null ? void 0 : encoding.codec) ? ` codec: ${encoding.codec}` : ""}`
160
+ logger?.info(
161
+ `Splitting ${input} start: ${start} end: ${end}${encoding?.codec ? ` codec: ${encoding.codec}` : ""}`
162
162
  );
163
163
  const command = "ffmpeg";
164
164
  const args = [
@@ -172,8 +172,8 @@ async function splitFile(input, output, start, end, encoding, signal, logger) {
172
172
  ...commonFfmpegArguments(
173
173
  (0, import_node_path.extname)(input),
174
174
  (0, import_node_path.extname)(output),
175
- (encoding == null ? void 0 : encoding.codec) ?? null,
176
- (encoding == null ? void 0 : encoding.bitrate) ?? null
175
+ encoding?.codec ?? null,
176
+ encoding?.bitrate ?? null
177
177
  ),
178
178
  (0, import_shell.quotePath)(output)
179
179
  ];
@@ -189,15 +189,15 @@ async function splitFile(input, output, start, end, encoding, signal, logger) {
189
189
  return true;
190
190
  }
191
191
  async function transcodeFile(input, output, encoding, signal, logger) {
192
- if (!(encoding == null ? void 0 : encoding.codec) && (0, import_mime.areSameType)(input, output)) {
193
- logger == null ? void 0 : logger.info(
192
+ if (!encoding?.codec && (0, import_mime.areSameType)(input, output)) {
193
+ logger?.info(
194
194
  `Input and output container and codec are the same, copying ${input} to output directory`
195
195
  );
196
196
  await (0, import_promises.copyFile)(input, output);
197
197
  return;
198
198
  }
199
- logger == null ? void 0 : logger.info(
200
- `Transcoding ${input}${(encoding == null ? void 0 : encoding.codec) ? ` codec: ${encoding.codec}` : ""}`
199
+ logger?.info(
200
+ `Transcoding ${input}${encoding?.codec ? ` codec: ${encoding.codec}` : ""}`
201
201
  );
202
202
  const command = "ffmpeg";
203
203
  const args = [
@@ -207,8 +207,8 @@ async function transcodeFile(input, output, encoding, signal, logger) {
207
207
  ...commonFfmpegArguments(
208
208
  (0, import_node_path.extname)(input),
209
209
  (0, import_node_path.extname)(output),
210
- (encoding == null ? void 0 : encoding.codec) ?? null,
211
- (encoding == null ? void 0 : encoding.bitrate) ?? null
210
+ encoding?.codec ?? null,
211
+ encoding?.bitrate ?? null
212
212
  ),
213
213
  (0, import_shell.quotePath)(output)
214
214
  ];
@@ -23,8 +23,8 @@ async function execCmd(command, logger, signal) {
23
23
  "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
24
  );
25
25
  }
26
- logger == null ? void 0 : logger.error(error);
27
- logger == null ? void 0 : logger.info(stdout);
26
+ logger?.error(error);
27
+ logger?.info(stdout);
28
28
  throw new Error(stderr);
29
29
  }
30
30
  }
@@ -122,8 +122,8 @@ function commonFfmpegArguments(sourceExtension, destExtension, codec, bitrate) {
122
122
  }
123
123
  async function splitFile(input, output, start, end, encoding, signal, logger) {
124
124
  if (start === end) return false;
125
- logger == null ? void 0 : logger.info(
126
- `Splitting ${input} start: ${start} end: ${end}${(encoding == null ? void 0 : encoding.codec) ? ` codec: ${encoding.codec}` : ""}`
125
+ logger?.info(
126
+ `Splitting ${input} start: ${start} end: ${end}${encoding?.codec ? ` codec: ${encoding.codec}` : ""}`
127
127
  );
128
128
  const command = "ffmpeg";
129
129
  const args = [
@@ -137,8 +137,8 @@ async function splitFile(input, output, start, end, encoding, signal, logger) {
137
137
  ...commonFfmpegArguments(
138
138
  extname(input),
139
139
  extname(output),
140
- (encoding == null ? void 0 : encoding.codec) ?? null,
141
- (encoding == null ? void 0 : encoding.bitrate) ?? null
140
+ encoding?.codec ?? null,
141
+ encoding?.bitrate ?? null
142
142
  ),
143
143
  quotePath(output)
144
144
  ];
@@ -154,15 +154,15 @@ async function splitFile(input, output, start, end, encoding, signal, logger) {
154
154
  return true;
155
155
  }
156
156
  async function transcodeFile(input, output, encoding, signal, logger) {
157
- if (!(encoding == null ? void 0 : encoding.codec) && areSameType(input, output)) {
158
- logger == null ? void 0 : logger.info(
157
+ if (!encoding?.codec && areSameType(input, output)) {
158
+ logger?.info(
159
159
  `Input and output container and codec are the same, copying ${input} to output directory`
160
160
  );
161
161
  await copyFile(input, output);
162
162
  return;
163
163
  }
164
- logger == null ? void 0 : logger.info(
165
- `Transcoding ${input}${(encoding == null ? void 0 : encoding.codec) ? ` codec: ${encoding.codec}` : ""}`
164
+ logger?.info(
165
+ `Transcoding ${input}${encoding?.codec ? ` codec: ${encoding.codec}` : ""}`
166
166
  );
167
167
  const command = "ffmpeg";
168
168
  const args = [
@@ -172,8 +172,8 @@ async function transcodeFile(input, output, encoding, signal, logger) {
172
172
  ...commonFfmpegArguments(
173
173
  extname(input),
174
174
  extname(output),
175
- (encoding == null ? void 0 : encoding.codec) ?? null,
176
- (encoding == null ? void 0 : encoding.bitrate) ?? null
175
+ encoding?.codec ?? null,
176
+ encoding?.bitrate ?? null
177
177
  ),
178
178
  quotePath(output)
179
179
  ];
@@ -69,15 +69,14 @@ class Node {
69
69
  class NodeMap {
70
70
  map;
71
71
  constructor(entries) {
72
- const keyedEntries = entries == null ? void 0 : entries.map(
72
+ const keyedEntries = entries?.map(
73
73
  ([index, node]) => [`${index[0]}-${index[1]}`, { index, node }]
74
74
  );
75
75
  this.map = new Map(keyedEntries);
76
76
  }
77
77
  get([hypIndex, refIndex]) {
78
- var _a;
79
78
  const key = `${hypIndex}-${refIndex}`;
80
- return (_a = this.map.get(key)) == null ? void 0 : _a.node;
79
+ return this.map.get(key)?.node;
81
80
  }
82
81
  set([hypIndex, refIndex], node) {
83
82
  const key = `${hypIndex}-${refIndex}`;
@@ -159,7 +158,7 @@ class BacktraceGraph {
159
158
  */
160
159
  getPath({ sample } = { sample: false }) {
161
160
  let node = this.getNode(0, 0);
162
- (0, import_node_assert.default)(node == null ? void 0 : node.isRoot, "The node at (-1, -1) was expected to be a root node.");
161
+ (0, import_node_assert.default)(node?.isRoot, "The node at (-1, -1) was expected to be a root node.");
163
162
  const path = [];
164
163
  while (!node.isTerminal) {
165
164
  const opType = sample ? choose(Array.from(node.children.keys())) : (
@@ -211,7 +210,6 @@ class BacktraceGraph {
211
210
  * @returns A list of index tuples representing the end node of unambiguous span matches.
212
211
  */
213
212
  getUnambiguousTokenSpanMatches(ref) {
214
- var _a;
215
213
  ref = "_" + ref;
216
214
  const monoMatchEndNodes = /* @__PURE__ */ new Set();
217
215
  const refIndexes = new import_utils.Counter();
@@ -226,7 +224,7 @@ class BacktraceGraph {
226
224
  if (!this.nodes.has(_index)) {
227
225
  break;
228
226
  }
229
- if (!((_a = this.nodes.get(_index)) == null ? void 0 : _a.parents)) {
227
+ if (!this.nodes.get(_index)?.parents) {
230
228
  break;
231
229
  }
232
230
  if (ref[_refIndex] === import_utils.END_DELIMITER) {
@@ -272,8 +270,7 @@ class BacktraceGraph {
272
270
  * Add parents to the node at the given index based on the backtrace matrix.
273
271
  */
274
272
  addParentsFromBacktrace(index) {
275
- var _a;
276
- const node = (_a = this._nodes) == null ? void 0 : _a.get(index);
273
+ const node = this._nodes?.get(index);
277
274
  (0, import_node_assert.default)(
278
275
  !!node,
279
276
  `Node at index ${index.toString()} does not exist in the graph.`
@@ -42,15 +42,14 @@ class Node {
42
42
  class NodeMap {
43
43
  map;
44
44
  constructor(entries) {
45
- const keyedEntries = entries == null ? void 0 : entries.map(
45
+ const keyedEntries = entries?.map(
46
46
  ([index, node]) => [`${index[0]}-${index[1]}`, { index, node }]
47
47
  );
48
48
  this.map = new Map(keyedEntries);
49
49
  }
50
50
  get([hypIndex, refIndex]) {
51
- var _a;
52
51
  const key = `${hypIndex}-${refIndex}`;
53
- return (_a = this.map.get(key)) == null ? void 0 : _a.node;
52
+ return this.map.get(key)?.node;
54
53
  }
55
54
  set([hypIndex, refIndex], node) {
56
55
  const key = `${hypIndex}-${refIndex}`;
@@ -132,7 +131,7 @@ class BacktraceGraph {
132
131
  */
133
132
  getPath({ sample } = { sample: false }) {
134
133
  let node = this.getNode(0, 0);
135
- assert(node == null ? void 0 : node.isRoot, "The node at (-1, -1) was expected to be a root node.");
134
+ assert(node?.isRoot, "The node at (-1, -1) was expected to be a root node.");
136
135
  const path = [];
137
136
  while (!node.isTerminal) {
138
137
  const opType = sample ? choose(Array.from(node.children.keys())) : (
@@ -184,7 +183,6 @@ class BacktraceGraph {
184
183
  * @returns A list of index tuples representing the end node of unambiguous span matches.
185
184
  */
186
185
  getUnambiguousTokenSpanMatches(ref) {
187
- var _a;
188
186
  ref = "_" + ref;
189
187
  const monoMatchEndNodes = /* @__PURE__ */ new Set();
190
188
  const refIndexes = new Counter();
@@ -199,7 +197,7 @@ class BacktraceGraph {
199
197
  if (!this.nodes.has(_index)) {
200
198
  break;
201
199
  }
202
- if (!((_a = this.nodes.get(_index)) == null ? void 0 : _a.parents)) {
200
+ if (!this.nodes.get(_index)?.parents) {
203
201
  break;
204
202
  }
205
203
  if (ref[_refIndex] === END_DELIMITER) {
@@ -245,8 +243,7 @@ class BacktraceGraph {
245
243
  * Add parents to the node at the given index based on the backtrace matrix.
246
244
  */
247
245
  addParentsFromBacktrace(index) {
248
- var _a;
249
- const node = (_a = this._nodes) == null ? void 0 : _a.get(index);
246
+ const node = this._nodes?.get(index);
250
247
  assert(
251
248
  !!node,
252
249
  `Node at index ${index.toString()} does not exist in the graph.`
@@ -242,7 +242,6 @@ function isSubstitution(hypIndex, refIndex, lastHypIndex, lastRefIndex) {
242
242
  return !(refIndex === lastRefIndex || hypIndex === lastHypIndex);
243
243
  }
244
244
  function errorAlignBeamSearch(src, beamSize = 100) {
245
- var _a;
246
245
  const startPath = new Path(src);
247
246
  let beam = [startPath];
248
247
  let pruneMap = {};
@@ -278,7 +277,7 @@ function errorAlignBeamSearch(src, beamSize = 100) {
278
277
  return a.normCost - b.normCost;
279
278
  });
280
279
  beam = newBeamPaths.slice(0, beamSize);
281
- if ((_a = beam[0]) == null ? void 0 : _a.atUnambiguousMatchNode) {
280
+ if (beam[0]?.atUnambiguousMatchNode) {
282
281
  beam = beam.slice(0, 1);
283
282
  pruneMap = {};
284
283
  }
@@ -209,7 +209,6 @@ function isSubstitution(hypIndex, refIndex, lastHypIndex, lastRefIndex) {
209
209
  return !(refIndex === lastRefIndex || hypIndex === lastHypIndex);
210
210
  }
211
211
  function errorAlignBeamSearch(src, beamSize = 100) {
212
- var _a;
213
212
  const startPath = new Path(src);
214
213
  let beam = [startPath];
215
214
  let pruneMap = {};
@@ -245,7 +244,7 @@ function errorAlignBeamSearch(src, beamSize = 100) {
245
244
  return a.normCost - b.normCost;
246
245
  });
247
246
  beam = newBeamPaths.slice(0, beamSize);
248
- if ((_a = beam[0]) == null ? void 0 : _a.atUnambiguousMatchNode) {
247
+ if (beam[0]?.atUnambiguousMatchNode) {
249
248
  beam = beam.slice(0, 1);
250
249
  pruneMap = {};
251
250
  }
@@ -77,7 +77,6 @@ var import_segmentation = require("./segmentation.cjs");
77
77
  var import_serializeDom = require("./serializeDom.cjs");
78
78
  var import_transform = require("./transform.cjs");
79
79
  async function markup(input, output, options) {
80
- var _a, _b, _c, _d;
81
80
  var _stack = [];
82
81
  try {
83
82
  const timing = (0, import_ghost_story.createAggregator)();
@@ -88,13 +87,13 @@ async function markup(input, output, options) {
88
87
  const spine = await epub.getSpineItems();
89
88
  const manifest = await epub.getManifest();
90
89
  for (let index = 0; index < spine.length; index++) {
91
- (_a = options.onProgress) == null ? void 0 : _a.call(options, index / spine.length);
90
+ options.onProgress?.(index / spine.length);
92
91
  const spineItem = spine[index];
93
- (_b = options.logger) == null ? void 0 : _b.info(
92
+ options.logger?.info(
94
93
  `Marking up epub item #${index}: ${(0, import_posix.basename)(spineItem.href)}`
95
94
  );
96
95
  const chapterId = spineItem.id;
97
- if ((_d = (_c = manifest[chapterId]) == null ? void 0 : _c.properties) == null ? void 0 : _d.includes("nav")) {
96
+ if (manifest[chapterId]?.properties?.includes("nav")) {
98
97
  continue;
99
98
  }
100
99
  const chapterXml = await epub.readXhtmlItemContents(chapterId);
@@ -15,7 +15,6 @@ import { getXhtmlSegmentation } from "./segmentation.js";
15
15
  import { serializeDom } from "./serializeDom.js";
16
16
  import { addMark } from "./transform.js";
17
17
  async function markup(input, output, options) {
18
- var _a, _b, _c, _d;
19
18
  var _stack = [];
20
19
  try {
21
20
  const timing = createAggregator();
@@ -26,13 +25,13 @@ async function markup(input, output, options) {
26
25
  const spine = await epub.getSpineItems();
27
26
  const manifest = await epub.getManifest();
28
27
  for (let index = 0; index < spine.length; index++) {
29
- (_a = options.onProgress) == null ? void 0 : _a.call(options, index / spine.length);
28
+ options.onProgress?.(index / spine.length);
30
29
  const spineItem = spine[index];
31
- (_b = options.logger) == null ? void 0 : _b.info(
30
+ options.logger?.info(
32
31
  `Marking up epub item #${index}: ${basename(spineItem.href)}`
33
32
  );
34
33
  const chapterId = spineItem.id;
35
- if ((_d = (_c = manifest[chapterId]) == null ? void 0 : _c.properties) == null ? void 0 : _d.includes("nav")) {
34
+ if (manifest[chapterId]?.properties?.includes("nav")) {
36
35
  continue;
37
36
  }
38
37
  const chapterXml = await epub.readXhtmlItemContents(chapterId);
@@ -49,7 +49,7 @@ function serializeDomNodes(nodes) {
49
49
  }
50
50
  const childFirstMark = child.marks[0];
51
51
  const lastChildFirstMark = lastChild.marks[0];
52
- if (childFirstMark === lastChildFirstMark || (childFirstMark == null ? void 0 : childFirstMark.eq(lastChildFirstMark))) {
52
+ if (childFirstMark === lastChildFirstMark || childFirstMark?.eq(lastChildFirstMark)) {
53
53
  return [
54
54
  ...acc.slice(0, acc.length - 1),
55
55
  [...lastPartition.slice(0, lastPartition.length), child]
@@ -26,7 +26,7 @@ function serializeDomNodes(nodes) {
26
26
  }
27
27
  const childFirstMark = child.marks[0];
28
28
  const lastChildFirstMark = lastChild.marks[0];
29
- if (childFirstMark === lastChildFirstMark || (childFirstMark == null ? void 0 : childFirstMark.eq(lastChildFirstMark))) {
29
+ if (childFirstMark === lastChildFirstMark || childFirstMark?.eq(lastChildFirstMark)) {
30
30
  return [
31
31
  ...acc.slice(0, acc.length - 1),
32
32
  [...lastPartition.slice(0, lastPartition.length), child]
@@ -58,7 +58,12 @@ function liftText(root) {
58
58
  if (node.isBlock) {
59
59
  return !!node.textContent.match(/\S/);
60
60
  }
61
- if (!(node instanceof import_model.TextNode)) return true;
61
+ if (!(node instanceof import_model.TextNode)) {
62
+ if (node.isLeaf && parent.isBlock && index === parent.children.length - 1 && !text.endsWith("\n")) {
63
+ text += "\n";
64
+ }
65
+ return true;
66
+ }
62
67
  if (mapping.map(pos) - mapping.map(lastTextEnd)) {
63
68
  mapping.appendMap(
64
69
  new import_map.StepMap([
@@ -38,7 +38,12 @@ function liftText(root) {
38
38
  if (node.isBlock) {
39
39
  return !!node.textContent.match(/\S/);
40
40
  }
41
- if (!(node instanceof TextNode)) return true;
41
+ if (!(node instanceof TextNode)) {
42
+ if (node.isLeaf && parent.isBlock && index === parent.children.length - 1 && !text.endsWith("\n")) {
43
+ text += "\n";
44
+ }
45
+ return true;
46
+ }
42
47
  if (mapping.map(pos) - mapping.map(lastTextEnd)) {
43
48
  mapping.appendMap(
44
49
  new StepMap([
@@ -75,15 +75,14 @@ var import_ghost_story = require("@storyteller-platform/ghost-story");
75
75
  var import_ffmpeg = require("../common/ffmpeg.cjs");
76
76
  var import_ranges = require("./ranges.cjs");
77
77
  async function processAudiobook(input, output, options) {
78
- var _a, _b, _c;
79
78
  const timing = (0, import_ghost_story.createAggregator)();
80
- timing.setMetadata("codec", ((_a = options.encoding) == null ? void 0 : _a.codec) ?? "unspecified");
81
- timing.setMetadata("bitrate", ((_b = options.encoding) == null ? void 0 : _b.bitrate) ?? "unspecified");
79
+ timing.setMetadata("codec", options.encoding?.codec ?? "unspecified");
80
+ timing.setMetadata("bitrate", options.encoding?.bitrate ?? "unspecified");
82
81
  timing.setMetadata("max-length", `${(options.maxLength ?? 2) * 60} minutes`);
83
82
  await (0, import_promises.mkdir)(output, { recursive: true });
84
83
  const allFiles = await (0, import_promises.readdir)(input, { recursive: true });
85
84
  const filenames = allFiles.filter((f) => (0, import_audiobook.isAudioFile)(f) || (0, import_audiobook.isZipArchive)(f));
86
- (_c = options.logger) == null ? void 0 : _c.debug(`Found ${filenames.length} files to process`);
85
+ options.logger?.debug(`Found ${filenames.length} files to process`);
87
86
  const outputFiles = [];
88
87
  const controller = new AbortController();
89
88
  const signal = AbortSignal.any([
@@ -97,15 +96,14 @@ async function processAudiobook(input, output, options) {
97
96
  if (signal.aborted) throw new Error("Aborted");
98
97
  const filepath = (0, import_node_path.join)(input, filename);
99
98
  function onFileProgress(progress) {
100
- var _a2, _b2;
101
99
  perFileProgress.set(index, progress);
102
100
  const updatedProgress = Array.from(perFileProgress.values()).reduce(
103
101
  (acc, p) => acc + p
104
102
  );
105
- (_a2 = options.logger) == null ? void 0 : _a2.info(
103
+ options.logger?.info(
106
104
  `Progress: ${Math.floor(updatedProgress * 100)}%`
107
105
  );
108
- (_b2 = options.onProgress) == null ? void 0 : _b2.call(options, updatedProgress);
106
+ options.onProgress?.(updatedProgress);
109
107
  }
110
108
  const fileOptions = {
111
109
  ...options,
@@ -150,12 +148,11 @@ async function processFile(input, output, prefix, options) {
150
148
  );
151
149
  await Promise.all(
152
150
  ranges.map(async (range, index) => {
153
- var _a, _b;
154
151
  var _stack2 = [];
155
152
  try {
156
153
  const outputExtension = determineExtension(
157
154
  range.filepath,
158
- (_a = options.encoding) == null ? void 0 : _a.codec
155
+ options.encoding?.codec
159
156
  );
160
157
  const outputFilename = `${prefix}${(index + 1).toString().padStart(5, "0")}${outputExtension}`;
161
158
  const outputFilepath = (0, import_node_path.join)(output, outputFilename);
@@ -164,11 +161,10 @@ async function processFile(input, output, prefix, options) {
164
161
  options.lock.release();
165
162
  });
166
163
  await options.lock.wait();
167
- if ((_b = options.signal) == null ? void 0 : _b.aborted) throw new Error("Aborted");
164
+ if (options.signal?.aborted) throw new Error("Aborted");
168
165
  await timing.timeAsync(
169
166
  `${range.filepath},${range.start}:${range.end}`,
170
167
  async () => {
171
- var _a2;
172
168
  const wasSplit = await (0, import_ffmpeg.splitFile)(
173
169
  range.filepath,
174
170
  outputFilepath,
@@ -180,7 +176,7 @@ async function processFile(input, output, prefix, options) {
180
176
  );
181
177
  if (wasSplit) {
182
178
  outputFiles.push(outputFilename);
183
- (_a2 = options.onProgress) == null ? void 0 : _a2.call(options, (outputFiles.length + 1) / ranges.length);
179
+ options.onProgress?.((outputFiles.length + 1) / ranges.length);
184
180
  }
185
181
  }
186
182
  );
@@ -22,15 +22,14 @@ import {
22
22
  import { splitFile } from "../common/ffmpeg.js";
23
23
  import { getSafeChapterRanges } from "./ranges.js";
24
24
  async function processAudiobook(input, output, options) {
25
- var _a, _b, _c;
26
25
  const timing = createAggregator();
27
- timing.setMetadata("codec", ((_a = options.encoding) == null ? void 0 : _a.codec) ?? "unspecified");
28
- timing.setMetadata("bitrate", ((_b = options.encoding) == null ? void 0 : _b.bitrate) ?? "unspecified");
26
+ timing.setMetadata("codec", options.encoding?.codec ?? "unspecified");
27
+ timing.setMetadata("bitrate", options.encoding?.bitrate ?? "unspecified");
29
28
  timing.setMetadata("max-length", `${(options.maxLength ?? 2) * 60} minutes`);
30
29
  await mkdir(output, { recursive: true });
31
30
  const allFiles = await readdir(input, { recursive: true });
32
31
  const filenames = allFiles.filter((f) => isAudioFile(f) || isZipArchive(f));
33
- (_c = options.logger) == null ? void 0 : _c.debug(`Found ${filenames.length} files to process`);
32
+ options.logger?.debug(`Found ${filenames.length} files to process`);
34
33
  const outputFiles = [];
35
34
  const controller = new AbortController();
36
35
  const signal = AbortSignal.any([
@@ -44,15 +43,14 @@ async function processAudiobook(input, output, options) {
44
43
  if (signal.aborted) throw new Error("Aborted");
45
44
  const filepath = join(input, filename);
46
45
  function onFileProgress(progress) {
47
- var _a2, _b2;
48
46
  perFileProgress.set(index, progress);
49
47
  const updatedProgress = Array.from(perFileProgress.values()).reduce(
50
48
  (acc, p) => acc + p
51
49
  );
52
- (_a2 = options.logger) == null ? void 0 : _a2.info(
50
+ options.logger?.info(
53
51
  `Progress: ${Math.floor(updatedProgress * 100)}%`
54
52
  );
55
- (_b2 = options.onProgress) == null ? void 0 : _b2.call(options, updatedProgress);
53
+ options.onProgress?.(updatedProgress);
56
54
  }
57
55
  const fileOptions = {
58
56
  ...options,
@@ -97,12 +95,11 @@ async function processFile(input, output, prefix, options) {
97
95
  );
98
96
  await Promise.all(
99
97
  ranges.map(async (range, index) => {
100
- var _a, _b;
101
98
  var _stack2 = [];
102
99
  try {
103
100
  const outputExtension = determineExtension(
104
101
  range.filepath,
105
- (_a = options.encoding) == null ? void 0 : _a.codec
102
+ options.encoding?.codec
106
103
  );
107
104
  const outputFilename = `${prefix}${(index + 1).toString().padStart(5, "0")}${outputExtension}`;
108
105
  const outputFilepath = join(output, outputFilename);
@@ -111,11 +108,10 @@ async function processFile(input, output, prefix, options) {
111
108
  options.lock.release();
112
109
  });
113
110
  await options.lock.wait();
114
- if ((_b = options.signal) == null ? void 0 : _b.aborted) throw new Error("Aborted");
111
+ if (options.signal?.aborted) throw new Error("Aborted");
115
112
  await timing.timeAsync(
116
113
  `${range.filepath},${range.start}:${range.end}`,
117
114
  async () => {
118
- var _a2;
119
115
  const wasSplit = await splitFile(
120
116
  range.filepath,
121
117
  outputFilepath,
@@ -127,7 +123,7 @@ async function processFile(input, output, prefix, options) {
127
123
  );
128
124
  if (wasSplit) {
129
125
  outputFiles.push(outputFilename);
130
- (_a2 = options.onProgress) == null ? void 0 : _a2.call(options, (outputFiles.length + 1) / ranges.length);
126
+ options.onProgress?.((outputFiles.length + 1) / ranges.length);
131
127
  }
132
128
  }
133
129
  );
@@ -75,7 +75,7 @@ var import_vad = require("@storyteller-platform/ghost-story/vad");
75
75
  var import_ffmpeg = require("../common/ffmpeg.cjs");
76
76
  async function getSafeChapterRanges(input, duration, chapters, maxSeconds, signal, logger) {
77
77
  if (!chapters.length) {
78
- logger == null ? void 0 : logger.info(
78
+ logger?.info(
79
79
  `Track is longer than ${maxSeconds / 60} minutes (${duration / 60}m); using VAD to determine safe split points.`
80
80
  );
81
81
  const ranges2 = await getSafeRanges(input, duration, maxSeconds, 0, signal);
@@ -103,7 +103,7 @@ async function getSafeChapterRanges(input, duration, chapters, maxSeconds, signa
103
103
  ranges.push(range);
104
104
  continue;
105
105
  }
106
- logger == null ? void 0 : logger.info(
106
+ logger?.info(
107
107
  `Chapter is longer than ${maxSeconds / 60} minutes (${duration / 60}m); using VAD to determine safe split points.`
108
108
  );
109
109
  const chapterRanges = await getSafeRanges(
@@ -132,7 +132,7 @@ async function getSafeRanges(input, duration, maxSeconds, start = 0, signal, log
132
132
  });
133
133
  const ranges = [{ start, end: duration + start }];
134
134
  for (let i = 0; i + 1 < duration / maxSeconds; i++) {
135
- if (signal == null ? void 0 : signal.aborted) throw new Error("Aborted");
135
+ if (signal?.aborted) throw new Error("Aborted");
136
136
  const tmpFilepath = (0, import_node_path.join)(tmpDir, i.toString(), `${rawFilename}.wav`);
137
137
  await (0, import_promises.mkdir)((0, import_node_path.dirname)(tmpFilepath), { recursive: true });
138
138
  const approxCutPoint = start + maxSeconds * (i + 1);
@@ -10,7 +10,7 @@ import { detectVoiceActivity } from "@storyteller-platform/ghost-story/vad";
10
10
  import { splitFile } from "../common/ffmpeg.js";
11
11
  async function getSafeChapterRanges(input, duration, chapters, maxSeconds, signal, logger) {
12
12
  if (!chapters.length) {
13
- logger == null ? void 0 : logger.info(
13
+ logger?.info(
14
14
  `Track is longer than ${maxSeconds / 60} minutes (${duration / 60}m); using VAD to determine safe split points.`
15
15
  );
16
16
  const ranges2 = await getSafeRanges(input, duration, maxSeconds, 0, signal);
@@ -38,7 +38,7 @@ async function getSafeChapterRanges(input, duration, chapters, maxSeconds, signa
38
38
  ranges.push(range);
39
39
  continue;
40
40
  }
41
- logger == null ? void 0 : logger.info(
41
+ logger?.info(
42
42
  `Chapter is longer than ${maxSeconds / 60} minutes (${duration / 60}m); using VAD to determine safe split points.`
43
43
  );
44
44
  const chapterRanges = await getSafeRanges(
@@ -67,7 +67,7 @@ async function getSafeRanges(input, duration, maxSeconds, start = 0, signal, log
67
67
  });
68
68
  const ranges = [{ start, end: duration + start }];
69
69
  for (let i = 0; i + 1 < duration / maxSeconds; i++) {
70
- if (signal == null ? void 0 : signal.aborted) throw new Error("Aborted");
70
+ if (signal?.aborted) throw new Error("Aborted");
71
71
  const tmpFilepath = join(tmpDir, i.toString(), `${rawFilename}.wav`);
72
72
  await mkdir(dirname(tmpFilepath), { recursive: true });
73
73
  const approxCutPoint = start + maxSeconds * (i + 1);
@@ -84,7 +84,6 @@ var import_async_semaphore = require("@esfx/async-semaphore");
84
84
  var import_audiobook = require("@storyteller-platform/audiobook");
85
85
  var import_ghost_story = require("@storyteller-platform/ghost-story");
86
86
  async function transcribe(input, output, locale, options) {
87
- var _a;
88
87
  if (process.env["DEBUG_TRANSCRIBE"] === "true") {
89
88
  const inspector = await import("node:inspector");
90
89
  inspector.open(9231, "0.0.0.0", true);
@@ -109,7 +108,7 @@ async function transcribe(input, output, locale, options) {
109
108
  await (0, import_ghost_story.ensureWhisperInstalled)({
110
109
  model,
111
110
  printOutput: ["debug", "info"].includes(
112
- ((_a = options.logger) == null ? void 0 : _a.level) ?? "silent"
111
+ options.logger?.level ?? "silent"
113
112
  ),
114
113
  signal
115
114
  });
@@ -126,7 +125,6 @@ async function transcribe(input, output, locale, options) {
126
125
  timing.setMetadata("threads", options.threads ?? 4);
127
126
  await Promise.all(
128
127
  filenames.map(async (filename) => {
129
- var _a2, _b, _c;
130
128
  var _stack = [];
131
129
  try {
132
130
  if (aborted()) throw new Error("Aborted");
@@ -140,7 +138,7 @@ async function transcribe(input, output, locale, options) {
140
138
  encoding: "utf-8",
141
139
  signal
142
140
  });
143
- (_a2 = options.logger) == null ? void 0 : _a2.info(`Found existing transcription for ${filepath}`);
141
+ options.logger?.info(`Found existing transcription for ${filepath}`);
144
142
  transcriptions.push(transcriptionFilepath);
145
143
  } catch {
146
144
  }
@@ -151,13 +149,12 @@ async function transcribe(input, output, locale, options) {
151
149
  });
152
150
  await semaphore.wait();
153
151
  function onFileProgress(progress) {
154
- var _a3, _b2;
155
152
  perFileProgress.set(filename, progress);
156
153
  const updatedProgress = Array.from(perFileProgress.values()).reduce((acc, p) => acc + p) / filenames.length;
157
- (_a3 = options.logger) == null ? void 0 : _a3.info(
154
+ options.logger?.info(
158
155
  `Progress: ${Math.floor(updatedProgress * 100)}%`
159
156
  );
160
- (_b2 = options.onProgress) == null ? void 0 : _b2.call(options, updatedProgress);
157
+ options.onProgress?.(updatedProgress);
161
158
  }
162
159
  const transcription = await transcribeFile(filepath, locale, {
163
160
  ...options,
@@ -168,7 +165,7 @@ async function transcribe(input, output, locale, options) {
168
165
  threads: options.threads ?? 4,
169
166
  onProgress: onFileProgress
170
167
  });
171
- (_b = options.logger) == null ? void 0 : _b.info(
168
+ options.logger?.info(
172
169
  (0, import_ghost_story.formatSingleReport)(
173
170
  transcription.timing,
174
171
  `Transcription Timing Report for ${filepath}`
@@ -184,7 +181,7 @@ async function transcribe(input, output, locale, options) {
184
181
  { signal }
185
182
  );
186
183
  transcriptions.push(transcriptionFilepath);
187
- (_c = options.onProgress) == null ? void 0 : _c.call(options, (transcriptions.length + 1) / filenames.length);
184
+ options.onProgress?.((transcriptions.length + 1) / filenames.length);
188
185
  } catch (_) {
189
186
  var _error = _, _hasError = true;
190
187
  } finally {
@@ -200,7 +197,6 @@ async function transcribe(input, output, locale, options) {
200
197
  return timing;
201
198
  }
202
199
  async function transcribeFile(input, locale, options) {
203
- var _a, _b;
204
200
  const audioFilepath = (0, import_node_path.resolve)(process.cwd(), input);
205
201
  const sharedOptions = {
206
202
  signal: options.signal,
@@ -215,11 +211,11 @@ async function transcribeFile(input, locale, options) {
215
211
  model: options.model,
216
212
  variant: fallbackVariant,
217
213
  printOutput: ["debug", "info"].includes(
218
- ((_a = options.logger) == null ? void 0 : _a.level) ?? "silent"
214
+ options.logger?.level ?? "silent"
219
215
  ),
220
216
  signal: options.signal
221
217
  });
222
- (_b = options.logger) == null ? void 0 : _b.info(`Transcribing audio file ${audioFilepath}`);
218
+ options.logger?.info(`Transcribing audio file ${audioFilepath}`);
223
219
  return (0, import_ghost_story.recognize)(audioFilepath, {
224
220
  engine: options.engine,
225
221
  options: {
@@ -228,12 +224,11 @@ async function transcribeFile(input, locale, options) {
228
224
  processors: options.processors,
229
225
  threads: options.threads,
230
226
  onProgress: (progress) => {
231
- var _a2;
232
227
  if (options.onProgress) {
233
228
  options.onProgress(progress);
234
229
  return;
235
230
  }
236
- (_a2 = options.logger) == null ? void 0 : _a2.info(
231
+ options.logger?.info(
237
232
  `Transcribing ${audioFilepath} progress: ${Math.floor(progress * 100)}%`
238
233
  );
239
234
  },
@@ -15,7 +15,6 @@ import {
15
15
  recognize
16
16
  } from "@storyteller-platform/ghost-story";
17
17
  async function transcribe(input, output, locale, options) {
18
- var _a;
19
18
  if (process.env["DEBUG_TRANSCRIBE"] === "true") {
20
19
  const inspector = await import("node:inspector");
21
20
  inspector.open(9231, "0.0.0.0", true);
@@ -40,7 +39,7 @@ async function transcribe(input, output, locale, options) {
40
39
  await ensureWhisperInstalled({
41
40
  model,
42
41
  printOutput: ["debug", "info"].includes(
43
- ((_a = options.logger) == null ? void 0 : _a.level) ?? "silent"
42
+ options.logger?.level ?? "silent"
44
43
  ),
45
44
  signal
46
45
  });
@@ -57,7 +56,6 @@ async function transcribe(input, output, locale, options) {
57
56
  timing.setMetadata("threads", options.threads ?? 4);
58
57
  await Promise.all(
59
58
  filenames.map(async (filename) => {
60
- var _a2, _b, _c;
61
59
  var _stack = [];
62
60
  try {
63
61
  if (aborted()) throw new Error("Aborted");
@@ -71,7 +69,7 @@ async function transcribe(input, output, locale, options) {
71
69
  encoding: "utf-8",
72
70
  signal
73
71
  });
74
- (_a2 = options.logger) == null ? void 0 : _a2.info(`Found existing transcription for ${filepath}`);
72
+ options.logger?.info(`Found existing transcription for ${filepath}`);
75
73
  transcriptions.push(transcriptionFilepath);
76
74
  } catch {
77
75
  }
@@ -82,13 +80,12 @@ async function transcribe(input, output, locale, options) {
82
80
  });
83
81
  await semaphore.wait();
84
82
  function onFileProgress(progress) {
85
- var _a3, _b2;
86
83
  perFileProgress.set(filename, progress);
87
84
  const updatedProgress = Array.from(perFileProgress.values()).reduce((acc, p) => acc + p) / filenames.length;
88
- (_a3 = options.logger) == null ? void 0 : _a3.info(
85
+ options.logger?.info(
89
86
  `Progress: ${Math.floor(updatedProgress * 100)}%`
90
87
  );
91
- (_b2 = options.onProgress) == null ? void 0 : _b2.call(options, updatedProgress);
88
+ options.onProgress?.(updatedProgress);
92
89
  }
93
90
  const transcription = await transcribeFile(filepath, locale, {
94
91
  ...options,
@@ -99,7 +96,7 @@ async function transcribe(input, output, locale, options) {
99
96
  threads: options.threads ?? 4,
100
97
  onProgress: onFileProgress
101
98
  });
102
- (_b = options.logger) == null ? void 0 : _b.info(
99
+ options.logger?.info(
103
100
  formatSingleReport(
104
101
  transcription.timing,
105
102
  `Transcription Timing Report for ${filepath}`
@@ -115,7 +112,7 @@ async function transcribe(input, output, locale, options) {
115
112
  { signal }
116
113
  );
117
114
  transcriptions.push(transcriptionFilepath);
118
- (_c = options.onProgress) == null ? void 0 : _c.call(options, (transcriptions.length + 1) / filenames.length);
115
+ options.onProgress?.((transcriptions.length + 1) / filenames.length);
119
116
  } catch (_) {
120
117
  var _error = _, _hasError = true;
121
118
  } finally {
@@ -131,7 +128,6 @@ async function transcribe(input, output, locale, options) {
131
128
  return timing;
132
129
  }
133
130
  async function transcribeFile(input, locale, options) {
134
- var _a, _b;
135
131
  const audioFilepath = resolve(process.cwd(), input);
136
132
  const sharedOptions = {
137
133
  signal: options.signal,
@@ -146,11 +142,11 @@ async function transcribeFile(input, locale, options) {
146
142
  model: options.model,
147
143
  variant: fallbackVariant,
148
144
  printOutput: ["debug", "info"].includes(
149
- ((_a = options.logger) == null ? void 0 : _a.level) ?? "silent"
145
+ options.logger?.level ?? "silent"
150
146
  ),
151
147
  signal: options.signal
152
148
  });
153
- (_b = options.logger) == null ? void 0 : _b.info(`Transcribing audio file ${audioFilepath}`);
149
+ options.logger?.info(`Transcribing audio file ${audioFilepath}`);
154
150
  return recognize(audioFilepath, {
155
151
  engine: options.engine,
156
152
  options: {
@@ -159,12 +155,11 @@ async function transcribeFile(input, locale, options) {
159
155
  processors: options.processors,
160
156
  threads: options.threads,
161
157
  onProgress: (progress) => {
162
- var _a2;
163
158
  if (options.onProgress) {
164
159
  options.onProgress(progress);
165
160
  return;
166
161
  }
167
- (_a2 = options.logger) == null ? void 0 : _a2.info(
162
+ options.logger?.info(
168
163
  `Transcribing ${audioFilepath} progress: ${Math.floor(progress * 100)}%`
169
164
  );
170
165
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storyteller-platform/align",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "description": "A library and CLI for automatically aligning audiobooks and EPUBs to produce Media Overlays",
5
5
  "author": "Shane Friedman",
6
6
  "license": "MIT",
@@ -61,7 +61,7 @@
61
61
  "@optique/run": "^0.10.7",
62
62
  "@storyteller-platform/audiobook": "^0.3.10",
63
63
  "@storyteller-platform/epub": "^0.4.8",
64
- "@storyteller-platform/ghost-story": "^0.1.6",
64
+ "@storyteller-platform/ghost-story": "^0.1.7",
65
65
  "@storyteller-platform/transliteration": "^3.1.1",
66
66
  "chalk": "^5.4.1",
67
67
  "cli-progress": "^3.12.0",