@bendyline/squisq-cli 1.0.1 → 1.1.0

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 CHANGED
@@ -54,6 +54,49 @@ squisq video ./my-folder --orientation portrait --captions social
54
54
 
55
55
  **Requires:** [ffmpeg](https://ffmpeg.org/) installed and available on your PATH.
56
56
 
57
+ ## Programmatic API
58
+
59
+ Use the CLI as a library from Node.js — no shell-out required:
60
+
61
+ ```ts
62
+ import { renderDocToMp4, MemoryContentContainer, readInput } from '@bendyline/squisq-cli/api';
63
+
64
+ // Load a document from disk
65
+ const { doc, container } = await readInput('./my-article.md');
66
+
67
+ // Render to MP4
68
+ const result = await renderDocToMp4(doc, container, {
69
+ outputPath: './output.mp4',
70
+ fps: 30,
71
+ quality: 'high',
72
+ orientation: 'landscape',
73
+ captionStyle: 'social',
74
+ onProgress: (phase, pct) => console.log(`${phase}: ${pct}%`),
75
+ });
76
+
77
+ console.log(`Rendered ${result.frameCount} frames (${result.duration}s)`);
78
+ ```
79
+
80
+ ### `extractThumbnails`
81
+
82
+ Extract JPEG thumbnails from the first frame of a rendered video:
83
+
84
+ ```ts
85
+ import { extractThumbnails } from '@bendyline/squisq-cli/api';
86
+
87
+ await extractThumbnails({
88
+ videoPath: './output.mp4',
89
+ outputDir: './thumbs',
90
+ slug: 'my-article',
91
+ sizes: [
92
+ { name: 'og', width: 1200, height: 630, filter: 'scale=1200:630' },
93
+ { name: 'thumb', width: 480, height: 270, filter: 'scale=480:270' },
94
+ ],
95
+ });
96
+ ```
97
+
98
+ See the full [API Reference](../../docs/API.md#bendylinesquisq-cli) for all types and options.
99
+
57
100
  ## Input Formats
58
101
 
59
102
  The CLI accepts three types of input:
@@ -21,6 +21,7 @@ describe('readInput', () => {
21
21
  });
22
22
  it('reads a .md file into a container and MarkdownDocument', async () => {
23
23
  const result = await readInput(FIXTURE_MD);
24
+ expect(result.markdownDoc).to.not.equal(null);
24
25
  expect(result.markdownDoc).to.have.property('type', 'document');
25
26
  expect(result.markdownDoc.children).to.be.an('array');
26
27
  expect(result.markdownDoc.children.length).to.be.greaterThan(0);
@@ -36,6 +37,7 @@ describe('readInput', () => {
36
37
  const zipPath = join(tempDir, 'test.zip');
37
38
  await writeFile(zipPath, buf);
38
39
  const result = await readInput(zipPath);
40
+ expect(result.markdownDoc).to.not.equal(null);
39
41
  expect(result.markdownDoc.type).to.equal('document');
40
42
  const doc = await result.container.readDocument();
41
43
  expect(doc).to.include('# From ZIP');
@@ -48,6 +50,7 @@ describe('readInput', () => {
48
50
  const dbkPath = join(tempDir, 'test.dbk');
49
51
  await writeFile(dbkPath, buf);
50
52
  const result = await readInput(dbkPath);
53
+ expect(result.markdownDoc).to.not.equal(null);
51
54
  expect(result.markdownDoc.type).to.equal('document');
52
55
  const doc = await result.container.readDocument();
53
56
  expect(doc).to.include('# From DBK');
@@ -58,6 +61,7 @@ describe('readInput', () => {
58
61
  await writeFile(join(folderPath, 'index.md'), '# Folder Doc\n\nContent here.');
59
62
  await writeFile(join(folderPath, 'image.txt'), 'placeholder');
60
63
  const result = await readInput(folderPath);
64
+ expect(result.markdownDoc).to.not.equal(null);
61
65
  expect(result.markdownDoc.type).to.equal('document');
62
66
  const doc = await result.container.readDocument();
63
67
  expect(doc).to.include('# Folder Doc');
@@ -76,8 +80,41 @@ describe('readInput', () => {
76
80
  }
77
81
  catch (err) {
78
82
  expect(err).to.be.instanceOf(Error);
79
- expect(err.message).to.include('No markdown document found');
83
+ expect(err.message).to.include('No markdown document');
80
84
  }
81
85
  });
86
+ it('reads a .json file as Doc JSON', async () => {
87
+ const doc = {
88
+ articleId: 'test-article',
89
+ duration: 30,
90
+ blocks: [{ id: 'b1', startTime: 0, duration: 30, audioSegment: 0 }],
91
+ audio: { segments: [] },
92
+ };
93
+ const jsonPath = join(tempDir, 'doc.json');
94
+ await writeFile(jsonPath, JSON.stringify(doc));
95
+ const result = await readInput(jsonPath);
96
+ expect(result.markdownDoc).to.equal(null);
97
+ expect(result.doc).to.deep.include({ articleId: 'test-article', duration: 30 });
98
+ expect(result.doc.blocks).to.have.length(1);
99
+ });
100
+ it('reads a folder with doc.json instead of markdown', async () => {
101
+ const folderPath = join(tempDir, 'jsondoc');
102
+ await mkdir(folderPath, { recursive: true });
103
+ const doc = {
104
+ articleId: 'folder-doc',
105
+ duration: 20,
106
+ blocks: [],
107
+ audio: { segments: [] },
108
+ };
109
+ await writeFile(join(folderPath, 'doc.json'), JSON.stringify(doc));
110
+ await writeFile(join(folderPath, 'image.txt'), 'placeholder');
111
+ const result = await readInput(folderPath);
112
+ expect(result.markdownDoc).to.equal(null);
113
+ expect(result.doc).to.deep.include({ articleId: 'folder-doc' });
114
+ // Media files are still in the container
115
+ const files = await result.container.listFiles();
116
+ const paths = files.map((f) => f.path);
117
+ expect(paths).to.include('image.txt');
118
+ });
82
119
  });
83
120
  //# sourceMappingURL=readInput.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"readInput.test.js","sourceRoot":"","sources":["../../src/__tests__/readInput.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"readInput.test.js","sourceRoot":"","sources":["../../src/__tests__/readInput.test.ts"],"names":[],"mappings":"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"}
package/dist/api.d.ts ADDED
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Programmatic Video API
3
+ *
4
+ * Provides a library-style entry point for rendering Squisq documents to MP4
5
+ * from Node.js callers (e.g., Qualla's pipeline). This avoids the need to shell
6
+ * out to the `squisq video` CLI and gives callers full control over the Doc,
7
+ * MemoryContentContainer, and encoding options.
8
+ *
9
+ * Orchestrates the full pipeline: Doc → render HTML → Playwright frame capture → FFmpeg encode.
10
+ *
11
+ * Usage:
12
+ * import { renderDocToMp4 } from '@bendyline/squisq-cli/api';
13
+ *
14
+ * await renderDocToMp4(doc, container, {
15
+ * outputPath: '/tmp/output.mp4',
16
+ * fps: 30,
17
+ * quality: 'normal',
18
+ * orientation: 'landscape',
19
+ * });
20
+ */
21
+ import type { Doc } from '@bendyline/squisq/schemas';
22
+ import type { MemoryContentContainer } from '@bendyline/squisq/storage';
23
+ import type { VideoQuality, VideoOrientation } from '@bendyline/squisq-video';
24
+ export type { VideoQuality, VideoOrientation } from '@bendyline/squisq-video';
25
+ export { MemoryContentContainer } from '@bendyline/squisq/storage';
26
+ export { readInput } from './util/readInput.js';
27
+ export type { ReadInputResult } from './util/readInput.js';
28
+ /** Options for renderDocToMp4. */
29
+ export interface RenderDocToMp4Options {
30
+ /** Output file path for the MP4. */
31
+ outputPath: string;
32
+ /** Frames per second (default: 30). */
33
+ fps?: number;
34
+ /** Encoding quality preset (default: 'normal'). */
35
+ quality?: VideoQuality;
36
+ /** Video orientation (default: 'landscape'). */
37
+ orientation?: VideoOrientation;
38
+ /** Override video width in pixels. */
39
+ width?: number;
40
+ /** Override video height in pixels. */
41
+ height?: number;
42
+ /** Caption style to bake into the video (default: none). */
43
+ captionStyle?: 'standard' | 'social';
44
+ /** Seconds of cover-slide pre-roll before the story starts (default: 0). */
45
+ coverPreRoll?: number;
46
+ /**
47
+ * Progress callback. Called with a phase name and 0-100 percentage.
48
+ */
49
+ onProgress?: (phase: string, percent: number) => void;
50
+ }
51
+ /** Result returned by renderDocToMp4. */
52
+ export interface RenderDocToMp4Result {
53
+ /** Duration of the rendered video in seconds (including pre-roll). */
54
+ duration: number;
55
+ /** Number of frames captured. */
56
+ frameCount: number;
57
+ /** Output file path. */
58
+ outputPath: string;
59
+ }
60
+ /**
61
+ * Render a Doc + media container to an MP4 video file.
62
+ *
63
+ * The container should contain audio and image files referenced by the Doc's
64
+ * audio.segments[].src and block image paths. Files are embedded as base64
65
+ * data URIs in a self-contained render HTML page.
66
+ *
67
+ * Requires:
68
+ * - Playwright (chromium) — for headless frame capture
69
+ * - FFmpeg — for video encoding (must be on PATH)
70
+ *
71
+ * @param doc - The Doc structure to render
72
+ * @param container - MemoryContentContainer with audio/image files
73
+ * @param options - Rendering and encoding options
74
+ * @returns Result with duration and frame count
75
+ */
76
+ export declare function renderDocToMp4(doc: Doc, container: MemoryContentContainer, options: RenderDocToMp4Options): Promise<RenderDocToMp4Result>;
77
+ /** A thumbnail size specification. */
78
+ export interface ThumbnailSpec {
79
+ /** Label for the thumbnail (used in filename: `{slug}-{width}x{height}.jpg`). */
80
+ name: string;
81
+ /** Output width in pixels. */
82
+ width: number;
83
+ /** Output height in pixels. */
84
+ height: number;
85
+ /** FFmpeg video filter string (e.g., 'scale=1280:720'). */
86
+ filter: string;
87
+ }
88
+ /** Options for extractThumbnails. */
89
+ export interface ExtractThumbnailsOptions {
90
+ /** Path to the source MP4 video. */
91
+ videoPath: string;
92
+ /** Directory to write thumbnails into. */
93
+ outputDir: string;
94
+ /** Base slug for filenames (produces `{slug}-{width}x{height}.jpg`). */
95
+ slug: string;
96
+ /** Thumbnail sizes to generate. */
97
+ sizes: ThumbnailSpec[];
98
+ /** Overwrite existing thumbnails (default: false). */
99
+ force?: boolean;
100
+ }
101
+ /**
102
+ * Extract thumbnail images from the first frame of an MP4 video.
103
+ * Produces JPEG files at each specified size using FFmpeg video filters.
104
+ */
105
+ export declare function extractThumbnails(options: ExtractThumbnailsOptions): Promise<void>;
106
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAM9E,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,kCAAkC;AAClC,MAAM,WAAW,qBAAqB;IACpC,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IAEnB,uCAAuC;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,mDAAmD;IACnD,OAAO,CAAC,EAAE,YAAY,CAAC;IAEvB,gDAAgD;IAChD,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAE/B,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAC;IAErC,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACvD;AAED,yCAAyC;AACzC,MAAM,WAAW,oBAAoB;IACnC,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;IAEjB,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;IAEnB,wBAAwB;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,sBAAsB,EACjC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CA8L/B;AAmID,sCAAsC;AACtC,MAAM,WAAW,aAAa;IAC5B,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qCAAqC;AACrC,MAAM,WAAW,wBAAwB;IACvC,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,sDAAsD;IACtD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiCxF"}
package/dist/api.js ADDED
@@ -0,0 +1,324 @@
1
+ /**
2
+ * Programmatic Video API
3
+ *
4
+ * Provides a library-style entry point for rendering Squisq documents to MP4
5
+ * from Node.js callers (e.g., Qualla's pipeline). This avoids the need to shell
6
+ * out to the `squisq video` CLI and gives callers full control over the Doc,
7
+ * MemoryContentContainer, and encoding options.
8
+ *
9
+ * Orchestrates the full pipeline: Doc → render HTML → Playwright frame capture → FFmpeg encode.
10
+ *
11
+ * Usage:
12
+ * import { renderDocToMp4 } from '@bendyline/squisq-cli/api';
13
+ *
14
+ * await renderDocToMp4(doc, container, {
15
+ * outputPath: '/tmp/output.mp4',
16
+ * fps: 30,
17
+ * quality: 'normal',
18
+ * orientation: 'landscape',
19
+ * });
20
+ */
21
+ import { generateRenderHtml } from '@bendyline/squisq-video';
22
+ import { resolveDimensions } from '@bendyline/squisq-video';
23
+ import { detectFfmpeg } from './util/detectFfmpeg.js';
24
+ export { MemoryContentContainer } from '@bendyline/squisq/storage';
25
+ export { readInput } from './util/readInput.js';
26
+ /**
27
+ * Render a Doc + media container to an MP4 video file.
28
+ *
29
+ * The container should contain audio and image files referenced by the Doc's
30
+ * audio.segments[].src and block image paths. Files are embedded as base64
31
+ * data URIs in a self-contained render HTML page.
32
+ *
33
+ * Requires:
34
+ * - Playwright (chromium) — for headless frame capture
35
+ * - FFmpeg — for video encoding (must be on PATH)
36
+ *
37
+ * @param doc - The Doc structure to render
38
+ * @param container - MemoryContentContainer with audio/image files
39
+ * @param options - Rendering and encoding options
40
+ * @returns Result with duration and frame count
41
+ */
42
+ export async function renderDocToMp4(doc, container, options) {
43
+ const { outputPath, fps = 30, quality = 'normal', orientation = 'landscape', captionStyle, coverPreRoll = 0, onProgress, } = options;
44
+ const dimensions = resolveDimensions({
45
+ orientation,
46
+ width: options.width,
47
+ height: options.height,
48
+ });
49
+ // Detect ffmpeg early — needed for audio concat and video encoding
50
+ const ffmpegPath = await detectFfmpeg();
51
+ if (!ffmpegPath) {
52
+ throw new Error('ffmpeg is required but not found in PATH.\n' +
53
+ 'Install it with:\n' +
54
+ ' macOS: brew install ffmpeg\n' +
55
+ ' Ubuntu: sudo apt install ffmpeg\n' +
56
+ ' Windows: winget install ffmpeg');
57
+ }
58
+ onProgress?.('collecting media', 0);
59
+ // ── Collect images from container ───────────────────────────────
60
+ const { collectImagePaths } = await import('@bendyline/squisq-formats/html');
61
+ const imagePaths = collectImagePaths(doc);
62
+ const images = new Map();
63
+ for (const imgPath of imagePaths) {
64
+ const data = await container.readFile(imgPath);
65
+ if (data) {
66
+ images.set(imgPath, data);
67
+ }
68
+ }
69
+ // ── Collect audio segments ──────────────────────────────────────
70
+ const audio = new Map();
71
+ const audioBuffers = [];
72
+ if (doc.audio?.segments?.length) {
73
+ for (const seg of doc.audio.segments) {
74
+ const data = await container.readFile(seg.src);
75
+ if (data) {
76
+ audio.set(seg.src, data);
77
+ audio.set(seg.name, data);
78
+ audioBuffers.push(data);
79
+ }
80
+ }
81
+ }
82
+ // Concatenate audio for the MP4's audio track
83
+ let concatenatedAudio = null;
84
+ if (audioBuffers.length > 0) {
85
+ concatenatedAudio = await concatenateAudioBuffers(audioBuffers, ffmpegPath);
86
+ }
87
+ onProgress?.('generating render HTML', 10);
88
+ // ── Generate self-contained render HTML ─────────────────────────
89
+ const { PLAYER_BUNDLE } = await import('@bendyline/squisq-react/standalone-source');
90
+ const renderHtml = generateRenderHtml(doc, {
91
+ playerScript: PLAYER_BUNDLE,
92
+ images,
93
+ audio: audio.size > 0 ? audio : undefined,
94
+ width: dimensions.width,
95
+ height: dimensions.height,
96
+ captionStyle,
97
+ });
98
+ onProgress?.('launching browser', 15);
99
+ // ── Playwright frame capture ────────────────────────────────────
100
+ const { chromium } = await import('playwright-core');
101
+ const browser = await chromium.launch({ headless: true });
102
+ const page = await browser.newPage({
103
+ viewport: { width: dimensions.width, height: dimensions.height },
104
+ });
105
+ const pageErrors = [];
106
+ page.on('pageerror', (err) => pageErrors.push(err.message));
107
+ await page.setContent(renderHtml, { waitUntil: 'load' });
108
+ await page.waitForTimeout(500);
109
+ try {
110
+ await page.waitForFunction(() => typeof window.getDuration === 'function', { timeout: 15000 });
111
+ }
112
+ catch {
113
+ await browser.close();
114
+ const errorDetail = pageErrors.length
115
+ ? `\nPage errors:\n ${pageErrors.join('\n ')}`
116
+ : '\nNo page errors captured — the player may have failed to mount.';
117
+ throw new Error(`Render API did not initialize within 15 seconds.${errorDetail}`);
118
+ }
119
+ const docDuration = await page.evaluate(() => {
120
+ return window.getDuration();
121
+ });
122
+ if (docDuration <= 0) {
123
+ await browser.close();
124
+ throw new Error('Document has zero duration — nothing to render');
125
+ }
126
+ const storyFrameCount = Math.ceil(docDuration * fps);
127
+ const preRollFrameCount = Math.ceil(coverPreRoll * fps);
128
+ const totalFrames = preRollFrameCount + storyFrameCount;
129
+ const frames = [];
130
+ onProgress?.('capturing frames', 20);
131
+ // Cover slide pre-roll (if requested)
132
+ if (preRollFrameCount > 0) {
133
+ const hasCover = await page.evaluate(() => {
134
+ const w = window;
135
+ return typeof w.hasCoverBlock === 'function' ? w.hasCoverBlock() : false;
136
+ });
137
+ if (hasCover) {
138
+ await page.evaluate(() => {
139
+ window.showCover();
140
+ });
141
+ await page.waitForTimeout(100);
142
+ const coverFrame = new Uint8Array(await page.screenshot({ type: 'png' }));
143
+ for (let i = 0; i < preRollFrameCount; i++) {
144
+ frames.push(coverFrame);
145
+ }
146
+ await page.evaluate(() => {
147
+ window.hideCover();
148
+ });
149
+ }
150
+ }
151
+ // Story frames via seekTo
152
+ const frameInterval = 1 / fps;
153
+ for (let i = 0; i < storyFrameCount; i++) {
154
+ const time = i * frameInterval;
155
+ await page.evaluate((t) => {
156
+ return window.seekTo(t);
157
+ }, time);
158
+ const screenshot = await page.screenshot({ type: 'png' });
159
+ frames.push(new Uint8Array(screenshot));
160
+ // Report progress: frames phase is 20% to 80%
161
+ if (i % Math.max(1, Math.floor(fps / 2)) === 0 || i === storyFrameCount - 1) {
162
+ const pct = 20 + Math.round((frames.length / totalFrames) * 60);
163
+ onProgress?.('capturing frames', pct);
164
+ }
165
+ }
166
+ await browser.close();
167
+ onProgress?.('encoding video', 80);
168
+ // If there's a pre-roll, delay the audio track to match
169
+ let encodingAudio = concatenatedAudio;
170
+ if (coverPreRoll > 0 && concatenatedAudio) {
171
+ // Use FFmpeg to add silence padding at the start (adelay filter)
172
+ encodingAudio = await addAudioDelay(ffmpegPath, concatenatedAudio, coverPreRoll);
173
+ }
174
+ const { framesToMp4Native } = await import('./util/nativeEncoder.js');
175
+ await framesToMp4Native(ffmpegPath, frames, encodingAudio, outputPath, {
176
+ fps,
177
+ quality,
178
+ orientation,
179
+ width: dimensions.width,
180
+ height: dimensions.height,
181
+ onProgress: (percent, phase) => {
182
+ onProgress?.(`encoding: ${phase}`, 80 + Math.round(percent * 0.2));
183
+ },
184
+ });
185
+ onProgress?.('done', 100);
186
+ const totalDuration = docDuration + coverPreRoll;
187
+ return {
188
+ duration: totalDuration,
189
+ frameCount: frames.length,
190
+ outputPath,
191
+ };
192
+ }
193
+ // ── Audio helpers ─────────────────────────────────────────────────
194
+ /**
195
+ * Concatenate multiple audio buffers into one.
196
+ * Uses native ffmpeg concat when available, falls back to byte concatenation.
197
+ */
198
+ async function concatenateAudioBuffers(buffers, ffmpegPath) {
199
+ if (buffers.length === 0)
200
+ return new Uint8Array(0);
201
+ if (buffers.length === 1)
202
+ return new Uint8Array(buffers[0]);
203
+ if (ffmpegPath) {
204
+ return concatenateAudioNative(ffmpegPath, buffers);
205
+ }
206
+ // Fallback: naive byte concatenation (works for MP3)
207
+ const totalLength = buffers.reduce((sum, b) => sum + b.byteLength, 0);
208
+ const result = new Uint8Array(totalLength);
209
+ let offset = 0;
210
+ for (const buf of buffers) {
211
+ result.set(new Uint8Array(buf), offset);
212
+ offset += buf.byteLength;
213
+ }
214
+ return result;
215
+ }
216
+ async function concatenateAudioNative(ffmpegPath, buffers) {
217
+ const { writeFile, readFile, mkdir, rm } = await import('node:fs/promises');
218
+ const { join } = await import('node:path');
219
+ const { tmpdir } = await import('node:os');
220
+ const { randomBytes } = await import('node:crypto');
221
+ const { execFile } = await import('node:child_process');
222
+ const tmpId = randomBytes(8).toString('hex');
223
+ const workDir = join(tmpdir(), `squisq-audio-concat-${tmpId}`);
224
+ await mkdir(workDir, { recursive: true });
225
+ try {
226
+ const segmentPaths = [];
227
+ for (let i = 0; i < buffers.length; i++) {
228
+ const segPath = join(workDir, `seg-${i}.mp3`);
229
+ await writeFile(segPath, new Uint8Array(buffers[i]));
230
+ segmentPaths.push(segPath);
231
+ }
232
+ const listPath = join(workDir, 'concat-list.txt');
233
+ const listContent = segmentPaths.map((p) => `file '${p.replace(/\\/g, '/')}'`).join('\n');
234
+ await writeFile(listPath, listContent);
235
+ const outputPath = join(workDir, 'combined.mp3');
236
+ await new Promise((resolve, reject) => {
237
+ execFile(ffmpegPath, ['-y', '-f', 'concat', '-safe', '0', '-i', listPath, '-c', 'copy', outputPath], { timeout: 120000 }, (err) => {
238
+ if (err)
239
+ reject(new Error(`ffmpeg audio concat failed: ${err.message}`));
240
+ else
241
+ resolve();
242
+ });
243
+ });
244
+ const data = await readFile(outputPath);
245
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
246
+ }
247
+ finally {
248
+ await rm(workDir, { recursive: true, force: true });
249
+ }
250
+ }
251
+ /**
252
+ * Add silence at the start of an audio track by re-encoding with adelay filter.
253
+ */
254
+ async function addAudioDelay(ffmpegPath, audioData, delaySecs) {
255
+ const { writeFile, readFile, rm } = await import('node:fs/promises');
256
+ const { join } = await import('node:path');
257
+ const { tmpdir } = await import('node:os');
258
+ const { randomBytes } = await import('node:crypto');
259
+ const { execFile } = await import('node:child_process');
260
+ const tmpId = randomBytes(8).toString('hex');
261
+ const inputPath = join(tmpdir(), `squisq-audio-delay-in-${tmpId}.mp3`);
262
+ const outputPath = join(tmpdir(), `squisq-audio-delay-out-${tmpId}.mp3`);
263
+ try {
264
+ await writeFile(inputPath, audioData);
265
+ const delayMs = Math.round(delaySecs * 1000);
266
+ await new Promise((resolve, reject) => {
267
+ execFile(ffmpegPath, [
268
+ '-y',
269
+ '-i',
270
+ inputPath,
271
+ '-af',
272
+ `adelay=${delayMs}|${delayMs}`,
273
+ '-c:a',
274
+ 'libmp3lame',
275
+ '-b:a',
276
+ '128k',
277
+ outputPath,
278
+ ], { timeout: 60000 }, (err) => {
279
+ if (err)
280
+ reject(new Error(`ffmpeg audio delay failed: ${err.message}`));
281
+ else
282
+ resolve();
283
+ });
284
+ });
285
+ const data = await readFile(outputPath);
286
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
287
+ }
288
+ finally {
289
+ await rm(inputPath, { force: true });
290
+ await rm(outputPath, { force: true });
291
+ }
292
+ }
293
+ /**
294
+ * Extract thumbnail images from the first frame of an MP4 video.
295
+ * Produces JPEG files at each specified size using FFmpeg video filters.
296
+ */
297
+ export async function extractThumbnails(options) {
298
+ const { videoPath, outputDir, slug, sizes, force } = options;
299
+ const { existsSync } = await import('node:fs');
300
+ const { join } = await import('node:path');
301
+ const { execFile } = await import('node:child_process');
302
+ const ffmpegPath = await detectFfmpeg();
303
+ if (!ffmpegPath) {
304
+ throw new Error('ffmpeg is required for thumbnail extraction but not found in PATH.\n' +
305
+ 'Install it with:\n' +
306
+ ' macOS: brew install ffmpeg\n' +
307
+ ' Ubuntu: sudo apt install ffmpeg\n' +
308
+ ' Windows: winget install ffmpeg');
309
+ }
310
+ for (const thumb of sizes) {
311
+ const outputPath = join(outputDir, `${slug}-${thumb.width}x${thumb.height}.jpg`);
312
+ if (!force && existsSync(outputPath))
313
+ continue;
314
+ await new Promise((resolve, reject) => {
315
+ execFile(ffmpegPath, ['-y', '-i', videoPath, '-vf', thumb.filter, '-frames:v', '1', '-q:v', '2', outputPath], { timeout: 30000 }, (err) => {
316
+ if (err)
317
+ reject(new Error(`Thumbnail extraction failed (${thumb.name}): ${err.message}`));
318
+ else
319
+ resolve();
320
+ });
321
+ });
322
+ }
323
+ }
324
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAKH,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAItD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AA+ChD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAQ,EACR,SAAiC,EACjC,OAA8B;IAE9B,MAAM,EACJ,UAAU,EACV,GAAG,GAAG,EAAE,EACR,OAAO,GAAG,QAAQ,EAClB,WAAW,GAAG,WAAW,EACzB,YAAY,EACZ,YAAY,GAAG,CAAC,EAChB,UAAU,GACX,GAAG,OAAO,CAAC;IAEZ,MAAM,UAAU,GAAG,iBAAiB,CAAC;QACnC,WAAW;QACX,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IAEH,mEAAmE;IACnE,MAAM,UAAU,GAAG,MAAM,YAAY,EAAE,CAAC;IACxC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACb,6CAA6C;YAC3C,oBAAoB;YACpB,kCAAkC;YAClC,sCAAsC;YACtC,kCAAkC,CACrC,CAAC;IACJ,CAAC;IAED,UAAU,EAAE,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC;IAEpC,mEAAmE;IACnE,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,gCAAgC,CAAC,CAAC;IAC7E,MAAM,UAAU,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC9C,KAAK,MAAM,OAAO,IAAI,UAAU,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC/C,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,mEAAmE;IACnE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC7C,MAAM,YAAY,GAAkB,EAAE,CAAC;IACvC,IAAI,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QAChC,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;YACrC,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC/C,IAAI,IAAI,EAAE,CAAC;gBACT,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBACzB,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAC1B,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;IAED,8CAA8C;IAC9C,IAAI,iBAAiB,GAAsB,IAAI,CAAC;IAChD,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,iBAAiB,GAAG,MAAM,uBAAuB,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAC9E,CAAC;IAED,UAAU,EAAE,CAAC,wBAAwB,EAAE,EAAE,CAAC,CAAC;IAE3C,mEAAmE;IACnE,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,2CAA2C,CAAC,CAAC;IACpF,MAAM,UAAU,GAAG,kBAAkB,CAAC,GAAG,EAAE;QACzC,YAAY,EAAE,aAAa;QAC3B,MAAM;QACN,KAAK,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;QACzC,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,YAAY;KACb,CAAC,CAAC;IAEH,UAAU,EAAE,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;IAEtC,mEAAmE;IACnE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC;QACjC,QAAQ,EAAE,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE;KACjE,CAAC,CAAC;IAEH,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IAE5D,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;IACzD,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;IAE/B,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,eAAe,CACxB,GAAG,EAAE,CAAC,OAAQ,MAA6C,CAAC,WAAW,KAAK,UAAU,EACtF,EAAE,OAAO,EAAE,KAAK,EAAE,CACnB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACtB,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM;YACnC,CAAC,CAAC,qBAAqB,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;YAChD,CAAC,CAAC,kEAAkE,CAAC;QACvE,MAAM,IAAI,KAAK,CAAC,mDAAmD,WAAW,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,MAAM,WAAW,GAAW,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE;QACnD,OAAQ,MAAmD,CAAC,WAAW,EAAE,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;QACrB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC;IACrD,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC,CAAC;IACxD,MAAM,WAAW,GAAG,iBAAiB,GAAG,eAAe,CAAC;IACxD,MAAM,MAAM,GAAiB,EAAE,CAAC;IAEhC,UAAU,EAAE,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;IAErC,sCAAsC;IACtC,IAAI,iBAAiB,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAY,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE;YACjD,MAAM,CAAC,GAAG,MAAsD,CAAC;YACjE,OAAO,OAAO,CAAC,CAAC,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;QAC3E,CAAC,CAAC,CAAC;QAEH,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE;gBACtB,MAA+C,CAAC,SAAS,EAAE,CAAC;YAC/D,CAAC,CAAC,CAAC;YACH,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;YAC/B,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;YAC1E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,iBAAiB,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3C,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC1B,CAAC;YACD,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE;gBACtB,MAA+C,CAAC,SAAS,EAAE,CAAC;YAC/D,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,0BAA0B;IAC1B,MAAM,aAAa,GAAG,CAAC,GAAG,GAAG,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,CAAC,GAAG,aAAa,CAAC;QAC/B,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAS,EAAE,EAAE;YAChC,OAAQ,MAA8D,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnF,CAAC,EAAE,IAAI,CAAC,CAAC;QAET,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1D,MAAM,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;QAExC,8CAA8C;QAC9C,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,eAAe,GAAG,CAAC,EAAE,CAAC;YAC5E,MAAM,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;YAChE,UAAU,EAAE,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IAEtB,UAAU,EAAE,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;IAEnC,wDAAwD;IACxD,IAAI,aAAa,GAAG,iBAAiB,CAAC;IACtC,IAAI,YAAY,GAAG,CAAC,IAAI,iBAAiB,EAAE,CAAC;QAC1C,iEAAiE;QACjE,aAAa,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,iBAAiB,EAAE,YAAY,CAAC,CAAC;IACnF,CAAC;IAED,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAC;IACtE,MAAM,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE;QACrE,GAAG;QACH,OAAO;QACP,WAAW;QACX,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,UAAU,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;YAC7B,UAAU,EAAE,CAAC,aAAa,KAAK,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC;QACrE,CAAC;KACF,CAAC,CAAC;IAEH,UAAU,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAE1B,MAAM,aAAa,GAAG,WAAW,GAAG,YAAY,CAAC;IACjD,OAAO;QACL,QAAQ,EAAE,aAAa;QACvB,UAAU,EAAE,MAAM,CAAC,MAAM;QACzB,UAAU;KACX,CAAC;AACJ,CAAC;AAED,qEAAqE;AAErE;;;GAGG;AACH,KAAK,UAAU,uBAAuB,CACpC,OAAsB,EACtB,UAAmB;IAEnB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IACnD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAE5D,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,sBAAsB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACrD,CAAC;IAED,qDAAqD;IACrD,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IACtE,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,CAAC,UAAU,CAAC;IAC3B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,sBAAsB,CACnC,UAAkB,EAClB,OAAsB;IAEtB,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAC5E,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;IAC3C,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IAC3C,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IACpD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAExD,MAAM,KAAK,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,uBAAuB,KAAK,EAAE,CAAC,CAAC;IAC/D,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,IAAI,CAAC;QACH,MAAM,YAAY,GAAa,EAAE,CAAC;QAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YAC9C,MAAM,SAAS,CAAC,OAAO,EAAE,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACrD,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;QAClD,MAAM,WAAW,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1F,MAAM,SAAS,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QAEvC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;QACjD,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,QAAQ,CACN,UAAU,EACV,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAC9E,EAAE,OAAO,EAAE,MAAO,EAAE,EACpB,CAAC,GAAG,EAAE,EAAE;gBACN,IAAI,GAAG;oBAAE,MAAM,CAAC,IAAI,KAAK,CAAC,+BAA+B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;;oBACpE,OAAO,EAAE,CAAC;YACjB,CAAC,CACF,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,CAAC;QACxC,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACvE,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,aAAa,CAC1B,UAAkB,EAClB,SAAqB,EACrB,SAAiB;IAEjB,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;IACrE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;IAC3C,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IAC3C,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IACpD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAExD,MAAM,KAAK,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,yBAAyB,KAAK,MAAM,CAAC,CAAC;IACvE,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,0BAA0B,KAAK,MAAM,CAAC,CAAC;IAEzE,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;QAE7C,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,QAAQ,CACN,UAAU,EACV;gBACE,IAAI;gBACJ,IAAI;gBACJ,SAAS;gBACT,KAAK;gBACL,UAAU,OAAO,IAAI,OAAO,EAAE;gBAC9B,MAAM;gBACN,YAAY;gBACZ,MAAM;gBACN,MAAM;gBACN,UAAU;aACX,EACD,EAAE,OAAO,EAAE,KAAM,EAAE,EACnB,CAAC,GAAG,EAAE,EAAE;gBACN,IAAI,GAAG;oBAAE,MAAM,CAAC,IAAI,KAAK,CAAC,8BAA8B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;;oBACnE,OAAO,EAAE,CAAC;YACjB,CAAC,CACF,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,CAAC;QACxC,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACvE,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACrC,MAAM,EAAE,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AA8BD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAiC;IACvE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAC7D,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;IAC3C,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAExD,MAAM,UAAU,GAAG,MAAM,YAAY,EAAE,CAAC;IACxC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACb,sEAAsE;YACpE,oBAAoB;YACpB,kCAAkC;YAClC,sCAAsC;YACtC,kCAAkC,CACrC,CAAC;IACJ,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,MAAM,CAAC,CAAC;QACjF,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,UAAU,CAAC;YAAE,SAAS;QAE/C,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,QAAQ,CACN,UAAU,EACV,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,CAAC,EACvF,EAAE,OAAO,EAAE,KAAM,EAAE,EACnB,CAAC,GAAG,EAAE,EAAE;gBACN,IAAI,GAAG;oBAAE,MAAM,CAAC,IAAI,KAAK,CAAC,gCAAgC,KAAK,CAAC,IAAI,MAAM,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;;oBACrF,OAAO,EAAE,CAAC;YACjB,CAAC,CACF,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
@@ -77,11 +77,15 @@ async function runConvert(inputPath, opts) {
77
77
  }
78
78
  }
79
79
  console.error(`Reading: ${resolvedInput}`);
80
- const { container, markdownDoc } = await readInput(resolvedInput);
80
+ const result = await readInput(resolvedInput);
81
+ const { container } = result;
82
+ if (!result.markdownDoc) {
83
+ throw new Error('Convert command requires a markdown document. JSON Doc input is not supported for convert — use the video command instead.');
84
+ }
81
85
  // Apply transform if requested
82
- let exportMarkdownDoc = markdownDoc;
86
+ let exportMarkdownDoc = result.markdownDoc;
83
87
  if (opts.transform) {
84
- exportMarkdownDoc = await applyTransformToMarkdown(markdownDoc, container, opts.transform, opts.theme);
88
+ exportMarkdownDoc = await applyTransformToMarkdown(result.markdownDoc, container, opts.transform, opts.theme);
85
89
  console.error(` Applied transform: ${opts.transform}`);
86
90
  }
87
91
  const themeId = opts.theme;
@@ -1 +1 @@
1
- {"version":3,"file":"convert.js","sourceRoot":"","sources":["../../src/commands/convert.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"convert.js","sourceRoot":"","sources":["../../src/commands/convert.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,8 @@
1
1
  /**
2
2
  * video command
3
3
  *
4
- * Renders a squisq document to MP4 video by:
5
- * 1. Parsing the input (markdown, container, or folder)
6
- * 2. Generating a self-contained render HTML
7
- * 3. Capturing frames via Playwright headless browser
8
- * 4. Encoding to MP4 using native ffmpeg (fast) or ffmpeg.wasm (fallback)
4
+ * Renders a squisq document to MP4 video by delegating to the
5
+ * programmatic renderDocToMp4 API.
9
6
  *
10
7
  * Usage:
11
8
  * squisq video <input> [-o output.mp4] [--fps 30] [--quality normal] [--orientation landscape]
@@ -1 +1 @@
1
- {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../src/commands/video.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuBzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsC3D"}
1
+ {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../src/commands/video.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuBzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsC3D"}
@@ -1,11 +1,8 @@
1
1
  /**
2
2
  * video command
3
3
  *
4
- * Renders a squisq document to MP4 video by:
5
- * 1. Parsing the input (markdown, container, or folder)
6
- * 2. Generating a self-contained render HTML
7
- * 3. Capturing frames via Playwright headless browser
8
- * 4. Encoding to MP4 using native ffmpeg (fast) or ffmpeg.wasm (fallback)
4
+ * Renders a squisq document to MP4 video by delegating to the
5
+ * programmatic renderDocToMp4 API.
9
6
  *
10
7
  * Usage:
11
8
  * squisq video <input> [-o output.mp4] [--fps 30] [--quality normal] [--orientation landscape]
@@ -13,7 +10,7 @@
13
10
  import { mkdir } from 'node:fs/promises';
14
11
  import { dirname, basename, extname, resolve } from 'node:path';
15
12
  import { readInput } from '../util/readInput.js';
16
- import { detectFfmpeg } from '../util/detectFfmpeg.js';
13
+ import { renderDocToMp4 } from '../api.js';
17
14
  const VALID_QUALITIES = ['draft', 'normal', 'high'];
18
15
  const VALID_ORIENTATIONS = ['landscape', 'portrait'];
19
16
  const VALID_CAPTIONS = ['off', 'standard', 'social'];
@@ -76,166 +73,38 @@ async function runVideo(inputPath, opts) {
76
73
  await mkdir(dirname(outputPath), { recursive: true });
77
74
  // ── Step 1: Read input ──────────────────────────────────────────
78
75
  console.error(`Reading: ${resolvedInput}`);
79
- const { container, markdownDoc } = await readInput(resolvedInput);
80
- // ── Step 2: Parse to Doc ────────────────────────────────────────
81
- const { markdownToDoc } = await import('@bendyline/squisq/doc');
82
- const doc = markdownToDoc(markdownDoc);
83
- // ── Step 3: Collect media from container ────────────────────────
84
- const { collectImagePaths } = await import('@bendyline/squisq-formats/html');
85
- const imagePaths = collectImagePaths(doc);
86
- const images = new Map();
87
- for (const imgPath of imagePaths) {
88
- const data = await container.readFile(imgPath);
89
- if (data) {
90
- images.set(imgPath, data);
91
- }
76
+ const result = await readInput(resolvedInput);
77
+ const { container } = result;
78
+ // ── Step 2: Get or parse Doc ────────────────────────────────────
79
+ let doc;
80
+ if (result.doc) {
81
+ console.error('Using pre-built Doc JSON');
82
+ doc = result.doc;
92
83
  }
93
- // Collect audio segments
94
- const audio = new Map();
95
- let concatenatedAudio = null;
96
- if (doc.audio?.segments?.length) {
97
- for (const seg of doc.audio.segments) {
98
- const data = await container.readFile(seg.src);
99
- if (data) {
100
- audio.set(seg.src, data);
101
- // Also map by name for the audio URL rewriting in the player
102
- audio.set(seg.name, data);
103
- }
104
- }
105
- // For encoding, concatenate audio segments into one file
106
- // The player handles segment playback internally, but the encoder
107
- // needs a single audio track. We'll use the first segment as a
108
- // representative — full audio concatenation would need ffmpeg.
109
- // For now, pass audio map to the render HTML so the player handles it.
110
- if (audio.size > 0) {
111
- // Use the first segment's raw bytes — the encoder will handle it
112
- const firstSeg = doc.audio.segments[0];
113
- const firstData = await container.readFile(firstSeg.src);
114
- if (firstData) {
115
- concatenatedAudio = new Uint8Array(firstData);
116
- }
117
- }
84
+ else if (result.markdownDoc) {
85
+ const { markdownToDoc } = await import('@bendyline/squisq/doc');
86
+ doc = markdownToDoc(result.markdownDoc);
118
87
  }
119
- // ── Step 4: Generate render HTML ────────────────────────────────
120
- const { generateRenderHtml } = await import('@bendyline/squisq-video');
121
- const { PLAYER_BUNDLE } = await import('@bendyline/squisq-react/standalone-source');
122
- const { resolveDimensions } = await import('@bendyline/squisq-video');
123
- const dimensions = resolveDimensions({
124
- orientation,
125
- width: opts.width ? parseInt(opts.width, 10) : undefined,
126
- height: opts.height ? parseInt(opts.height, 10) : undefined,
127
- });
128
- const renderHtml = generateRenderHtml(doc, {
129
- playerScript: PLAYER_BUNDLE,
130
- images,
131
- audio: audio.size > 0 ? audio : undefined,
132
- width: dimensions.width,
133
- height: dimensions.height,
134
- captionStyle,
135
- });
136
- console.error(`Viewport: ${dimensions.width}x${dimensions.height}, ${fps} fps, quality: ${quality}, captions: ${captions}`);
137
- // ── Step 5: Capture frames via Playwright ───────────────────────
138
- const { chromium } = await import('playwright-core');
139
- const browser = await chromium.launch({ headless: true });
140
- const page = await browser.newPage({
141
- viewport: { width: dimensions.width, height: dimensions.height },
142
- });
143
- // Capture page errors so they don't vanish silently
144
- const pageErrors = [];
145
- page.on('pageerror', (err) => pageErrors.push(err.message));
146
- page.on('console', (msg) => {
147
- if (msg.type() === 'error')
148
- pageErrors.push(msg.text());
149
- });
150
- // Load the render HTML — use 'load' since everything is inline (no network)
151
- await page.setContent(renderHtml, { waitUntil: 'load' });
152
- // Give React one frame to mount and run useEffect
153
- await page.waitForTimeout(500);
154
- // Wait for the render API to be available
155
- try {
156
- await page.waitForFunction(() => typeof window.getDuration === 'function', { timeout: 15000 });
157
- }
158
- catch {
159
- await browser.close();
160
- const errorDetail = pageErrors.length
161
- ? `\nPage errors:\n ${pageErrors.join('\n ')}`
162
- : '\nNo page errors captured — the player may have failed to mount.';
163
- throw new Error(`Render API did not initialize within 15 seconds.${errorDetail}`);
164
- }
165
- // Get duration from the player
166
- const duration = await page.evaluate(() => {
167
- return window.getDuration();
168
- });
169
- if (duration <= 0) {
170
- await browser.close();
171
- throw new Error('Document has zero duration — nothing to render');
172
- }
173
- const totalFrames = Math.ceil(duration * fps);
174
- console.error(`Duration: ${duration.toFixed(1)}s, ${totalFrames} frames to capture`);
175
- const frames = [];
176
- const frameInterval = 1 / fps;
177
- // Optional: render cover frame (time 0)
178
- const hasCover = await page.evaluate(() => {
179
- const w = window;
180
- return typeof w.hasCoverBlock === 'function' ? w.hasCoverBlock() : false;
181
- });
182
- if (hasCover) {
183
- const coverFrameCount = 2 * fps;
184
- await page.evaluate(() => {
185
- window.showCover();
186
- });
187
- await page.waitForTimeout(100);
188
- const coverScreenshot = await page.screenshot({ type: 'png' });
189
- const coverFrame = new Uint8Array(coverScreenshot);
190
- for (let i = 0; i < coverFrameCount; i++) {
191
- frames.push(coverFrame);
192
- }
193
- await page.evaluate(() => {
194
- window.hideCover();
195
- });
196
- writeProgress('Capturing', coverFrameCount, totalFrames + coverFrameCount);
197
- }
198
- // Capture animation frames
199
- const totalWithCover = totalFrames + frames.length;
200
- for (let i = 0; i < totalFrames; i++) {
201
- const time = i * frameInterval;
202
- await page.evaluate((t) => {
203
- return window.seekTo(t);
204
- }, time);
205
- const screenshot = await page.screenshot({ type: 'png' });
206
- frames.push(new Uint8Array(screenshot));
207
- if (i % Math.max(1, Math.floor(fps / 2)) === 0 || i === totalFrames - 1) {
208
- writeProgress('Capturing', frames.length, totalWithCover);
209
- }
88
+ else {
89
+ throw new Error('No document found in input');
210
90
  }
211
- clearProgress();
212
- await browser.close();
213
- // ── Step 6: Encode to MP4 ───────────────────────────────────────
214
- const ffmpegPath = await detectFfmpeg();
215
- const exportOptions = {
91
+ console.error(`Rendering: ${fps} fps, quality: ${quality}, orientation: ${orientation}, captions: ${captions}`);
92
+ // ── Step 3: Render via programmatic API ─────────────────────────
93
+ const result2 = await renderDocToMp4(doc, container, {
94
+ outputPath,
216
95
  fps,
217
96
  quality: quality,
218
97
  orientation: orientation,
219
- width: dimensions.width,
220
- height: dimensions.height,
221
- onProgress: (percent, phase) => {
222
- writeProgress('Encoding', percent, 100, phase);
98
+ width: opts.width ? parseInt(opts.width, 10) : undefined,
99
+ height: opts.height ? parseInt(opts.height, 10) : undefined,
100
+ captionStyle,
101
+ coverPreRoll: 2,
102
+ onProgress: (phase, percent) => {
103
+ writeProgress(phase, percent, 100);
223
104
  },
224
- };
225
- if (ffmpegPath) {
226
- console.error(`Using native ffmpeg: ${ffmpegPath}`);
227
- const { framesToMp4Native } = await import('../util/nativeEncoder.js');
228
- await framesToMp4Native(ffmpegPath, frames, concatenatedAudio, outputPath, exportOptions);
229
- }
230
- else {
231
- throw new Error('ffmpeg is required but not found in PATH.\n' +
232
- 'Install it with:\n' +
233
- ' macOS: brew install ffmpeg\n' +
234
- ' Ubuntu: sudo apt install ffmpeg\n' +
235
- ' Windows: winget install ffmpeg');
236
- }
105
+ });
237
106
  clearProgress();
238
- console.error(` ✓ ${outputPath}`);
107
+ console.error(` ✓ ${outputPath} (${result2.duration.toFixed(1)}s, ${result2.frameCount} frames)`);
239
108
  console.error('Done.');
240
109
  }
241
110
  // ── Progress helpers ──────────────────────────────────────────────
@@ -1 +1 @@
1
- {"version":3,"file":"video.js","sourceRoot":"","sources":["../../src/commands/video.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"video.js","sourceRoot":"","sources":["../../src/commands/video.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ // src/util/nativeEncoder.ts
2
+ import { execFile } from "child_process";
3
+ import { writeFile, readFile, mkdir, rm } from "fs/promises";
4
+ import { join } from "path";
5
+ import { tmpdir } from "os";
6
+ import { randomBytes } from "crypto";
7
+ import { QUALITY_PRESETS, resolveDimensions } from "@bendyline/squisq-video";
8
+ async function framesToMp4Native(ffmpegPath, frames, audio, outputPath, options = {}) {
9
+ const fps = options.fps ?? 30;
10
+ const quality = options.quality ?? "normal";
11
+ const { width, height } = resolveDimensions(options);
12
+ const preset = QUALITY_PRESETS[quality];
13
+ const onProgress = options.onProgress;
14
+ if (frames.length === 0) {
15
+ throw new Error("No frames provided for encoding");
16
+ }
17
+ const tmpId = randomBytes(8).toString("hex");
18
+ const workDir = join(tmpdir(), `squisq-video-${tmpId}`);
19
+ await mkdir(workDir, { recursive: true });
20
+ try {
21
+ onProgress?.(0, "writing frames");
22
+ const padLen = String(frames.length).length;
23
+ for (let i = 0; i < frames.length; i++) {
24
+ const name = `frame-${String(i + 1).padStart(padLen, "0")}.png`;
25
+ await writeFile(join(workDir, name), frames[i]);
26
+ if (onProgress && i % 10 === 0) {
27
+ onProgress(Math.round(i / frames.length * 30), "writing frames");
28
+ }
29
+ }
30
+ let audioPath = null;
31
+ if (audio) {
32
+ audioPath = join(workDir, "audio-input");
33
+ await writeFile(audioPath, audio);
34
+ }
35
+ onProgress?.(30, "encoding");
36
+ const padPattern = join(workDir, `frame-%0${padLen}d.png`);
37
+ const args = ["-y", "-framerate", String(fps), "-i", padPattern];
38
+ if (audioPath) {
39
+ args.push("-i", audioPath);
40
+ }
41
+ args.push(
42
+ "-c:v",
43
+ "libx264",
44
+ "-preset",
45
+ preset.preset,
46
+ "-crf",
47
+ String(preset.crf),
48
+ "-pix_fmt",
49
+ "yuv420p",
50
+ "-vf",
51
+ `scale=${width}:${height}:force_original_aspect_ratio=decrease,pad=${width}:${height}:(ow-iw)/2:(oh-ih)/2`
52
+ );
53
+ if (audioPath) {
54
+ args.push("-c:a", "aac", "-b:a", "128k", "-shortest");
55
+ }
56
+ args.push(outputPath);
57
+ await new Promise((resolve, reject) => {
58
+ const proc = execFile(ffmpegPath, args, { timeout: 6e5 }, (err) => {
59
+ if (err) {
60
+ reject(new Error(`ffmpeg failed: ${err.message}`));
61
+ } else {
62
+ resolve();
63
+ }
64
+ });
65
+ proc.stderr?.on("data", () => {
66
+ });
67
+ });
68
+ onProgress?.(100, "done");
69
+ } finally {
70
+ await rm(workDir, { recursive: true, force: true });
71
+ }
72
+ }
73
+ async function framesToMp4NativeBytes(ffmpegPath, frames, audio, options = {}) {
74
+ const tmpId = randomBytes(8).toString("hex");
75
+ const tmpOutput = join(tmpdir(), `squisq-video-out-${tmpId}.mp4`);
76
+ try {
77
+ await framesToMp4Native(ffmpegPath, frames, audio, tmpOutput, options);
78
+ const data = await readFile(tmpOutput);
79
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
80
+ } finally {
81
+ await rm(tmpOutput, { force: true });
82
+ }
83
+ }
84
+ export {
85
+ framesToMp4Native,
86
+ framesToMp4NativeBytes
87
+ };
88
+ //# sourceMappingURL=nativeEncoder-MWHOONST.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/util/nativeEncoder.ts"],"sourcesContent":["/**\n * Native FFmpeg Encoder\n *\n * Encodes PNG frames to MP4 using a locally installed ffmpeg binary.\n * Writes frames to a temporary directory, invokes ffmpeg as a child process,\n * and reads the resulting MP4.\n *\n * This is the fast path — used when native ffmpeg is detected on the system.\n * Falls back to the WASM encoder (in @bendyline/squisq-video) when unavailable.\n */\n\nimport { execFile } from 'node:child_process';\nimport { writeFile, readFile, mkdir, rm } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { randomBytes } from 'node:crypto';\n\nimport type { VideoExportOptions } from '@bendyline/squisq-video';\nimport { QUALITY_PRESETS, resolveDimensions } from '@bendyline/squisq-video';\n\n/**\n * Encode frame PNGs to MP4 using native ffmpeg.\n *\n * @param ffmpegPath - Absolute path to the ffmpeg binary\n * @param frames - Array of PNG image bytes (one per frame)\n * @param audio - Optional audio file bytes to mux\n * @param outputPath - Where to write the final MP4\n * @param options - Encoding options (fps, quality, dimensions, progress)\n */\nexport async function framesToMp4Native(\n ffmpegPath: string,\n frames: Uint8Array[],\n audio: Uint8Array | null,\n outputPath: string,\n options: VideoExportOptions = {},\n): Promise<void> {\n const fps = options.fps ?? 30;\n const quality = options.quality ?? 'normal';\n const { width, height } = resolveDimensions(options);\n const preset = QUALITY_PRESETS[quality];\n const onProgress = options.onProgress;\n\n if (frames.length === 0) {\n throw new Error('No frames provided for encoding');\n }\n\n // Create a temp working directory\n const tmpId = randomBytes(8).toString('hex');\n const workDir = join(tmpdir(), `squisq-video-${tmpId}`);\n await mkdir(workDir, { recursive: true });\n\n try {\n onProgress?.(0, 'writing frames');\n\n // Write frame PNGs to temp directory\n const padLen = String(frames.length).length;\n for (let i = 0; i < frames.length; i++) {\n const name = `frame-${String(i + 1).padStart(padLen, '0')}.png`;\n await writeFile(join(workDir, name), frames[i]);\n\n if (onProgress && i % 10 === 0) {\n onProgress(Math.round((i / frames.length) * 30), 'writing frames');\n }\n }\n\n // Write audio if provided\n let audioPath: string | null = null;\n if (audio) {\n audioPath = join(workDir, 'audio-input');\n await writeFile(audioPath, audio);\n }\n\n onProgress?.(30, 'encoding');\n\n // Build ffmpeg arguments\n const padPattern = join(workDir, `frame-%0${padLen}d.png`);\n const args = ['-y', '-framerate', String(fps), '-i', padPattern];\n\n if (audioPath) {\n args.push('-i', audioPath);\n }\n\n args.push(\n '-c:v',\n 'libx264',\n '-preset',\n preset.preset,\n '-crf',\n String(preset.crf),\n '-pix_fmt',\n 'yuv420p',\n '-vf',\n `scale=${width}:${height}:force_original_aspect_ratio=decrease,pad=${width}:${height}:(ow-iw)/2:(oh-ih)/2`,\n );\n\n if (audioPath) {\n args.push('-c:a', 'aac', '-b:a', '128k', '-shortest');\n }\n\n args.push(outputPath);\n\n // Run ffmpeg\n await new Promise<void>((resolve, reject) => {\n const proc = execFile(ffmpegPath, args, { timeout: 600_000 }, (err) => {\n if (err) {\n reject(new Error(`ffmpeg failed: ${err.message}`));\n } else {\n resolve();\n }\n });\n\n // ffmpeg writes progress to stderr\n proc.stderr?.on('data', () => {\n // Could parse ffmpeg progress output here in the future\n });\n });\n\n onProgress?.(100, 'done');\n } finally {\n // Clean up temp directory\n await rm(workDir, { recursive: true, force: true });\n }\n}\n\n/**\n * Encode frames using native ffmpeg and return the MP4 bytes (instead of writing to disk).\n * Useful when the caller needs the bytes in memory.\n */\nexport async function framesToMp4NativeBytes(\n ffmpegPath: string,\n frames: Uint8Array[],\n audio: Uint8Array | null,\n options: VideoExportOptions = {},\n): Promise<Uint8Array> {\n const tmpId = randomBytes(8).toString('hex');\n const tmpOutput = join(tmpdir(), `squisq-video-out-${tmpId}.mp4`);\n\n try {\n await framesToMp4Native(ffmpegPath, frames, audio, tmpOutput, options);\n const data = await readFile(tmpOutput);\n return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n } finally {\n await rm(tmpOutput, { force: true });\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,19 +1,31 @@
1
1
  /**
2
2
  * readInput
3
3
  *
4
- * Unified input reader for the CLI. Accepts a path to a .md file,
5
- * .zip/.dbk container, or a folder and returns a MemoryContentContainer
6
- * (virtual file system) plus the parsed MarkdownDocument.
4
+ * Unified input reader for the CLI. Accepts a path to a .md file, .json file
5
+ * (Doc schema), .zip/.dbk container, or a folder and returns a MemoryContentContainer
6
+ * (virtual file system) plus either the parsed MarkdownDocument or a pre-built Doc.
7
+ *
8
+ * When a .json file or a container/folder containing doc.json is provided, the
9
+ * Doc is returned directly and markdownDoc will be null. Callers should check
10
+ * result.doc first; when present, skip markdownToDoc() and use it directly.
7
11
  */
8
12
  import type { MarkdownDocument } from '@bendyline/squisq/markdown';
13
+ import type { Doc } from '@bendyline/squisq/schemas';
9
14
  import { MemoryContentContainer } from '@bendyline/squisq/storage';
10
15
  export interface ReadInputResult {
11
16
  container: MemoryContentContainer;
12
- markdownDoc: MarkdownDocument;
17
+ /** Parsed markdown document. Null when input is a Doc JSON file. */
18
+ markdownDoc: MarkdownDocument | null;
19
+ /** Pre-built Doc from JSON input. Present when input is .json or contains doc.json. */
20
+ doc?: Doc;
13
21
  }
14
22
  /**
15
- * Read input from a file path (markdown, ZIP/DBK container, or folder)
16
- * and return a populated ContentContainer + parsed MarkdownDocument.
23
+ * Read input from a file path (markdown, JSON Doc, ZIP/DBK container, or folder)
24
+ * and return a populated ContentContainer + parsed MarkdownDocument or Doc.
25
+ *
26
+ * When the input is a .json file (or a container/folder containing doc.json),
27
+ * the result will have `doc` populated and `markdownDoc` set to null.
28
+ * Otherwise, `markdownDoc` is populated and `doc` is undefined.
17
29
  */
18
30
  export declare function readInput(inputPath: string): Promise<ReadInputResult>;
19
31
  //# sourceMappingURL=readInput.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"readInput.d.ts","sourceRoot":"","sources":["../../src/util/readInput.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAGnE,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,sBAAsB,CAAC;IAClC,WAAW,EAAE,gBAAgB,CAAC;CAC/B;AA2CD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAc3E"}
1
+ {"version":3,"file":"readInput.d.ts","sourceRoot":"","sources":["../../src/util/readInput.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAGnE,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,sBAAsB,CAAC;IAClC,oEAAoE;IACpE,WAAW,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACrC,uFAAuF;IACvF,GAAG,CAAC,EAAE,GAAG,CAAC;CACX;AA2CD;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAkB3E"}
@@ -1,9 +1,13 @@
1
1
  /**
2
2
  * readInput
3
3
  *
4
- * Unified input reader for the CLI. Accepts a path to a .md file,
5
- * .zip/.dbk container, or a folder and returns a MemoryContentContainer
6
- * (virtual file system) plus the parsed MarkdownDocument.
4
+ * Unified input reader for the CLI. Accepts a path to a .md file, .json file
5
+ * (Doc schema), .zip/.dbk container, or a folder and returns a MemoryContentContainer
6
+ * (virtual file system) plus either the parsed MarkdownDocument or a pre-built Doc.
7
+ *
8
+ * When a .json file or a container/folder containing doc.json is provided, the
9
+ * Doc is returned directly and markdownDoc will be null. Callers should check
10
+ * result.doc first; when present, skip markdownToDoc() and use it directly.
7
11
  */
8
12
  import { readFile, readdir, stat } from 'node:fs/promises';
9
13
  import { join, extname } from 'node:path';
@@ -48,8 +52,12 @@ async function walkDir(root, prefix = '') {
48
52
  return paths;
49
53
  }
50
54
  /**
51
- * Read input from a file path (markdown, ZIP/DBK container, or folder)
52
- * and return a populated ContentContainer + parsed MarkdownDocument.
55
+ * Read input from a file path (markdown, JSON Doc, ZIP/DBK container, or folder)
56
+ * and return a populated ContentContainer + parsed MarkdownDocument or Doc.
57
+ *
58
+ * When the input is a .json file (or a container/folder containing doc.json),
59
+ * the result will have `doc` populated and `markdownDoc` set to null.
60
+ * Otherwise, `markdownDoc` is populated and `doc` is undefined.
53
61
  */
54
62
  export async function readInput(inputPath) {
55
63
  const info = await stat(inputPath);
@@ -60,6 +68,9 @@ export async function readInput(inputPath) {
60
68
  if (ext === '.zip' || ext === '.dbk') {
61
69
  return readContainer(inputPath);
62
70
  }
71
+ if (ext === '.json') {
72
+ return readDocJsonFile(inputPath);
73
+ }
63
74
  // Default: treat as a markdown file
64
75
  return readMarkdownFile(inputPath);
65
76
  }
@@ -70,12 +81,36 @@ async function readMarkdownFile(filePath) {
70
81
  const markdownDoc = parseMarkdown(content);
71
82
  return { container, markdownDoc };
72
83
  }
84
+ /**
85
+ * Read a standalone Doc JSON file. The container is empty (no media bundled);
86
+ * callers should populate it or set basePath for media resolution.
87
+ */
88
+ async function readDocJsonFile(filePath) {
89
+ const content = await readFile(filePath, 'utf-8');
90
+ const doc = JSON.parse(content);
91
+ const container = new MemoryContentContainer();
92
+ return { container, markdownDoc: null, doc };
93
+ }
94
+ /**
95
+ * Known filenames for Doc JSON inside containers and folders.
96
+ * Checked in priority order before falling back to markdown discovery.
97
+ */
98
+ const DOC_JSON_NAMES = ['doc.json', 'story.json'];
73
99
  async function readContainer(filePath) {
74
100
  const data = await readFile(filePath);
75
101
  const container = await zipToContainer(data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength));
102
+ // Check for Doc JSON inside the container first
103
+ for (const name of DOC_JSON_NAMES) {
104
+ const jsonData = await container.readFile(name);
105
+ if (jsonData) {
106
+ const decoder = new TextDecoder();
107
+ const doc = JSON.parse(decoder.decode(jsonData));
108
+ return { container, markdownDoc: null, doc };
109
+ }
110
+ }
76
111
  const markdown = await container.readDocument();
77
112
  if (!markdown) {
78
- throw new Error(`No markdown document found in container: ${filePath}`);
113
+ throw new Error(`No markdown document or doc.json found in container: ${filePath}`);
79
114
  }
80
115
  const markdownDoc = parseMarkdown(markdown);
81
116
  return { container, markdownDoc };
@@ -88,9 +123,18 @@ async function readFolder(dirPath) {
88
123
  const data = await readFile(absPath);
89
124
  await container.writeFile(relPath, new Uint8Array(data.buffer, data.byteOffset, data.byteLength), mimeFromExt(relPath));
90
125
  }
126
+ // Check for Doc JSON inside the folder first
127
+ for (const name of DOC_JSON_NAMES) {
128
+ const jsonData = await container.readFile(name);
129
+ if (jsonData) {
130
+ const decoder = new TextDecoder();
131
+ const doc = JSON.parse(decoder.decode(jsonData));
132
+ return { container, markdownDoc: null, doc };
133
+ }
134
+ }
91
135
  const markdown = await container.readDocument();
92
136
  if (!markdown) {
93
- throw new Error(`No markdown document found in folder: ${dirPath}`);
137
+ throw new Error(`No markdown document or doc.json found in folder: ${dirPath}`);
94
138
  }
95
139
  const markdownDoc = parseMarkdown(markdown);
96
140
  return { container, markdownDoc };
@@ -1 +1 @@
1
- {"version":3,"file":"readInput.js","sourceRoot":"","sources":["../../src/util/readInput.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAE3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAOrE,2DAA2D;AAC3D,MAAM,UAAU,GAA2B;IACzC,KAAK,EAAE,eAAe;IACtB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,kBAAkB;IAC3B,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;CACtB,CAAC;AAEF,SAAS,WAAW,CAAC,QAAgB;IACnC,OAAO,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,0BAA0B,CAAC;AACnF,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,OAAO,CAAC,IAAY,EAAE,MAAM,GAAG,EAAE;IAC9C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;QAChE,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QAClE,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,SAAiB;IAC/C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC;IAEnC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACvB,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;IAC7C,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACrC,OAAO,aAAa,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IAED,oCAAoC;IACpC,OAAO,gBAAgB,CAAC,SAAS,CAAC,CAAC;AACrC,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,QAAgB;IAC9C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,IAAI,sBAAsB,EAAE,CAAC;IAC/C,MAAM,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IAC3C,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;AACpC,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,QAAgB;IAC3C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,MAAM,cAAc,CACpC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAgB,CACrF,CAAC;IAEF,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,YAAY,EAAE,CAAC;IAChD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,4CAA4C,QAAQ,EAAE,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,WAAW,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC5C,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;AACpC,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,OAAe;IACvC,MAAM,SAAS,GAAG,IAAI,sBAAsB,EAAE,CAAC;IAC/C,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAErC,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,SAAS,CAAC,SAAS,CACvB,OAAO,EACP,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,EAC7D,WAAW,CAAC,OAAO,CAAC,CACrB,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,YAAY,EAAE,CAAC;IAChD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,yCAAyC,OAAO,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,WAAW,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC5C,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;AACpC,CAAC"}
1
+ {"version":3,"file":"readInput.js","sourceRoot":"","sources":["../../src/util/readInput.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bendyline/squisq-cli",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Squisq CLI — convert markdown documents to DOCX, PDF, HTML, and more",
5
5
  "license": "MIT",
6
6
  "author": "Bendyline",
@@ -28,6 +28,18 @@
28
28
  },
29
29
  "main": "./dist/index.js",
30
30
  "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "import": "./dist/index.js",
35
+ "default": "./dist/index.js"
36
+ },
37
+ "./api": {
38
+ "types": "./dist/api.d.ts",
39
+ "import": "./dist/api.js",
40
+ "default": "./dist/api.js"
41
+ }
42
+ },
31
43
  "files": [
32
44
  "dist"
33
45
  ],
@@ -37,10 +49,10 @@
37
49
  "test": "mocha"
38
50
  },
39
51
  "dependencies": {
40
- "@bendyline/squisq": "1.1.1",
41
- "@bendyline/squisq-formats": "1.1.1",
42
- "@bendyline/squisq-react": "1.0.3",
43
- "@bendyline/squisq-video": "1.0.1",
52
+ "@bendyline/squisq": "1.2.0",
53
+ "@bendyline/squisq-formats": "1.2.0",
54
+ "@bendyline/squisq-react": "1.1.0",
55
+ "@bendyline/squisq-video": "1.0.2",
44
56
  "commander": "^12.0.0",
45
57
  "playwright-core": "^1.48.0"
46
58
  },