@bendyline/squisq-cli 2.8.9 → 2.8.10
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/README.md +11 -0
- package/dist/{api-QLYK5AQE.js → api-O34CQ6ZP.js} +4 -2
- package/dist/api.d.ts +109 -1
- package/dist/api.js +430 -82
- package/dist/{chunk-XD2ICI5G.js → chunk-4FJZYJC3.js} +433 -85
- package/dist/{chunk-Z3BHD4AF.js → chunk-RQSP3OPR.js} +2 -1
- package/dist/{chunk-GGVASRPG.js → chunk-Y5XKUWJ5.js} +2 -1
- package/dist/index.js +48 -6
- package/dist/{nativeEncoder-PMVSFLMN.js → nativeEncoder-RILHXTXI.js} +1 -1
- package/dist/{nativeEncoder-RZ3T4Z6S.js → nativeEncoder-T43J5UMP.js} +1 -1
- package/dist/squisq-player.full.global.js +344 -344
- package/dist/squisq-player.global.js +64 -64
- package/package.json +3 -3
|
@@ -141,7 +141,7 @@ async function framesToMp4Native(ffmpegPath, frames, audio, outputPath, options
|
|
|
141
141
|
}
|
|
142
142
|
args.push(outputPath);
|
|
143
143
|
await runFfmpeg(ffmpegPath, args, {
|
|
144
|
-
timeoutMs: 6e5,
|
|
144
|
+
timeoutMs: Math.max(6e5, frames.length * 250),
|
|
145
145
|
failureMessage: "ffmpeg failed",
|
|
146
146
|
signal: options.signal
|
|
147
147
|
});
|
|
@@ -227,6 +227,7 @@ async function framesToGifNativeBytes(ffmpegPath, frames, options = {}) {
|
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
export {
|
|
230
|
+
lastMeaningfulFfmpegLine,
|
|
230
231
|
runFfmpeg,
|
|
231
232
|
GIF_EXPORT_DEFAULTS,
|
|
232
233
|
framesToMp4Native,
|
|
@@ -143,7 +143,7 @@ async function framesToMp4Native(ffmpegPath, frames, audio, outputPath, options
|
|
|
143
143
|
}
|
|
144
144
|
args.push(outputPath);
|
|
145
145
|
await runFfmpeg(ffmpegPath, args, {
|
|
146
|
-
timeoutMs: 6e5,
|
|
146
|
+
timeoutMs: Math.max(6e5, frames.length * 250),
|
|
147
147
|
failureMessage: "ffmpeg failed",
|
|
148
148
|
signal: options.signal
|
|
149
149
|
});
|
|
@@ -229,6 +229,7 @@ async function framesToGifNativeBytes(ffmpegPath, frames, options = {}) {
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
export {
|
|
232
|
+
lastMeaningfulFfmpegLine,
|
|
232
233
|
runFfmpeg,
|
|
233
234
|
GIF_EXPORT_DEFAULTS,
|
|
234
235
|
framesToMp4Native,
|
package/dist/index.js
CHANGED
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
renderDocToDashboardPng,
|
|
10
10
|
renderDocToGif,
|
|
11
11
|
renderDocToMp4
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-4FJZYJC3.js";
|
|
13
|
+
import "./chunk-Y5XKUWJ5.js";
|
|
14
14
|
|
|
15
15
|
// src/index.ts
|
|
16
16
|
import { createRequire } from "module";
|
|
@@ -321,6 +321,8 @@ var VALID_ORIENTATIONS = ["landscape", "portrait"];
|
|
|
321
321
|
var VALID_CAPTIONS = ["off", "standard", "social"];
|
|
322
322
|
var VALID_FORMATS2 = ["mp4", "gif"];
|
|
323
323
|
var VALID_GIF_DITHERS = ["bayer", "sierra2_4a", "none"];
|
|
324
|
+
var VALID_FRAME_TRANSPORTS = ["pipe", "memory"];
|
|
325
|
+
var VALID_CAPTURE_FORMATS = ["png", "jpeg"];
|
|
324
326
|
function registerVideoCommand(program2) {
|
|
325
327
|
program2.command("video").description("Render a squisq document to MP4 video or animated GIF").argument("<input>", "Path to .md/.json file, .zip/.dbk container, or folder").argument("[output]", "Output .mp4 or .gif path (default: <input>.<format>)").option("-o, --output <path>", "Output .mp4 or .gif path (format inferred from extension)").option("--format <format>", `Output format: ${VALID_FORMATS2.join(", ")} (default: mp4)`).option("--fps <number>", "Frames per second (default: 30 for MP4, 10 for GIF)").option(
|
|
326
328
|
"--quality <level>",
|
|
@@ -342,7 +344,19 @@ function registerVideoCommand(program2) {
|
|
|
342
344
|
"--cover-preroll <seconds>",
|
|
343
345
|
"Seconds of cover-slide pre-roll before the story starts (default: 2)",
|
|
344
346
|
"2"
|
|
345
|
-
).option("--width <pixels>", "Override video width (must be even for MP4)").option("--height <pixels>", "Override video height (must be even for MP4)").option("--overwrite", "Replace an existing output file (default: refuse and exit non-zero)").option(
|
|
347
|
+
).option("--width <pixels>", "Override video width (must be even for MP4)").option("--height <pixels>", "Override video height (must be even for MP4)").option("--overwrite", "Replace an existing output file (default: refuse and exit non-zero)").option(
|
|
348
|
+
"--frame-transport <mode>",
|
|
349
|
+
`MP4 frame delivery: ${VALID_FRAME_TRANSPORTS.join(", ")} (default: pipe, streams frames to ffmpeg)`
|
|
350
|
+
).option(
|
|
351
|
+
"--capture-format <format>",
|
|
352
|
+
`MP4 still format captured per frame: ${VALID_CAPTURE_FORMATS.join(", ")} (default: png for high quality, jpeg otherwise)`
|
|
353
|
+
).option(
|
|
354
|
+
"--frames-dir <dir>",
|
|
355
|
+
"MP4 only: spool every captured frame here and keep it after the render"
|
|
356
|
+
).option(
|
|
357
|
+
"--resume",
|
|
358
|
+
"MP4 only: reuse frames an identical earlier render spooled into --frames-dir"
|
|
359
|
+
).option("--animations", "Enable slide animations/transitions (GIF default: disabled)").option("--no-animations", "Disable slide animations/transitions").option("--loop <count>", "GIF repeat count: 0 forever, -1 no loop (default: 0)").option("--max-colors <count>", "GIF palette size from 2 to 256 (default: 256)").option(
|
|
346
360
|
"--dither <algorithm>",
|
|
347
361
|
`GIF dithering: ${VALID_GIF_DITHERS.join(", ")} (default: sierra2_4a)`
|
|
348
362
|
).option("--bayer-scale <number>", "GIF Bayer dither strength from 0 to 5 (default: 3)").action(async (inputPath, outputArg, opts) => {
|
|
@@ -405,6 +419,29 @@ async function runVideo(inputPath, opts) {
|
|
|
405
419
|
if (!Number.isFinite(coverPreRoll) || coverPreRoll < 0) {
|
|
406
420
|
throw new Error("Cover pre-roll must be a number of seconds >= 0");
|
|
407
421
|
}
|
|
422
|
+
if (outputFormat === "gif" && (opts.frameTransport || opts.captureFormat || opts.framesDir || opts.resume)) {
|
|
423
|
+
throw new Error(
|
|
424
|
+
"--frame-transport, --capture-format, --frames-dir, and --resume only apply to MP4 output"
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
const frameTransport = opts.frameTransport ?? "pipe";
|
|
428
|
+
if (!VALID_FRAME_TRANSPORTS.includes(frameTransport)) {
|
|
429
|
+
throw new Error(
|
|
430
|
+
`Invalid frame transport "${frameTransport}". Valid: ${VALID_FRAME_TRANSPORTS.join(", ")}`
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
const captureFormat = opts.captureFormat;
|
|
434
|
+
if (captureFormat !== void 0 && !VALID_CAPTURE_FORMATS.includes(captureFormat)) {
|
|
435
|
+
throw new Error(
|
|
436
|
+
`Invalid capture format "${captureFormat}". Valid: ${VALID_CAPTURE_FORMATS.join(", ")}`
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
if (opts.resume && !opts.framesDir) {
|
|
440
|
+
throw new Error("--resume requires --frames-dir");
|
|
441
|
+
}
|
|
442
|
+
if ((opts.framesDir || captureFormat) && frameTransport !== "pipe") {
|
|
443
|
+
throw new Error("--frames-dir and --capture-format require --frame-transport pipe");
|
|
444
|
+
}
|
|
408
445
|
const animationsEnabled = opts.animations ?? outputFormat === "mp4";
|
|
409
446
|
const loop = opts.loop === void 0 ? 0 : Number(opts.loop);
|
|
410
447
|
const maxColors = opts.maxColors === void 0 ? 256 : Number(opts.maxColors);
|
|
@@ -462,7 +499,7 @@ async function runVideo(inputPath, opts) {
|
|
|
462
499
|
doc = { ...doc, themeId: opts.theme };
|
|
463
500
|
}
|
|
464
501
|
const motionLabel = animationsEnabled ? "animations on" : "animations off";
|
|
465
|
-
const qualityLabel = outputFormat === "mp4" ? `, quality: ${quality}` : "";
|
|
502
|
+
const qualityLabel = outputFormat === "mp4" ? `, quality: ${quality}, transport: ${frameTransport}` : "";
|
|
466
503
|
console.error(
|
|
467
504
|
`Rendering ${outputFormat.toUpperCase()}: ${fps} fps${qualityLabel}, orientation: ${orientation}, captions: ${captions}, ${motionLabel}`
|
|
468
505
|
);
|
|
@@ -485,15 +522,20 @@ async function runVideo(inputPath, opts) {
|
|
|
485
522
|
bayerScale
|
|
486
523
|
}) : await renderDocToMp4(doc, container, {
|
|
487
524
|
...sharedRenderOptions,
|
|
488
|
-
quality
|
|
525
|
+
quality,
|
|
526
|
+
frameTransport,
|
|
527
|
+
captureFormat,
|
|
528
|
+
framesDir: opts.framesDir ? resolve2(opts.framesDir) : void 0,
|
|
529
|
+
resume: opts.resume
|
|
489
530
|
});
|
|
490
531
|
clearProgress();
|
|
491
532
|
const warnings = "warnings" in result2 && Array.isArray(result2.warnings) ? result2.warnings : [];
|
|
492
533
|
for (const warning of warnings) {
|
|
493
534
|
console.error(` \u26A0 ${warning}`);
|
|
494
535
|
}
|
|
536
|
+
const reused = "reusedFrameCount" in result2 && result2.reusedFrameCount ? `, ${result2.reusedFrameCount} reused from ${opts.framesDir}` : "";
|
|
495
537
|
console.error(
|
|
496
|
-
` \u2713 ${outputPath} (${result2.duration.toFixed(1)}s, ${result2.frameCount} frames)`
|
|
538
|
+
` \u2713 ${outputPath} (${result2.duration.toFixed(1)}s, ${result2.frameCount} frames${reused})`
|
|
497
539
|
);
|
|
498
540
|
console.error("Done.");
|
|
499
541
|
}
|