cbrowser 18.70.0 → 18.71.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/dist/browser.d.ts +32 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +46 -2
- package/dist/browser.js.map +1 -1
- package/dist/cli.js +1465 -24
- package/dist/cli.js.map +1 -1
- package/dist/cognitive/index.d.ts +10 -0
- package/dist/cognitive/index.d.ts.map +1 -1
- package/dist/cognitive/index.js +8 -0
- package/dist/cognitive/index.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +151 -3
- package/dist/daemon.js.map +1 -1
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +67 -0
- package/dist/mcp-server.js.map +1 -1
- package/dist/mcp-tools/base/capture-tools.d.ts +189 -0
- package/dist/mcp-tools/base/capture-tools.d.ts.map +1 -0
- package/dist/mcp-tools/base/capture-tools.js +667 -0
- package/dist/mcp-tools/base/capture-tools.js.map +1 -0
- package/dist/mcp-tools/base/gif-tools.d.ts +19 -0
- package/dist/mcp-tools/base/gif-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/gif-tools.js +45 -27
- package/dist/mcp-tools/base/gif-tools.js.map +1 -1
- package/dist/mcp-tools/base/index.d.ts +2 -1
- package/dist/mcp-tools/base/index.d.ts.map +1 -1
- package/dist/mcp-tools/base/index.js +5 -1
- package/dist/mcp-tools/base/index.js.map +1 -1
- package/dist/mcp-tools/tool-categories.d.ts.map +1 -1
- package/dist/mcp-tools/tool-categories.js +11 -0
- package/dist/mcp-tools/tool-categories.js.map +1 -1
- package/dist/recording/auto-capture.d.ts +72 -0
- package/dist/recording/auto-capture.d.ts.map +1 -0
- package/dist/recording/auto-capture.js +155 -0
- package/dist/recording/auto-capture.js.map +1 -0
- package/dist/recording/contact-sheet.d.ts +65 -0
- package/dist/recording/contact-sheet.d.ts.map +1 -0
- package/dist/recording/contact-sheet.js +204 -0
- package/dist/recording/contact-sheet.js.map +1 -0
- package/dist/recording/encoders.d.ts +101 -0
- package/dist/recording/encoders.d.ts.map +1 -0
- package/dist/recording/encoders.js +304 -0
- package/dist/recording/encoders.js.map +1 -0
- package/dist/recording/engine.d.ts +263 -0
- package/dist/recording/engine.d.ts.map +1 -0
- package/dist/recording/engine.js +890 -0
- package/dist/recording/engine.js.map +1 -0
- package/dist/recording/ssim.d.ts +35 -0
- package/dist/recording/ssim.d.ts.map +1 -0
- package/dist/recording/ssim.js +113 -0
- package/dist/recording/ssim.js.map +1 -0
- package/dist/recording/timing.d.ts +124 -0
- package/dist/recording/timing.d.ts.map +1 -0
- package/dist/recording/timing.js +251 -0
- package/dist/recording/timing.js.map +1 -0
- package/dist/recording/types.d.ts +213 -0
- package/dist/recording/types.d.ts.map +1 -0
- package/dist/recording/types.js +171 -0
- package/dist/recording/types.js.map +1 -0
- package/dist/testing/nl-test-suite.d.ts +10 -0
- package/dist/testing/nl-test-suite.d.ts.map +1 -1
- package/dist/testing/nl-test-suite.js +13 -1
- package/dist/testing/nl-test-suite.js.map +1 -1
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recording encoders — turn a directory of captured frames into an animated
|
|
3
|
+
* GIF, an animated WebP, or a video.
|
|
4
|
+
*
|
|
5
|
+
* Two hard constraints shape this module:
|
|
6
|
+
*
|
|
7
|
+
* 1. Frames arrive from a CDP screencast, so they are JPEGs of *differing*
|
|
8
|
+
* byte length and occasionally differing pixel dimensions (a viewport
|
|
9
|
+
* change mid-capture re-sizes the stream). Every frame is therefore
|
|
10
|
+
* normalised to one locked output size before encoding. Do not "optimise"
|
|
11
|
+
* this into raw-buffer stacking — sharp's animated encoders need a joined
|
|
12
|
+
* input, and a stacked raw buffer silently produces a single tall page.
|
|
13
|
+
*
|
|
14
|
+
* 2. Capture is event-driven, so frames are *not* evenly spaced. Per-frame
|
|
15
|
+
* delays come from the caller (derived from frame timestamps), never from
|
|
16
|
+
* a constant cadence.
|
|
17
|
+
*
|
|
18
|
+
* @since v18.70.0
|
|
19
|
+
*/
|
|
20
|
+
import { spawn } from "node:child_process";
|
|
21
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
22
|
+
import { homedir } from "node:os";
|
|
23
|
+
import { join } from "node:path";
|
|
24
|
+
import sharp from "sharp";
|
|
25
|
+
/**
|
|
26
|
+
* Thrown when an encoder's external dependency is missing. Callers surface the
|
|
27
|
+
* message verbatim and exit non-zero — recording itself has already succeeded
|
|
28
|
+
* at this point, so this must never be swallowed into a silent partial result.
|
|
29
|
+
*/
|
|
30
|
+
export class MissingEncoderError extends Error {
|
|
31
|
+
constructor(message) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = "MissingEncoderError";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// =========================================================================
|
|
37
|
+
// Frame normalisation
|
|
38
|
+
// =========================================================================
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the locked output dimensions from the first frame, honouring any
|
|
41
|
+
* caller override and forcing even numbers (video encoders reject odd sizes).
|
|
42
|
+
*/
|
|
43
|
+
async function lockDimensions(firstFrame, options, requireEven = false) {
|
|
44
|
+
const meta = await sharp(firstFrame).metadata();
|
|
45
|
+
const firstCrop = options.crops?.[0];
|
|
46
|
+
const baseWidth = options.width ?? firstCrop?.width ?? meta.width;
|
|
47
|
+
const baseHeight = options.height ?? firstCrop?.height ?? meta.height;
|
|
48
|
+
if (!baseWidth || !baseHeight) {
|
|
49
|
+
throw new Error(`Cannot determine frame dimensions from ${firstFrame}`);
|
|
50
|
+
}
|
|
51
|
+
const scale = options.scale ?? 1;
|
|
52
|
+
if (scale <= 0 || scale > 1) {
|
|
53
|
+
throw new Error(`Invalid scale ${scale} - must be > 0 and <= 1`);
|
|
54
|
+
}
|
|
55
|
+
const width = Math.max(1, Math.round(baseWidth * scale));
|
|
56
|
+
const height = Math.max(1, Math.round(baseHeight * scale));
|
|
57
|
+
// Only the video path forces even dimensions - yuv420p subsampling requires
|
|
58
|
+
// them. Applying that rounding to GIF/WebP made a 393px-wide iPhone capture
|
|
59
|
+
// emit a 394px artifact, and a one-pixel drift from the declared viewport is
|
|
60
|
+
// exactly what breaks a pixel-exact visual baseline for no real reason.
|
|
61
|
+
if (!requireEven)
|
|
62
|
+
return { width, height };
|
|
63
|
+
return {
|
|
64
|
+
width: Math.max(2, Math.round(width / 2) * 2),
|
|
65
|
+
height: Math.max(2, Math.round(height / 2) * 2),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Normalise one frame to the locked size. `fit: "contain"` preserves aspect
|
|
70
|
+
* ratio and letterboxes rather than distorting - a frame that arrived at a
|
|
71
|
+
* different viewport size should look small, not stretched.
|
|
72
|
+
*/
|
|
73
|
+
async function normaliseFrame(framePath, width, height, crop) {
|
|
74
|
+
let pipeline = sharp(framePath);
|
|
75
|
+
if (crop) {
|
|
76
|
+
// The crop is trimmed to the frame it is being applied to: an element that
|
|
77
|
+
// drifts partly off-screen still yields the visible part rather than
|
|
78
|
+
// failing the whole encode on a sharp extract_area error.
|
|
79
|
+
const meta = await pipeline.metadata();
|
|
80
|
+
const frameWidth = meta.width ?? width;
|
|
81
|
+
const frameHeight = meta.height ?? height;
|
|
82
|
+
const left = Math.max(0, Math.min(Math.round(crop.x), frameWidth - 1));
|
|
83
|
+
const top = Math.max(0, Math.min(Math.round(crop.y), frameHeight - 1));
|
|
84
|
+
const extractWidth = Math.max(1, Math.min(Math.round(crop.width), frameWidth - left));
|
|
85
|
+
const extractHeight = Math.max(1, Math.min(Math.round(crop.height), frameHeight - top));
|
|
86
|
+
pipeline = pipeline.extract({ left, top, width: extractWidth, height: extractHeight });
|
|
87
|
+
}
|
|
88
|
+
return pipeline
|
|
89
|
+
.resize(width, height, {
|
|
90
|
+
fit: "contain",
|
|
91
|
+
background: { r: 0, g: 0, b: 0, alpha: 1 },
|
|
92
|
+
})
|
|
93
|
+
.png()
|
|
94
|
+
.toBuffer();
|
|
95
|
+
}
|
|
96
|
+
/** Validate the frames/delays pairing shared by every animated encoder. */
|
|
97
|
+
function assertEncodable(frames, delays, label) {
|
|
98
|
+
if (frames.length === 0) {
|
|
99
|
+
throw new Error(`Cannot encode ${label}: no frames`);
|
|
100
|
+
}
|
|
101
|
+
if (delays.length !== frames.length) {
|
|
102
|
+
throw new Error(`Cannot encode ${label}: ${frames.length} frames but ${delays.length} delays - ` +
|
|
103
|
+
`delays must be derived per-frame from capture timestamps`);
|
|
104
|
+
}
|
|
105
|
+
const missing = frames.filter((f) => !existsSync(f));
|
|
106
|
+
if (missing.length > 0) {
|
|
107
|
+
throw new Error(`Cannot encode ${label}: ${missing.length} frame file(s) missing, first: ${missing[0]}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// =========================================================================
|
|
111
|
+
// Animated image encoders (sharp)
|
|
112
|
+
// =========================================================================
|
|
113
|
+
/**
|
|
114
|
+
* Encode frames into an animated GIF with per-frame delays.
|
|
115
|
+
*
|
|
116
|
+
* A single-frame recording (a static page that emitted no screencast events)
|
|
117
|
+
* encodes to a one-page GIF rather than failing.
|
|
118
|
+
*/
|
|
119
|
+
export async function encodeGif(frames, delays, outPath, options = {}) {
|
|
120
|
+
assertEncodable(frames, delays, "GIF");
|
|
121
|
+
const { width, height } = await lockDimensions(frames[0], options);
|
|
122
|
+
const normalised = await Promise.all(frames.map((f, i) => normaliseFrame(f, width, height, options.crops?.[i])));
|
|
123
|
+
await sharp(normalised, { join: { animated: true } })
|
|
124
|
+
.gif({ delay: delays.map((d) => Math.max(10, Math.round(d))), loop: options.loop ?? 0 })
|
|
125
|
+
.toFile(outPath);
|
|
126
|
+
return { path: outPath, bytes: statSync(outPath).size, frames: frames.length, width, height };
|
|
127
|
+
}
|
|
128
|
+
/** Encode frames into an animated WebP with per-frame delays. */
|
|
129
|
+
export async function encodeWebp(frames, delays, outPath, options = {}) {
|
|
130
|
+
assertEncodable(frames, delays, "WebP");
|
|
131
|
+
const { width, height } = await lockDimensions(frames[0], options);
|
|
132
|
+
const normalised = await Promise.all(frames.map((f, i) => normaliseFrame(f, width, height, options.crops?.[i])));
|
|
133
|
+
await sharp(normalised, { join: { animated: true } })
|
|
134
|
+
.webp({ delay: delays.map((d) => Math.max(10, Math.round(d))), loop: options.loop ?? 0 })
|
|
135
|
+
.toFile(outPath);
|
|
136
|
+
return { path: outPath, bytes: statSync(outPath).size, frames: frames.length, width, height };
|
|
137
|
+
}
|
|
138
|
+
// =========================================================================
|
|
139
|
+
// ffmpeg resolution
|
|
140
|
+
// =========================================================================
|
|
141
|
+
/**
|
|
142
|
+
* Locate Playwright's bundled ffmpeg. A bare `ffmpeg` is never invoked: the
|
|
143
|
+
* PATH binary is not guaranteed to exist on deploy targets, and silently
|
|
144
|
+
* picking up an arbitrary system build makes output non-reproducible.
|
|
145
|
+
*
|
|
146
|
+
* Probe order: $PLAYWRIGHT_BROWSERS_PATH, then the per-user cache directories.
|
|
147
|
+
*/
|
|
148
|
+
export function resolveFfmpegPath() {
|
|
149
|
+
const override = process.env.CBROWSER_FFMPEG_PATH;
|
|
150
|
+
if (override && existsSync(override))
|
|
151
|
+
return override;
|
|
152
|
+
const roots = [];
|
|
153
|
+
if (process.env.PLAYWRIGHT_BROWSERS_PATH)
|
|
154
|
+
roots.push(process.env.PLAYWRIGHT_BROWSERS_PATH);
|
|
155
|
+
roots.push(join(homedir(), ".cache", "ms-playwright"));
|
|
156
|
+
for (const root of roots) {
|
|
157
|
+
if (!existsSync(root))
|
|
158
|
+
continue;
|
|
159
|
+
let entries;
|
|
160
|
+
try {
|
|
161
|
+
entries = readdirSync(root);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
for (const entry of entries.filter((e) => e.startsWith("ffmpeg-")).sort().reverse()) {
|
|
167
|
+
for (const bin of ["ffmpeg-linux", "ffmpeg-mac", "ffmpeg-win64.exe"]) {
|
|
168
|
+
const candidate = join(root, entry, bin);
|
|
169
|
+
if (existsSync(candidate))
|
|
170
|
+
return candidate;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
/** Run ffmpeg and collect stdout+stderr. */
|
|
177
|
+
function runFfmpeg(bin, args, stdin) {
|
|
178
|
+
return new Promise((resolve, reject) => {
|
|
179
|
+
const proc = spawn(bin, args, { stdio: ["pipe", "pipe", "pipe"] });
|
|
180
|
+
let output = "";
|
|
181
|
+
proc.stdout.on("data", (d) => { output += d.toString(); });
|
|
182
|
+
proc.stderr.on("data", (d) => { output += d.toString(); });
|
|
183
|
+
proc.on("error", reject);
|
|
184
|
+
proc.on("close", (code) => resolve({ code: code ?? -1, output }));
|
|
185
|
+
if (stdin) {
|
|
186
|
+
proc.stdin.on("error", () => { });
|
|
187
|
+
proc.stdin.end(stdin);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
proc.stdin.end();
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
/** Cached capability probe of a resolved ffmpeg binary. */
|
|
195
|
+
const capabilityCache = new Map();
|
|
196
|
+
async function ffmpegCapabilities(bin) {
|
|
197
|
+
const cached = capabilityCache.get(bin);
|
|
198
|
+
if (cached)
|
|
199
|
+
return cached;
|
|
200
|
+
const parse = (text) => {
|
|
201
|
+
const names = new Set();
|
|
202
|
+
for (const line of text.split("\n")) {
|
|
203
|
+
const match = line.match(/^\s*[A-Z. ]{2,6}\s+(\S+)/);
|
|
204
|
+
if (match)
|
|
205
|
+
names.add(match[1]);
|
|
206
|
+
}
|
|
207
|
+
return names;
|
|
208
|
+
};
|
|
209
|
+
const [muxers, encoders] = await Promise.all([
|
|
210
|
+
runFfmpeg(bin, ["-hide_banner", "-muxers"]),
|
|
211
|
+
runFfmpeg(bin, ["-hide_banner", "-encoders"]),
|
|
212
|
+
]);
|
|
213
|
+
const caps = { muxers: parse(muxers.output), encoders: parse(encoders.output) };
|
|
214
|
+
capabilityCache.set(bin, caps);
|
|
215
|
+
return caps;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Resample variable-delay frames onto a constant-rate timeline by repeating
|
|
219
|
+
* each frame for as long as it was on screen. Video containers assume a fixed
|
|
220
|
+
* frame rate; repeating is how event-driven capture maps onto one without
|
|
221
|
+
* inventing content that was never displayed.
|
|
222
|
+
*/
|
|
223
|
+
export function resampleToConstantRate(frames, delays, fps) {
|
|
224
|
+
const frameMs = 1000 / fps;
|
|
225
|
+
const timeline = [];
|
|
226
|
+
for (let i = 0; i < frames.length; i++) {
|
|
227
|
+
const repeats = Math.max(1, Math.round((delays[i] ?? frameMs) / frameMs));
|
|
228
|
+
for (let r = 0; r < repeats; r++)
|
|
229
|
+
timeline.push(frames[i]);
|
|
230
|
+
}
|
|
231
|
+
return timeline;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Encode frames into a video via an ffmpeg-family binary.
|
|
235
|
+
*
|
|
236
|
+
* `container` selects the muxer/encoder pair. Playwright's bundled ffmpeg is a
|
|
237
|
+
* stripped build that ships only the WebM muxer and the libvpx (VP8) encoder,
|
|
238
|
+
* so "webm" works out of the box and "mp4" requires a fuller ffmpeg.
|
|
239
|
+
*/
|
|
240
|
+
async function encodeVideo(frames, delays, outPath, container, options = {}) {
|
|
241
|
+
assertEncodable(frames, delays, container.toUpperCase());
|
|
242
|
+
const bin = resolveFfmpegPath();
|
|
243
|
+
if (!bin) {
|
|
244
|
+
throw new MissingEncoderError(`Cannot encode ${container.toUpperCase()}: no ffmpeg binary found. ` +
|
|
245
|
+
`Looked for Playwright's bundled ffmpeg under $PLAYWRIGHT_BROWSERS_PATH and ` +
|
|
246
|
+
`${join(homedir(), ".cache", "ms-playwright")}/ffmpeg-*/. ` +
|
|
247
|
+
`Install it with 'npx playwright install ffmpeg', or re-run with --format gif,webp.`);
|
|
248
|
+
}
|
|
249
|
+
const caps = await ffmpegCapabilities(bin);
|
|
250
|
+
const wanted = container === "webm"
|
|
251
|
+
? { muxer: "webm", encoders: ["libvpx", "libvpx-vp9"] }
|
|
252
|
+
: { muxer: "mp4", encoders: ["libx264", "libopenh264", "h264_videotoolbox", "mpeg4"] };
|
|
253
|
+
const encoder = wanted.encoders.find((e) => caps.encoders.has(e));
|
|
254
|
+
if (!caps.muxers.has(wanted.muxer) || !encoder) {
|
|
255
|
+
const missing = [
|
|
256
|
+
!caps.muxers.has(wanted.muxer) ? `muxer '${wanted.muxer}'` : null,
|
|
257
|
+
!encoder ? `video encoder (need one of: ${wanted.encoders.join(", ")})` : null,
|
|
258
|
+
].filter(Boolean).join(" and ");
|
|
259
|
+
throw new MissingEncoderError(`Cannot encode ${container.toUpperCase()}: ${bin} is missing ${missing}. ` +
|
|
260
|
+
`Playwright's bundled ffmpeg is a stripped build (WebM/VP8 only). ` +
|
|
261
|
+
`Install a full ffmpeg and set CBROWSER_FFMPEG_PATH, or re-run with --format ${container === "mp4" ? "webm" : "gif"}.`);
|
|
262
|
+
}
|
|
263
|
+
const { width, height } = await lockDimensions(frames[0], options, true);
|
|
264
|
+
const fps = options.fps ?? 10;
|
|
265
|
+
const timeline = resampleToConstantRate(frames, delays, fps);
|
|
266
|
+
const cropTimeline = options.crops
|
|
267
|
+
? resampleToConstantRate(options.crops.map((_, i) => String(i)), delays, fps)
|
|
268
|
+
.map((i) => options.crops[Number(i)])
|
|
269
|
+
: undefined;
|
|
270
|
+
// Frames are normalised to identical JPEG dimensions and concatenated into
|
|
271
|
+
// one mjpeg stream; the stripped build has only the image2pipe demuxer, and
|
|
272
|
+
// it needs the decoder named explicitly when reading from a pipe.
|
|
273
|
+
const jpegs = await Promise.all(timeline.map(async (f, i) => sharp(await normaliseFrame(f, width, height, cropTimeline?.[i]))
|
|
274
|
+
.jpeg({ quality: 90 })
|
|
275
|
+
.toBuffer()));
|
|
276
|
+
const args = [
|
|
277
|
+
"-hide_banner", "-loglevel", "error", "-y",
|
|
278
|
+
"-f", "image2pipe", "-c:v", "mjpeg", "-framerate", String(fps), "-i", "pipe:0",
|
|
279
|
+
"-c:v", encoder,
|
|
280
|
+
"-pix_fmt", "yuv420p",
|
|
281
|
+
"-an",
|
|
282
|
+
outPath,
|
|
283
|
+
];
|
|
284
|
+
const { code, output } = await runFfmpeg(bin, args, Buffer.concat(jpegs));
|
|
285
|
+
if (code !== 0 || !existsSync(outPath)) {
|
|
286
|
+
throw new Error(`ffmpeg failed encoding ${container} (exit ${code}): ${output.trim() || "no output"}`);
|
|
287
|
+
}
|
|
288
|
+
return { path: outPath, bytes: statSync(outPath).size, frames: timeline.length, width, height };
|
|
289
|
+
}
|
|
290
|
+
/** Encode frames into a WebM/VP8 video. Works with Playwright's bundled ffmpeg. */
|
|
291
|
+
export async function encodeWebm(frames, delays, outPath, options = {}) {
|
|
292
|
+
return encodeVideo(frames, delays, outPath, "webm", options);
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Encode frames into an MP4.
|
|
296
|
+
*
|
|
297
|
+
* Requires an ffmpeg with the mp4 muxer and an H.264-family encoder. Playwright's
|
|
298
|
+
* bundled binary has neither, so this throws {@link MissingEncoderError} unless a
|
|
299
|
+
* fuller ffmpeg is installed.
|
|
300
|
+
*/
|
|
301
|
+
export async function encodeMp4(frames, delays, outPath, options = {}) {
|
|
302
|
+
return encodeVideo(frames, delays, outPath, "mp4", options);
|
|
303
|
+
}
|
|
304
|
+
//# sourceMappingURL=encoders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encoders.js","sourceRoot":"","sources":["../../src/recording/encoders.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CBrowser - Cognitive Browser Automation
|
|
3
|
+
* Copyright 2026 Alexandria Eden alexandria.shai.eden@gmail.com
|
|
4
|
+
* Learn more at https://cbrowser.ai - MIT License
|
|
5
|
+
*/
|
|
6
|
+
import type { Locator, Page } from "playwright";
|
|
7
|
+
import { type CaptureMethod, type Engine, type RecordingManifest, type RecordingTarget } from "./types.js";
|
|
8
|
+
/** Output formats the CLI can request. */
|
|
9
|
+
export type CaptureFormat = "gif" | "webp" | "mp4" | "webm";
|
|
10
|
+
/** Condition that delays the first frame. */
|
|
11
|
+
export type StartTrigger = {
|
|
12
|
+
kind: "lifecycle";
|
|
13
|
+
event: "load" | "domcontentloaded" | "networkidle";
|
|
14
|
+
} | {
|
|
15
|
+
kind: "element";
|
|
16
|
+
selector: string;
|
|
17
|
+
};
|
|
18
|
+
/** Condition that ends the capture. */
|
|
19
|
+
export type StopTrigger = {
|
|
20
|
+
kind: "element-appears";
|
|
21
|
+
selector: string;
|
|
22
|
+
} | {
|
|
23
|
+
kind: "element-disappears";
|
|
24
|
+
selector: string;
|
|
25
|
+
} | {
|
|
26
|
+
kind: "idle";
|
|
27
|
+
idleMs: number;
|
|
28
|
+
};
|
|
29
|
+
/** Default ceiling on how long any trigger may wait. */
|
|
30
|
+
export declare const DEFAULT_TRIGGER_TIMEOUT_MS = 30000;
|
|
31
|
+
export interface VideoCaptureOptions {
|
|
32
|
+
/** What to capture: the whole viewport, a fixed region, or a tracked element. */
|
|
33
|
+
target?: RecordingTarget;
|
|
34
|
+
/** Requested frames per second. Screencast frames above this rate are dropped. */
|
|
35
|
+
fps?: number;
|
|
36
|
+
/** Auto-stop after this many milliseconds. Omit for an open-ended recording. */
|
|
37
|
+
durationMs?: number;
|
|
38
|
+
/** Directory for frames, manifest and artifacts. Defaults to a slug dir under `baseDir`. */
|
|
39
|
+
outDir?: string;
|
|
40
|
+
/** Encoders to run at stop time. Defaults to `["gif"]`. */
|
|
41
|
+
format?: CaptureFormat[];
|
|
42
|
+
/** JPEG quality for captured frames (1-100, default 80). */
|
|
43
|
+
quality?: number;
|
|
44
|
+
/** Hard cap on retained frames; protects the disk on a long open-ended run. */
|
|
45
|
+
maxFrames?: number;
|
|
46
|
+
/** Recording name. Defaults to a timestamp slug. */
|
|
47
|
+
slug?: string;
|
|
48
|
+
/** Also write a contact sheet: one JPEG summarising the whole capture. */
|
|
49
|
+
contactSheet?: boolean | {
|
|
50
|
+
columns?: number;
|
|
51
|
+
maxFrames?: number;
|
|
52
|
+
};
|
|
53
|
+
/** Delay the first frame until this condition holds. */
|
|
54
|
+
startTrigger?: StartTrigger;
|
|
55
|
+
/** Extra delay after the start trigger fires, in milliseconds. */
|
|
56
|
+
startDelayMs?: number;
|
|
57
|
+
/** Stop capture when this condition holds. */
|
|
58
|
+
stopTrigger?: StopTrigger;
|
|
59
|
+
/** How long a trigger may wait before giving up (default 30s). */
|
|
60
|
+
triggerTimeoutMs?: number;
|
|
61
|
+
/**
|
|
62
|
+
* Resolves a selector to a Locator for element targets. Supplied by the
|
|
63
|
+
* caller so the engine reuses the browser's existing nine-strategy resolver
|
|
64
|
+
* (including its self-healing cache) rather than owning a second one.
|
|
65
|
+
*/
|
|
66
|
+
resolveElement?: (selector: string) => Promise<Locator | null>;
|
|
67
|
+
}
|
|
68
|
+
export interface VideoCaptureStatus {
|
|
69
|
+
state: "idle" | "recording" | "stopped";
|
|
70
|
+
slug: string;
|
|
71
|
+
outDir: string;
|
|
72
|
+
/** Frames retained so far. */
|
|
73
|
+
frames: number;
|
|
74
|
+
/** Milliseconds since capture started (frozen once stopped). */
|
|
75
|
+
elapsedMs: number;
|
|
76
|
+
captureMethod: CaptureMethod;
|
|
77
|
+
/** Present once stopped. */
|
|
78
|
+
manifestPath?: string;
|
|
79
|
+
}
|
|
80
|
+
export interface VideoCaptureResult {
|
|
81
|
+
manifestPath: string;
|
|
82
|
+
manifest: RecordingManifest;
|
|
83
|
+
/** Encoders that failed, by format. Encoding failure never loses the frames. */
|
|
84
|
+
encodeErrors: Record<string, string>;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* One recording run. Not reusable: `start()` may be called once, and `stop()`
|
|
88
|
+
* is idempotent, returning the same result on every subsequent call.
|
|
89
|
+
*/
|
|
90
|
+
export declare class VideoCaptureSession {
|
|
91
|
+
private page;
|
|
92
|
+
private engine;
|
|
93
|
+
private baseDir;
|
|
94
|
+
private opts;
|
|
95
|
+
private startTrigger?;
|
|
96
|
+
private startDelayMs;
|
|
97
|
+
private stopTrigger?;
|
|
98
|
+
private target;
|
|
99
|
+
private slug;
|
|
100
|
+
private outDir;
|
|
101
|
+
private framesDir;
|
|
102
|
+
private state;
|
|
103
|
+
private captureMethod;
|
|
104
|
+
private cdp;
|
|
105
|
+
private loopTimer;
|
|
106
|
+
private durationTimer;
|
|
107
|
+
private stopping;
|
|
108
|
+
private startWallMs;
|
|
109
|
+
private startedAtIso;
|
|
110
|
+
private stopWallMs;
|
|
111
|
+
private frames;
|
|
112
|
+
private nextDueMs;
|
|
113
|
+
private writeQueue;
|
|
114
|
+
private consoleEvents;
|
|
115
|
+
private networkEvents;
|
|
116
|
+
private consoleListener;
|
|
117
|
+
private requestListener;
|
|
118
|
+
private viewport;
|
|
119
|
+
private regionClamped;
|
|
120
|
+
private outputDims;
|
|
121
|
+
/**
|
|
122
|
+
* Output dimensions as whole pixels.
|
|
123
|
+
*
|
|
124
|
+
* NOT rounded to even: the GIF/WebP encoders now emit exactly these numbers,
|
|
125
|
+
* so a 393px-wide viewport produces a 393px artifact. Only the video path
|
|
126
|
+
* rounds up to even internally (yuv420p needs it), which is the one place a
|
|
127
|
+
* single pixel of difference is unavoidable.
|
|
128
|
+
*/
|
|
129
|
+
private static outputDim;
|
|
130
|
+
/** Crop applied to frames captured right now; re-derived per frame for element targets. */
|
|
131
|
+
private currentCrop;
|
|
132
|
+
/** Whether `currentCrop` still reflects a live element measurement. */
|
|
133
|
+
private currentTracking;
|
|
134
|
+
private elementLocator;
|
|
135
|
+
private trackTimer;
|
|
136
|
+
private startTriggerLabel;
|
|
137
|
+
private stopTriggerLabel;
|
|
138
|
+
private triggerTimedOut;
|
|
139
|
+
private stopTriggerTimer;
|
|
140
|
+
private stopTimeoutTimer;
|
|
141
|
+
/** Rolling SSIM state for the idle stop trigger. */
|
|
142
|
+
private idleSignature;
|
|
143
|
+
private lastChangeMs;
|
|
144
|
+
private idleScanQueue;
|
|
145
|
+
private result;
|
|
146
|
+
private finishedResolve;
|
|
147
|
+
/**
|
|
148
|
+
* Resolves when the capture has stopped from ANY source - explicit stop(),
|
|
149
|
+
* the duration timer, or a stop trigger. Callers that started an open-ended
|
|
150
|
+
* capture await this instead of assuming they are the ones who will end it.
|
|
151
|
+
*/
|
|
152
|
+
readonly finished: Promise<VideoCaptureResult>;
|
|
153
|
+
/**
|
|
154
|
+
* @param page Page to record. Must already be navigated - the engine never
|
|
155
|
+
* navigates, so the caller controls what is on screen at t=0.
|
|
156
|
+
* @param engine Browser family, which decides the capture method.
|
|
157
|
+
* @param baseDir Directory recordings are created under when no `outDir` is given.
|
|
158
|
+
*/
|
|
159
|
+
constructor(page: Page, engine: Engine, baseDir: string);
|
|
160
|
+
start(options?: VideoCaptureOptions): Promise<VideoCaptureStatus>;
|
|
161
|
+
/**
|
|
162
|
+
* Stop capture, score the frames, write the manifest, run the encoders.
|
|
163
|
+
*
|
|
164
|
+
* Idempotent: concurrent and repeated calls all resolve to the same result,
|
|
165
|
+
* so an auto-stop racing an explicit stop cannot double-encode.
|
|
166
|
+
*/
|
|
167
|
+
stop(): Promise<VideoCaptureResult>;
|
|
168
|
+
status(): VideoCaptureStatus;
|
|
169
|
+
/**
|
|
170
|
+
* Resolve the capture target into a crop rect and a locked output size.
|
|
171
|
+
*
|
|
172
|
+
* Output dimensions are fixed here, for the whole capture, because animated
|
|
173
|
+
* GIF/WebP and every video container require a constant frame size. An
|
|
174
|
+
* element that grows or shrinks is re-fitted into these locked dimensions
|
|
175
|
+
* rather than changing them mid-stream.
|
|
176
|
+
*/
|
|
177
|
+
private setUpTarget;
|
|
178
|
+
/**
|
|
179
|
+
* Measure the tracked element, padded and clamped into the viewport.
|
|
180
|
+
* Returns null when the element has no usable box right now.
|
|
181
|
+
*/
|
|
182
|
+
private measureElement;
|
|
183
|
+
/**
|
|
184
|
+
* Re-measure the tracked element on the frame cadence so `crop` follows it as
|
|
185
|
+
* it moves. Polling rather than measuring inside the screencast handler: that
|
|
186
|
+
* handler must stay synchronous to ack frames promptly, and an await there
|
|
187
|
+
* would stall the stream.
|
|
188
|
+
*/
|
|
189
|
+
private startElementTracking;
|
|
190
|
+
/**
|
|
191
|
+
* Wait for the start trigger, then the start delay.
|
|
192
|
+
*
|
|
193
|
+
* Returns false when the trigger timed out. Timing out is a reportable
|
|
194
|
+
* outcome, not an exception: the caller still gets a manifest saying which
|
|
195
|
+
* trigger was asked for and that it never fired.
|
|
196
|
+
*/
|
|
197
|
+
private awaitStartTrigger;
|
|
198
|
+
/** Whether the start condition currently holds. */
|
|
199
|
+
private startConditionHolds;
|
|
200
|
+
/** Poll a condition until it holds or the budget runs out. */
|
|
201
|
+
private waitForCondition;
|
|
202
|
+
/**
|
|
203
|
+
* Watch for the stop condition, and enforce the trigger timeout.
|
|
204
|
+
*
|
|
205
|
+
* A stop trigger that never fires must not hang the capture: the timeout
|
|
206
|
+
* stops it anyway and flags `trigger_timeout`, keeping every frame captured
|
|
207
|
+
* up to that point.
|
|
208
|
+
*/
|
|
209
|
+
private startStopTriggerWatch;
|
|
210
|
+
/** Whether an element-based stop condition currently holds. */
|
|
211
|
+
private stopConditionHolds;
|
|
212
|
+
/**
|
|
213
|
+
* Stop once no frame has changed for `idleMs`.
|
|
214
|
+
*
|
|
215
|
+
* Reuses the same SSIM comparator and threshold that produce `change_points`,
|
|
216
|
+
* so "changed" means exactly the same thing live as it does in the manifest.
|
|
217
|
+
*/
|
|
218
|
+
private watchIdle;
|
|
219
|
+
private startScreencast;
|
|
220
|
+
/** Firefox/WebKit fallback: poll `page.screenshot` at the target rate. */
|
|
221
|
+
private startScreenshotLoop;
|
|
222
|
+
/**
|
|
223
|
+
* Capture one frame directly through Playwright rather than the screencast.
|
|
224
|
+
* Used to bracket the recording and to drive the non-Chromium fallback.
|
|
225
|
+
*/
|
|
226
|
+
private captureDirectFrame;
|
|
227
|
+
/**
|
|
228
|
+
* Rate-limit screencast frames to the requested fps.
|
|
229
|
+
*
|
|
230
|
+
* Frames are matched against a fixed grid of due times rather than against
|
|
231
|
+
* "time since the last kept frame". A since-last rule compounds every paint
|
|
232
|
+
* event's jitter into the next interval and drifts the achieved rate away
|
|
233
|
+
* from the target; the grid holds the average at exactly `fps`.
|
|
234
|
+
*/
|
|
235
|
+
private shouldKeep;
|
|
236
|
+
/**
|
|
237
|
+
* Record a frame and stream its bytes to disk.
|
|
238
|
+
*
|
|
239
|
+
* The index and timestamp are assigned synchronously so frame ordering
|
|
240
|
+
* follows arrival order; only the write is deferred, serialised through a
|
|
241
|
+
* queue so a slow disk cannot reorder frames or unbound memory.
|
|
242
|
+
*/
|
|
243
|
+
private enqueueFrame;
|
|
244
|
+
private attachPageListeners;
|
|
245
|
+
private detachPageListeners;
|
|
246
|
+
private doStop;
|
|
247
|
+
private buildManifest;
|
|
248
|
+
/** SSIM of each frame against its predecessor; index 0 is always null. */
|
|
249
|
+
private scoreFrames;
|
|
250
|
+
/**
|
|
251
|
+
* Attach each side-channel event to the frame whose display window contains
|
|
252
|
+
* it: the last frame at or before the event, or frame 0 for anything that
|
|
253
|
+
* fired before the first frame landed.
|
|
254
|
+
*/
|
|
255
|
+
private eventsForFrame;
|
|
256
|
+
/**
|
|
257
|
+
* Run the requested encoders. An encoder failure is recorded and reported but
|
|
258
|
+
* never thrown - the frames and manifest are the durable artifact, and losing
|
|
259
|
+
* a recording because a codec is missing would be the worst possible trade.
|
|
260
|
+
*/
|
|
261
|
+
private runEncoders;
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/recording/engine.ts"],"names":[],"mappings":"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"}
|