UNPKG

coze-plugin-utils

Version:

Comprehensive utility library for Coze plugins with multimedia processing, browser automation, cloud storage integration, and AI-powered video/audio generation capabilities

122 lines 5.33 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.htmlToVideo = htmlToVideo; exports.htmlToScreenshot = htmlToScreenshot; const node_path_1 = __importDefault(require("node:path")); const node_fs_1 = __importDefault(require("node:fs")); const promises_1 = require("timers/promises"); const fluent_ffmpeg_1 = __importDefault(require("fluent-ffmpeg")); const ffmpeg_static_1 = __importDefault(require("ffmpeg-static")); const puppeteer_core_1 = __importDefault(require("puppeteer-core")); const core_1 = require("../core"); async function htmlToVideo({ code, duration = 2, width, height, deviceScaleFactor = 1, sample_ratio = 1, }) { sample_ratio = sample_ratio || 1; const apiKey = (0, core_1.getGlobalConfig)('browser')?.apiKey; if (!apiKey) { throw new Error('请先配置 browser apiKey'); } // 写入 /tmp 目录 const tmpDir = (0, core_1.createTempDir)(); const browser = await puppeteer_core_1.default.connect({ browserWSEndpoint: `wss://production-sfo.browserless.io/?token=${apiKey}`, }); const page = await browser.newPage(); // await page.setViewport({ width, height }); // 包裹 SVG 成 HTML 页面 const html = code; await page.setContent(html); // 获取页面实际尺寸 const dimensions = { width, height }; if (!dimensions.width || !dimensions.height) { const autoDimensions = await page.evaluate(() => ({ width: document.documentElement.scrollWidth, height: document.documentElement.scrollHeight, })); dimensions.width = dimensions.width || autoDimensions.width; dimensions.height = dimensions.height || autoDimensions.height; } await page.setViewport({ ...dimensions, deviceScaleFactor }); // 启动 DevTools 会话 const client = await page.target().createCDPSession(); // 0.1 = 动画统一放慢 sample_ratio 倍,因为要考虑 browserless 延迟,直接原速度截图生成动画会卡 await client.send('Animation.setPlaybackRate', { playbackRate: 1 / sample_ratio }); const frames = []; await client.send('Page.startScreencast', { format: 'png', everyNthFrame: 1, }); client.on('Page.screencastFrame', async (res) => { const buffer = Buffer.from(res.data, 'base64'); frames.push(buffer); console.log('capturing frame', frames.length, '...'); await client.send('Page.screencastFrameAck', { sessionId: res.sessionId }); }); await (0, promises_1.setTimeout)(sample_ratio * duration * 1000); await client.send('Page.stopScreencast'); await browser.close(); const framePrefix = node_path_1.default.join(tmpDir, 'frame_'); for (let i = 0; i < frames.length; i++) { const filename = `${framePrefix}${String(i).padStart(4, '0')}.png`; console.log('writing frame', filename, '...'); node_fs_1.default.writeFileSync(filename, frames[i]); } const outputPath = node_path_1.default.join(tmpDir, 'output.mp4'); await new Promise((resolve, reject) => { (0, fluent_ffmpeg_1.default)() .setFfmpegPath(ffmpeg_static_1.default) .input(`${framePrefix}%04d.png`) .inputFPS(frames.length / duration) .outputOptions([ '-pix_fmt yuv420p', `-t ${duration}`, ]) .output(outputPath) .on('end', resolve) .on('error', reject) .run(); }); return outputPath; } /** * 截取HTML页面的屏幕截图 * @param options 截图选项 * @returns 返回图片的临时文件路径 */ async function htmlToScreenshot({ code, width, height, deviceScaleFactor = 1, delay = 500, }) { const apiKey = (0, core_1.getGlobalConfig)('browser')?.apiKey; if (!apiKey) { throw new Error('请先配置 browser apiKey'); } // 创建临时目录 const tmpDir = (0, core_1.createTempDir)(); const browser = await puppeteer_core_1.default.connect({ browserWSEndpoint: `wss://production-sfo.browserless.io/?token=${apiKey}`, }); const page = await browser.newPage(); // 设置HTML内容 await page.setContent(code); // 等待页面加载完成 - 等待DOM加载完成 await page.waitForFunction(() => document.readyState === 'complete'); // 获取页面实际尺寸 const dimensions = { width, height }; if (!dimensions.width || !dimensions.height) { const autoDimensions = await page.evaluate(() => ({ width: document.documentElement.scrollWidth, height: document.documentElement.scrollHeight, })); dimensions.width = dimensions.width || autoDimensions.width; dimensions.height = dimensions.height || autoDimensions.height; } await page.setViewport({ ...dimensions, deviceScaleFactor }); // 延迟指定毫秒数 await (0, promises_1.setTimeout)(delay); // 截图 const screenshotPath = node_path_1.default.join(tmpDir, 'screenshot.png'); await page.screenshot({ path: screenshotPath, fullPage: true }); await browser.close(); return screenshotPath; } //# sourceMappingURL=browser.js.map