@css-doodle/cli
Version:
Command-line tool for css-doodle to preview and generate images/videos
91 lines (77 loc) • 2.55 kB
JavaScript
import { setTimeout } from 'node:timers/promises';
import { spawn } from 'node:child_process';
import { randomUUID } from 'node:crypto';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { msgTip } from '../message.js';
const defaultWindowWidth = 1200;
const defaultWindowHeight = 800;
const defaultScale = 1;
export async function screencast(page, options) {
const { scale, output, selector, windowWidth, windowHeight } = options;
const WIDTH = windowWidth || defaultWindowWidth;
const HEIGHT = windowHeight || defaultWindowHeight;
const SCALE = scale || defaultScale;
await page.setViewport({
width: WIDTH,
height: HEIGHT,
defaultScaleFactor: SCALE
});
await setTimeout(200);
const castOption = {
path: options.mp4
? join(tmpdir(), randomUUID() + '.webm')
: output
};
const crop = await page.evaluate(async selector => {
const element = document.querySelector(selector);
if (element) {
const rect = element.getBoundingClientRect();
if (rect.width === 0 || rect.height === 0) {
await setTimeout(1000);
}
const { width, height, x, y } = element.getBoundingClientRect();
return {
x,
y,
width,
height: height || width,
};
}
}, selector);
if (crop) {
crop.x = Math.max(crop.x, 0) || 0;
crop.y = Math.max(crop.y, 0) || 0;
crop.width = Math.min(crop.width, WIDTH) || WIDTH;
crop.height = Math.min(crop.height, HEIGHT) || HEIGHT;
castOption.crop = crop;
}
if (!options.quiet) {
console.log(msgTip('Recording'));
}
const recorder = await page.screencast(castOption);
await setTimeout(options.time);
await recorder.stop();
if (options.mp4) {
try {
return await webmToMp4(castOption.path, output);
} catch (e) {
throw e;
}
}
return output;
}
function webmToMp4(input, output) {
return new Promise((resolve, reject) => {
const ffmpeg = spawn('ffmpeg', ['-i', input, '-c:v', 'copy', output]);
ffmpeg.stdin.write('y\n');
ffmpeg.stdin.end();
ffmpeg.on('close', code => {
if (code === 0) {
resolve(output);
} else {
reject(new Error(`record failed, ffmpeg exited with code ${code}`));
}
});
});
}