@storyteller-platform/align 0.1.41 → 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 +4 -5
- package/dist/cli/bin.js +4 -5
- package/dist/common/ffmpeg.cjs +7 -8
- package/dist/common/ffmpeg.js +7 -8
- package/dist/readium/manifest.cjs +18 -12
- package/dist/readium/manifest.js +18 -12
- package/dist/transcribe/transcribe.cjs +8 -3
- package/dist/transcribe/transcribe.js +8 -3
- package/package.json +3 -3
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)(
|
|
364
|
+
(0, import_node_fs.rmSync)(markedup, { recursive: true, force: true });
|
|
366
365
|
});
|
|
367
366
|
}
|
|
368
|
-
const markupTiming = await (0, import_markup.markup)(input,
|
|
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 ${
|
|
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-
|
|
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(
|
|
317
|
+
rmSync(markedup, { recursive: true, force: true });
|
|
319
318
|
});
|
|
320
319
|
}
|
|
321
|
-
const markupTiming = await markup(input,
|
|
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 ${
|
|
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-
|
|
336
|
+
logger.info("Skipping markup, text-ref set to text-fragment");
|
|
338
337
|
}
|
|
339
338
|
logger.info("Aligning EPUB with audiobook...");
|
|
340
339
|
startProgressBar();
|
package/dist/common/ffmpeg.cjs
CHANGED
|
@@ -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
|
-
|
|
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);
|
package/dist/common/ffmpeg.js
CHANGED
|
@@ -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
|
-
|
|
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);
|
|
@@ -88,10 +88,19 @@ async function generateReadiumManifest(epub, options = {}) {
|
|
|
88
88
|
const dir = await epub.getBaseDirection();
|
|
89
89
|
const epubMetadata = await epub.getMetadata();
|
|
90
90
|
const vocab = await epub.getPackageVocabularyPrefixes();
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
)
|
|
94
|
-
|
|
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
|
+
}
|
|
95
104
|
const otherMetadata = epubMetadata.filter(
|
|
96
105
|
(meta) => (meta.properties["property"]?.split(":")[0] ?? "") in vocab
|
|
97
106
|
).map((meta) => {
|
|
@@ -130,8 +139,8 @@ async function generateReadiumManifest(epub, options = {}) {
|
|
|
130
139
|
...dir !== "auto" && {
|
|
131
140
|
readingProgression: dir === "ltr" ? import_shared.ReadingProgression.ltr : import_shared.ReadingProgression.rtl
|
|
132
141
|
},
|
|
133
|
-
//
|
|
134
|
-
...
|
|
142
|
+
// it's seconds
|
|
143
|
+
...duration !== void 0 && { duration },
|
|
135
144
|
...numberOfPages !== void 0 && { numberOfPages },
|
|
136
145
|
otherMetadata: Object.fromEntries(otherMetadata)
|
|
137
146
|
});
|
|
@@ -184,16 +193,13 @@ async function generateReadiumManifest(epub, options = {}) {
|
|
|
184
193
|
if (!item.mediaOverlay) return link;
|
|
185
194
|
const mediaOverlayItem = epubManifest[item.id];
|
|
186
195
|
if (!mediaOverlayItem) return link;
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
);
|
|
190
|
-
if (!refinedBy?.value) return link;
|
|
191
|
-
const itemDuration = (0, import_smil_clockvalue.default)(refinedBy.value);
|
|
196
|
+
const duration2 = refinesDurationMap.get(`#${item.mediaOverlay}`) || refinesDurationMap.get(`#${mediaOverlayItem.id}`);
|
|
197
|
+
if (!duration2) return link;
|
|
192
198
|
return new import_shared.Link({
|
|
193
199
|
href: link.href,
|
|
194
200
|
type: link.mediaType.string,
|
|
195
201
|
...link.properties && { properties: link.properties },
|
|
196
|
-
duration:
|
|
202
|
+
duration: duration2
|
|
197
203
|
});
|
|
198
204
|
})
|
|
199
205
|
);
|
package/dist/readium/manifest.js
CHANGED
|
@@ -71,10 +71,19 @@ async function generateReadiumManifest(epub, options = {}) {
|
|
|
71
71
|
const dir = await epub.getBaseDirection();
|
|
72
72
|
const epubMetadata = await epub.getMetadata();
|
|
73
73
|
const vocab = await epub.getPackageVocabularyPrefixes();
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
)
|
|
77
|
-
|
|
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
|
+
}
|
|
78
87
|
const otherMetadata = epubMetadata.filter(
|
|
79
88
|
(meta) => (meta.properties["property"]?.split(":")[0] ?? "") in vocab
|
|
80
89
|
).map((meta) => {
|
|
@@ -113,8 +122,8 @@ async function generateReadiumManifest(epub, options = {}) {
|
|
|
113
122
|
...dir !== "auto" && {
|
|
114
123
|
readingProgression: dir === "ltr" ? ReadingProgression.ltr : ReadingProgression.rtl
|
|
115
124
|
},
|
|
116
|
-
//
|
|
117
|
-
...
|
|
125
|
+
// it's seconds
|
|
126
|
+
...duration !== void 0 && { duration },
|
|
118
127
|
...numberOfPages !== void 0 && { numberOfPages },
|
|
119
128
|
otherMetadata: Object.fromEntries(otherMetadata)
|
|
120
129
|
});
|
|
@@ -167,16 +176,13 @@ async function generateReadiumManifest(epub, options = {}) {
|
|
|
167
176
|
if (!item.mediaOverlay) return link;
|
|
168
177
|
const mediaOverlayItem = epubManifest[item.id];
|
|
169
178
|
if (!mediaOverlayItem) return link;
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
);
|
|
173
|
-
if (!refinedBy?.value) return link;
|
|
174
|
-
const itemDuration = clockvalue(refinedBy.value);
|
|
179
|
+
const duration2 = refinesDurationMap.get(`#${item.mediaOverlay}`) || refinesDurationMap.get(`#${mediaOverlayItem.id}`);
|
|
180
|
+
if (!duration2) return link;
|
|
175
181
|
return new Link({
|
|
176
182
|
href: link.href,
|
|
177
183
|
type: link.mediaType.string,
|
|
178
184
|
...link.properties && { properties: link.properties },
|
|
179
|
-
duration:
|
|
185
|
+
duration: duration2
|
|
180
186
|
});
|
|
181
187
|
})
|
|
182
188
|
);
|
|
@@ -101,8 +101,9 @@ async function transcribe(input, output, locale, options) {
|
|
|
101
101
|
const engine = options.engine ?? "whisper.cpp";
|
|
102
102
|
const model = options.model ?? "tiny.en";
|
|
103
103
|
if (engine === "whisper.cpp") {
|
|
104
|
+
const resolvedModel = getWhisperCppModelId(locale.language, model);
|
|
104
105
|
await (0, import_ghost_story.ensureWhisperInstalled)({
|
|
105
|
-
model,
|
|
106
|
+
model: resolvedModel,
|
|
106
107
|
printOutput: ["debug", "info"].includes(
|
|
107
108
|
options.logger?.level ?? "silent"
|
|
108
109
|
),
|
|
@@ -205,8 +206,12 @@ async function transcribeFile(input, locale, options) {
|
|
|
205
206
|
const fallbackVariant = getCpuOverrideVariant(
|
|
206
207
|
options.whisperCpuOverride ?? null
|
|
207
208
|
);
|
|
209
|
+
const resolvedModel = getWhisperCppModelId(
|
|
210
|
+
sharedOptions.language,
|
|
211
|
+
options.model
|
|
212
|
+
);
|
|
208
213
|
const whisperOptions = await (0, import_ghost_story.ensureWhisperInstalled)({
|
|
209
|
-
model:
|
|
214
|
+
model: resolvedModel,
|
|
210
215
|
variant: fallbackVariant,
|
|
211
216
|
printOutput: ["debug", "info"].includes(
|
|
212
217
|
options.logger?.level ?? "silent"
|
|
@@ -218,7 +223,7 @@ async function transcribeFile(input, locale, options) {
|
|
|
218
223
|
engine: options.engine,
|
|
219
224
|
options: {
|
|
220
225
|
flashAttention: true,
|
|
221
|
-
model:
|
|
226
|
+
model: resolvedModel,
|
|
222
227
|
processors: options.processors,
|
|
223
228
|
threads: options.threads,
|
|
224
229
|
onProgress: (progress) => {
|
|
@@ -32,8 +32,9 @@ async function transcribe(input, output, locale, options) {
|
|
|
32
32
|
const engine = options.engine ?? "whisper.cpp";
|
|
33
33
|
const model = options.model ?? "tiny.en";
|
|
34
34
|
if (engine === "whisper.cpp") {
|
|
35
|
+
const resolvedModel = getWhisperCppModelId(locale.language, model);
|
|
35
36
|
await ensureWhisperInstalled({
|
|
36
|
-
model,
|
|
37
|
+
model: resolvedModel,
|
|
37
38
|
printOutput: ["debug", "info"].includes(
|
|
38
39
|
options.logger?.level ?? "silent"
|
|
39
40
|
),
|
|
@@ -136,8 +137,12 @@ async function transcribeFile(input, locale, options) {
|
|
|
136
137
|
const fallbackVariant = getCpuOverrideVariant(
|
|
137
138
|
options.whisperCpuOverride ?? null
|
|
138
139
|
);
|
|
140
|
+
const resolvedModel = getWhisperCppModelId(
|
|
141
|
+
sharedOptions.language,
|
|
142
|
+
options.model
|
|
143
|
+
);
|
|
139
144
|
const whisperOptions = await ensureWhisperInstalled({
|
|
140
|
-
model:
|
|
145
|
+
model: resolvedModel,
|
|
141
146
|
variant: fallbackVariant,
|
|
142
147
|
printOutput: ["debug", "info"].includes(
|
|
143
148
|
options.logger?.level ?? "silent"
|
|
@@ -149,7 +154,7 @@ async function transcribeFile(input, locale, options) {
|
|
|
149
154
|
engine: options.engine,
|
|
150
155
|
options: {
|
|
151
156
|
flashAttention: true,
|
|
152
|
-
model:
|
|
157
|
+
model: resolvedModel,
|
|
153
158
|
processors: options.processors,
|
|
154
159
|
threads: options.threads,
|
|
155
160
|
onProgress: (progress) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storyteller-platform/align",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.47",
|
|
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",
|
|
@@ -70,8 +70,8 @@
|
|
|
70
70
|
"@optique/core": "^0.10.7",
|
|
71
71
|
"@optique/run": "^0.10.7",
|
|
72
72
|
"@readium/shared": "^2.2.0",
|
|
73
|
-
"@storyteller-platform/audiobook": "^0.4.
|
|
74
|
-
"@storyteller-platform/epub": "^0.6.
|
|
73
|
+
"@storyteller-platform/audiobook": "^0.4.1",
|
|
74
|
+
"@storyteller-platform/epub": "^0.6.1",
|
|
75
75
|
"@storyteller-platform/ghost-story": "^0.1.11",
|
|
76
76
|
"@storyteller-platform/transliteration": "^3.1.2",
|
|
77
77
|
"chalk": "^5.4.1",
|