@editframe/cli 0.32.0-beta.0 → 0.33.0-beta
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/VERSION.js +1 -1
- package/dist/VERSION.js.map +1 -1
- package/dist/commands/render.js +27 -3
- package/dist/commands/render.js.map +1 -1
- package/package.json +5 -5
package/dist/VERSION.js
CHANGED
package/dist/VERSION.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VERSION.js","names":[],"sources":["../src/VERSION.ts"],"sourcesContent":["export const VERSION = \"0.
|
|
1
|
+
{"version":3,"file":"VERSION.js","names":[],"sources":["../src/VERSION.ts"],"sourcesContent":["export const VERSION = \"0.33.0-beta\";\n"],"mappings":";AAAA,MAAa,UAAU"}
|
package/dist/commands/render.js
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
|
-
import { withSpinner } from "../utils/withSpinner.js";
|
|
2
1
|
import { launchBrowserAndWaitForSDK } from "../utils/launchBrowserAndWaitForSDK.js";
|
|
3
2
|
import { PreviewServer } from "../utils/startPreviewServer.js";
|
|
4
3
|
import { program } from "commander";
|
|
5
4
|
import debug from "debug";
|
|
5
|
+
import ora from "ora";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { readFile } from "node:fs/promises";
|
|
8
8
|
import { createWriteStream } from "node:fs";
|
|
9
9
|
|
|
10
10
|
//#region src/commands/render.ts
|
|
11
11
|
const log = debug("ef:cli:render");
|
|
12
|
+
/**
|
|
13
|
+
* Format milliseconds as MM:SS or HH:MM:SS
|
|
14
|
+
*/
|
|
15
|
+
function formatTime(ms) {
|
|
16
|
+
const totalSeconds = Math.floor(ms / 1e3);
|
|
17
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
18
|
+
const minutes = Math.floor(totalSeconds % 3600 / 60);
|
|
19
|
+
const seconds = totalSeconds % 60;
|
|
20
|
+
if (hours > 0) return `${hours}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
|
|
21
|
+
return `${minutes}:${seconds.toString().padStart(2, "0")}`;
|
|
22
|
+
}
|
|
12
23
|
program.command("render [directory]").description("Render a video composition locally").option("-o, --output <path>", "Output file path", "output.mp4").option("-d, --data <json>", "Custom render data (JSON string)").option("--data-file <path>", "Custom render data from JSON file").option("--fps <number>", "Frame rate", "30").option("--scale <number>", "Resolution scale (0-1)", "1").option("--include-audio", "Include audio track", true).option("--no-include-audio", "Exclude audio track").option("--from-ms <number>", "Start time in milliseconds").option("--to-ms <number>", "End time in milliseconds").option("--experimental-native-render", "Use experimental canvas capture API (faster)").action(async (directory = ".", options) => {
|
|
13
24
|
const srcDir = path.resolve(process.cwd(), directory);
|
|
14
25
|
const outputPath = path.resolve(process.cwd(), options.output);
|
|
@@ -52,7 +63,16 @@ program.command("render [directory]").description("Render a video composition lo
|
|
|
52
63
|
}
|
|
53
64
|
await page.waitForFunction(() => typeof window.EF_RENDER !== "undefined", { timeout: 1e4 });
|
|
54
65
|
if (!await page.evaluate(() => window.EF_RENDER?.isReady())) throw new Error("Render API is not ready. No ef-timegroup found.");
|
|
55
|
-
|
|
66
|
+
const progressSpinner = ora("Rendering video...").start();
|
|
67
|
+
await page.exposeFunction("onRenderProgress", (progress) => {
|
|
68
|
+
const percent = (progress.progress * 100).toFixed(1);
|
|
69
|
+
const renderedTime = formatTime(progress.renderedMs);
|
|
70
|
+
const totalTime = formatTime(progress.totalDurationMs);
|
|
71
|
+
const remainingTime = formatTime(progress.estimatedRemainingMs);
|
|
72
|
+
const speed = progress.speedMultiplier.toFixed(2);
|
|
73
|
+
progressSpinner.text = `Rendering: ${progress.currentFrame}/${progress.totalFrames} frames (${percent}%) | ${renderedTime}/${totalTime} | ${remainingTime} remaining | ${speed}x speed`;
|
|
74
|
+
});
|
|
75
|
+
try {
|
|
56
76
|
const renderOptions = {
|
|
57
77
|
fps,
|
|
58
78
|
scale,
|
|
@@ -63,7 +83,11 @@ program.command("render [directory]").description("Render a video composition lo
|
|
|
63
83
|
await page.evaluate(async (opts) => {
|
|
64
84
|
await window.EF_RENDER.renderStreaming(opts);
|
|
65
85
|
}, renderOptions);
|
|
66
|
-
|
|
86
|
+
progressSpinner.succeed("Render complete");
|
|
87
|
+
} catch (error) {
|
|
88
|
+
progressSpinner.fail("Render failed");
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
67
91
|
outputStream.end();
|
|
68
92
|
await new Promise((resolve, reject) => {
|
|
69
93
|
outputStream.on("finish", () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","names":["renderData: Record<string, unknown> | undefined","renderOptions: any"],"sources":["../../src/commands/render.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { createWriteStream } from \"node:fs\";\nimport path from \"node:path\";\nimport { program } from \"commander\";\nimport debug from \"debug\";\nimport
|
|
1
|
+
{"version":3,"file":"render.js","names":["renderData: Record<string, unknown> | undefined","renderOptions: any"],"sources":["../../src/commands/render.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { createWriteStream } from \"node:fs\";\nimport path from \"node:path\";\nimport { program } from \"commander\";\nimport debug from \"debug\";\nimport ora from \"ora\";\nimport { launchBrowserAndWaitForSDK } from \"../utils/launchBrowserAndWaitForSDK.js\";\nimport { PreviewServer } from \"../utils/startPreviewServer.js\";\n\nconst log = debug(\"ef:cli:render\");\n\n/**\n * Format milliseconds as MM:SS or HH:MM:SS\n */\nfunction formatTime(ms: number): string {\n const totalSeconds = Math.floor(ms / 1000);\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n\n if (hours > 0) {\n return `${hours}:${minutes.toString().padStart(2, \"0\")}:${seconds.toString().padStart(2, \"0\")}`;\n }\n return `${minutes}:${seconds.toString().padStart(2, \"0\")}`;\n}\n\nprogram\n .command(\"render [directory]\")\n .description(\"Render a video composition locally\")\n .option(\"-o, --output <path>\", \"Output file path\", \"output.mp4\")\n .option(\"-d, --data <json>\", \"Custom render data (JSON string)\")\n .option(\"--data-file <path>\", \"Custom render data from JSON file\")\n .option(\"--fps <number>\", \"Frame rate\", \"30\")\n .option(\"--scale <number>\", \"Resolution scale (0-1)\", \"1\")\n .option(\"--include-audio\", \"Include audio track\", true)\n .option(\"--no-include-audio\", \"Exclude audio track\")\n .option(\"--from-ms <number>\", \"Start time in milliseconds\")\n .option(\"--to-ms <number>\", \"End time in milliseconds\")\n .option(\"--experimental-native-render\", \"Use experimental canvas capture API (faster)\")\n .action(async (directory = \".\", options) => {\n const srcDir = path.resolve(process.cwd(), directory);\n const outputPath = path.resolve(process.cwd(), options.output);\n\n // Parse custom data if provided\n let renderData: Record<string, unknown> | undefined;\n if (options.dataFile) {\n const dataFileContent = await readFile(options.dataFile, \"utf-8\");\n renderData = JSON.parse(dataFileContent);\n log(\"Loaded render data from file:\", options.dataFile);\n } else if (options.data) {\n renderData = JSON.parse(options.data);\n log(\"Using render data from --data option\");\n }\n\n // Parse numeric options\n const fps = parseInt(options.fps, 10);\n const scale = parseFloat(options.scale);\n const fromMs = options.fromMs ? parseInt(options.fromMs, 10) : undefined;\n const toMs = options.toMs ? parseInt(options.toMs, 10) : undefined;\n\n // Start preview server\n const previewServer = await PreviewServer.start(srcDir);\n log(\"Preview server started at:\", previewServer.url);\n\n // Launch browser and render\n await launchBrowserAndWaitForSDK(\n {\n url: previewServer.url,\n headless: true,\n interactive: false,\n efInteractive: false,\n nativeRender: options.experimentalNativeRender === true,\n },\n async (page) => {\n // Open output file for streaming writes\n const outputStream = createWriteStream(outputPath);\n let chunkCount = 0;\n let totalBytes = 0;\n\n // Expose chunk handler - writes directly to file\n await page.exposeFunction(\"onRenderChunk\", (chunkArray: number[]) => {\n const chunk = Buffer.from(chunkArray);\n outputStream.write(chunk);\n chunkCount++;\n totalBytes += chunk.length;\n log(`Received chunk ${chunkCount}: ${chunk.length} bytes (total: ${totalBytes} bytes)`);\n });\n\n // Set custom render data if provided\n if (renderData) {\n await page.evaluate((data) => {\n window.EF_RENDER_DATA = data;\n }, renderData);\n log(\"Set EF_RENDER_DATA:\", renderData);\n }\n\n // Wait for EF_RENDER API to be available\n await page.waitForFunction(\n () => typeof window.EF_RENDER !== \"undefined\",\n { timeout: 10_000 },\n );\n\n // Check if ready\n const isReady = await page.evaluate(() => window.EF_RENDER?.isReady());\n if (!isReady) {\n throw new Error(\"Render API is not ready. No ef-timegroup found.\");\n }\n\n // Create progress spinner\n const progressSpinner = ora(\"Rendering video...\").start();\n\n // Expose progress callback\n await page.exposeFunction(\"onRenderProgress\", (progress: {\n progress: number;\n currentFrame: number;\n totalFrames: number;\n renderedMs: number;\n totalDurationMs: number;\n elapsedMs: number;\n estimatedRemainingMs: number;\n speedMultiplier: number;\n }) => {\n const percent = (progress.progress * 100).toFixed(1);\n const renderedTime = formatTime(progress.renderedMs);\n const totalTime = formatTime(progress.totalDurationMs);\n const remainingTime = formatTime(progress.estimatedRemainingMs);\n const speed = progress.speedMultiplier.toFixed(2);\n \n progressSpinner.text = `Rendering: ${progress.currentFrame}/${progress.totalFrames} frames (${percent}%) | ${renderedTime}/${totalTime} | ${remainingTime} remaining | ${speed}x speed`;\n });\n\n // Render with streaming\n try {\n const renderOptions: any = {\n fps,\n scale,\n includeAudio: options.includeAudio !== false,\n };\n\n if (fromMs !== undefined) {\n renderOptions.fromMs = fromMs;\n }\n if (toMs !== undefined) {\n renderOptions.toMs = toMs;\n }\n\n await page.evaluate(async (opts) => {\n await window.EF_RENDER!.renderStreaming(opts);\n }, renderOptions);\n\n progressSpinner.succeed(\"Render complete\");\n } catch (error) {\n progressSpinner.fail(\"Render failed\");\n throw error;\n }\n\n // Close the output stream\n outputStream.end();\n\n // Wait for stream to finish\n await new Promise<void>((resolve, reject) => {\n outputStream.on(\"finish\", () => {\n log(`Render complete: ${chunkCount} chunks, ${totalBytes} bytes written to ${outputPath}`);\n resolve();\n });\n outputStream.on(\"error\", reject);\n });\n },\n );\n\n process.stderr.write(`\\nRender complete: ${outputPath}\\n`);\n });\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@editframe/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0-beta",
|
|
4
4
|
"description": "Command line interface for EditFrame",
|
|
5
5
|
"bin": {
|
|
6
6
|
"editframe": "./dist/index.js"
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
"typescript": "^5.5.4"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@editframe/api": "0.
|
|
26
|
-
"@editframe/assets": "0.
|
|
27
|
-
"@editframe/elements": "0.
|
|
28
|
-
"@editframe/vite-plugin": "0.
|
|
25
|
+
"@editframe/api": "0.33.0-beta",
|
|
26
|
+
"@editframe/assets": "0.33.0-beta",
|
|
27
|
+
"@editframe/elements": "0.33.0-beta",
|
|
28
|
+
"@editframe/vite-plugin": "0.33.0-beta",
|
|
29
29
|
"@inquirer/prompts": "^5.3.8",
|
|
30
30
|
"chalk": "^5.3.0",
|
|
31
31
|
"commander": "^12.0.0",
|