@editframe/cli 0.26.3-beta.0 → 0.30.0-beta.13
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/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/commands/auth.ts +0 -46
- package/src/commands/check.ts +0 -129
- package/src/commands/mux.ts +0 -10
- package/src/commands/preview.ts +0 -9
- package/src/commands/process-file.ts +0 -55
- package/src/commands/process.ts +0 -41
- package/src/commands/render.ts +0 -190
- package/src/commands/sync.ts +0 -13
- package/src/commands/test-asset.file +0 -0
- package/src/commands/webhook.ts +0 -76
- package/src/operations/processRenderInfo.ts +0 -40
- package/src/operations/syncAssetsDirectory/SubAssetSync.ts +0 -45
- package/src/operations/syncAssetsDirectory/SyncCaption.test.ts +0 -180
- package/src/operations/syncAssetsDirectory/SyncCaption.ts +0 -87
- package/src/operations/syncAssetsDirectory/SyncFragmentIndex.test.ts +0 -185
- package/src/operations/syncAssetsDirectory/SyncFragmentIndex.ts +0 -101
- package/src/operations/syncAssetsDirectory/SyncImage.test.ts +0 -162
- package/src/operations/syncAssetsDirectory/SyncImage.ts +0 -123
- package/src/operations/syncAssetsDirectory/SyncStatus.ts +0 -50
- package/src/operations/syncAssetsDirectory/SyncTrack.test.ts +0 -265
- package/src/operations/syncAssetsDirectory/SyncTrack.ts +0 -175
- package/src/operations/syncAssetsDirectory/doAssetSync.test.ts +0 -134
- package/src/operations/syncAssetsDirectory/doAssetSync.ts +0 -62
- package/src/operations/syncAssetsDirectory.test.ts +0 -510
- package/src/operations/syncAssetsDirectory.ts +0 -91
- package/src/utils/attachWorkbench.ts +0 -16
- package/src/utils/createReadableStreamFromReadable.ts +0 -113
- package/src/utils/getFolderSize.ts +0 -20
- package/src/utils/index.ts +0 -20
- package/src/utils/launchBrowserAndWaitForSDK.ts +0 -64
- package/src/utils/startDevServer.ts +0 -61
- package/src/utils/startPreviewServer.ts +0 -38
- package/src/utils/validateVideoResolution.ts +0 -36
- package/src/utils/withSpinner.ts +0 -16
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.30.0-beta.13\";\n"],"mappings":";AAAA,MAAa,UAAU"}
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import "dotenv/config";
|
|
|
12
12
|
import { Option, program } from "commander";
|
|
13
13
|
|
|
14
14
|
//#region src/index.ts
|
|
15
|
-
program.name("editframe").addOption(new Option("-t, --token <token>", "API Token").env("EF_TOKEN")).addOption(new Option("--ef-host <host>", "Editframe Host").env("EF_HOST").default("https://editframe.
|
|
15
|
+
program.name("editframe").addOption(new Option("-t, --token <token>", "API Token").env("EF_TOKEN")).addOption(new Option("--ef-host <host>", "Editframe Host").env("EF_HOST").default("https://editframe.com")).addOption(new Option("--ef-render-host <host>", "Editframe Render Host").env("EF_RENDER_HOST").default("https://editframe.com")).version(VERSION);
|
|
16
16
|
program.parse(process.argv);
|
|
17
17
|
|
|
18
18
|
//#endregion
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport \"dotenv/config\";\nimport { Option, program } from \"commander\";\n\nimport { VERSION } from \"./VERSION.js\";\n\nprogram\n .name(\"editframe\")\n .addOption(new Option(\"-t, --token <token>\", \"API Token\").env(\"EF_TOKEN\"))\n .addOption(\n new Option(\"--ef-host <host>\", \"Editframe Host\")\n .env(\"EF_HOST\")\n .default(\"https://editframe.
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport \"dotenv/config\";\nimport { Option, program } from \"commander\";\n\nimport { VERSION } from \"./VERSION.js\";\n\nprogram\n .name(\"editframe\")\n .addOption(new Option(\"-t, --token <token>\", \"API Token\").env(\"EF_TOKEN\"))\n .addOption(\n new Option(\"--ef-host <host>\", \"Editframe Host\")\n .env(\"EF_HOST\")\n .default(\"https://editframe.com\"),\n )\n .addOption(\n new Option(\"--ef-render-host <host>\", \"Editframe Render Host\")\n .env(\"EF_RENDER_HOST\")\n .default(\"https://editframe.com\"),\n )\n .version(VERSION);\n\nimport \"./commands/auth.js\";\nimport \"./commands/sync.js\";\nimport \"./commands/render.js\";\nimport \"./commands/preview.js\";\nimport \"./commands/process.js\";\nimport \"./commands/process-file.js\";\nimport \"./commands/check.js\";\nimport \"./commands/webhook.js\";\n\nprogram.parse(process.argv);\n"],"mappings":";;;;;;;;;;;;;;AAMA,QACG,KAAK,YAAY,CACjB,UAAU,IAAI,OAAO,uBAAuB,YAAY,CAAC,IAAI,WAAW,CAAC,CACzE,UACC,IAAI,OAAO,oBAAoB,iBAAiB,CAC7C,IAAI,UAAU,CACd,QAAQ,wBAAwB,CACpC,CACA,UACC,IAAI,OAAO,2BAA2B,wBAAwB,CAC3D,IAAI,iBAAiB,CACrB,QAAQ,wBAAwB,CACpC,CACA,QAAQ,QAAQ;AAWnB,QAAQ,MAAM,QAAQ,KAAK"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@editframe/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0-beta.13",
|
|
4
4
|
"description": "Command line interface for EditFrame",
|
|
5
5
|
"bin": {
|
|
6
6
|
"editframe": "./dist/index.js"
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
"typescript": "^5.5.4"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@editframe/api": "0.
|
|
25
|
-
"@editframe/assets": "0.
|
|
26
|
-
"@editframe/elements": "0.
|
|
27
|
-
"@editframe/vite-plugin": "0.
|
|
24
|
+
"@editframe/api": "0.30.0-beta.13",
|
|
25
|
+
"@editframe/assets": "0.30.0-beta.13",
|
|
26
|
+
"@editframe/elements": "0.30.0-beta.13",
|
|
27
|
+
"@editframe/vite-plugin": "0.30.0-beta.13",
|
|
28
28
|
"@inquirer/prompts": "^5.3.8",
|
|
29
29
|
"chalk": "^5.3.0",
|
|
30
30
|
"commander": "^12.0.0",
|
|
@@ -61,4 +61,4 @@
|
|
|
61
61
|
"./package.json": "./package.json"
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
-
}
|
|
64
|
+
}
|
package/src/commands/auth.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import { program } from "commander";
|
|
3
|
-
import debug from "debug";
|
|
4
|
-
import ora from "ora";
|
|
5
|
-
|
|
6
|
-
import { getClient } from "../utils/index.js";
|
|
7
|
-
|
|
8
|
-
const log = debug("ef:cli:auth");
|
|
9
|
-
|
|
10
|
-
export interface APIOrgResult {
|
|
11
|
-
apiKeyName: string;
|
|
12
|
-
id: string;
|
|
13
|
-
org_id: string;
|
|
14
|
-
created_at: unknown;
|
|
15
|
-
updated_at: unknown;
|
|
16
|
-
displayName: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const getApiData = async () => {
|
|
20
|
-
const response = await getClient().authenticatedFetch("/api/v1/organization");
|
|
21
|
-
return response.json() as Promise<APIOrgResult>;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const authCommand = program
|
|
25
|
-
.command("auth")
|
|
26
|
-
.description("Fetch organization data using API token")
|
|
27
|
-
.action(async () => {
|
|
28
|
-
const options = authCommand.opts();
|
|
29
|
-
log("Options:", options);
|
|
30
|
-
|
|
31
|
-
const spinner = ora("Loading...").start();
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
const apiData = await getApiData();
|
|
35
|
-
spinner.succeed("You are authenticated! 🎉");
|
|
36
|
-
process.stderr.write(
|
|
37
|
-
chalk.green(`You're using ${apiData.apiKeyName} API key 🚀\n`),
|
|
38
|
-
);
|
|
39
|
-
process.stderr.write(
|
|
40
|
-
chalk.blue(`Welcome to ${apiData.displayName} organization 🎉\n`),
|
|
41
|
-
);
|
|
42
|
-
} catch (error: any) {
|
|
43
|
-
spinner.fail("Authentication failed!");
|
|
44
|
-
log("Error:", error);
|
|
45
|
-
}
|
|
46
|
-
});
|
package/src/commands/check.ts
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { exec } from "node:child_process";
|
|
2
|
-
import os from "node:os";
|
|
3
|
-
import chalk from "chalk";
|
|
4
|
-
import { program } from "commander";
|
|
5
|
-
import ora from "ora";
|
|
6
|
-
|
|
7
|
-
interface CheckDescriptor {
|
|
8
|
-
check(): Promise<boolean>;
|
|
9
|
-
message(): string[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const checks: Record<string, CheckDescriptor> = {
|
|
13
|
-
ffmpeg: {
|
|
14
|
-
message: () => {
|
|
15
|
-
const platform = os.platform();
|
|
16
|
-
const message = [
|
|
17
|
-
"Processing assets for <ef-video>, <ef-audio>, <ef-captions>, and <ef-waveform>\n elements requires ffmpeg to be installed.",
|
|
18
|
-
];
|
|
19
|
-
switch (platform) {
|
|
20
|
-
case "darwin": {
|
|
21
|
-
message.push(
|
|
22
|
-
"On platform=darwin you can install ffmpeg using Homebrew:",
|
|
23
|
-
);
|
|
24
|
-
message.push(" - brew install ffmpeg");
|
|
25
|
-
message.push(
|
|
26
|
-
"Or you can download ffmpeg from https://ffmpeg.org/download.html",
|
|
27
|
-
);
|
|
28
|
-
break;
|
|
29
|
-
}
|
|
30
|
-
case "linux": {
|
|
31
|
-
message.push(
|
|
32
|
-
"You can install ffmpeg using your distribution's package manager.",
|
|
33
|
-
);
|
|
34
|
-
break;
|
|
35
|
-
}
|
|
36
|
-
case "win32": {
|
|
37
|
-
message.push(
|
|
38
|
-
"You can download ffmpeg from https://ffmpeg.org/download.html",
|
|
39
|
-
);
|
|
40
|
-
message.push(
|
|
41
|
-
"You can use package managers like Chocolatey or Scoop to install ffmpeg.",
|
|
42
|
-
);
|
|
43
|
-
message.push(" - choco install ffmpeg-full");
|
|
44
|
-
message.push(" - scoop install ffmpeg");
|
|
45
|
-
message.push(" - winget install ffmpeg");
|
|
46
|
-
break;
|
|
47
|
-
}
|
|
48
|
-
default: {
|
|
49
|
-
message.push(`Unrecognized platform ${platform}`);
|
|
50
|
-
message.push(
|
|
51
|
-
"You can download ffmpeg from https://ffmpeg.org/download.html",
|
|
52
|
-
);
|
|
53
|
-
message.push(
|
|
54
|
-
"Or try installing it from your operating system's package manager",
|
|
55
|
-
);
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return message;
|
|
60
|
-
},
|
|
61
|
-
check: async () => {
|
|
62
|
-
return new Promise((resolve, reject) => {
|
|
63
|
-
exec("ffmpeg -version", (error: any, stdout: any, _stderr: any) => {
|
|
64
|
-
if (error) {
|
|
65
|
-
reject(error);
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
resolve(stdout);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
|
|
74
|
-
whisper_timestamped: {
|
|
75
|
-
message: () => {
|
|
76
|
-
const message = [
|
|
77
|
-
"<ef-captions> Requires whisper_timestamped to be installed.",
|
|
78
|
-
];
|
|
79
|
-
|
|
80
|
-
message.push("whisper_timestamped depends on python3");
|
|
81
|
-
|
|
82
|
-
message.push(" - pip3 install whisper_timestamped");
|
|
83
|
-
|
|
84
|
-
message.push("Alternate installation instructions are availble at:");
|
|
85
|
-
message.push(
|
|
86
|
-
"https://github.com/linto-ai/whisper-timestamped#installation",
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
return message;
|
|
90
|
-
},
|
|
91
|
-
check: async () => {
|
|
92
|
-
return new Promise((resolve, reject) => {
|
|
93
|
-
exec(
|
|
94
|
-
"whisper_timestamped --version",
|
|
95
|
-
(error: any, stdout: any, _stderr: any) => {
|
|
96
|
-
if (error) {
|
|
97
|
-
reject(error);
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
resolve(stdout);
|
|
101
|
-
},
|
|
102
|
-
);
|
|
103
|
-
});
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
program
|
|
109
|
-
.command("check")
|
|
110
|
-
.description("Check on dependencies and other requirements")
|
|
111
|
-
.action(async () => {
|
|
112
|
-
for (const checkName in checks) {
|
|
113
|
-
const check = checks[checkName];
|
|
114
|
-
if (!check) {
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
const spinner = ora(`Checking ${checkName}`).start();
|
|
118
|
-
try {
|
|
119
|
-
await check.check();
|
|
120
|
-
spinner.succeed(
|
|
121
|
-
chalk.white.bgGreen(` Check for ${checkName} passed `),
|
|
122
|
-
);
|
|
123
|
-
} catch (_error) {
|
|
124
|
-
spinner.fail(chalk.white.bgRed(` Check for ${checkName} failed `));
|
|
125
|
-
process.stderr.write(chalk.red(check.message().join("\n\n")));
|
|
126
|
-
process.stderr.write("\n");
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
});
|
package/src/commands/mux.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Probe } from "@editframe/assets";
|
|
2
|
-
import { program } from "commander";
|
|
3
|
-
|
|
4
|
-
program
|
|
5
|
-
.command("mux <path>")
|
|
6
|
-
.description("Mux a file into multiple audio/video tracks.")
|
|
7
|
-
.action(async (path: string) => {
|
|
8
|
-
const probe = await Probe.probePath(path);
|
|
9
|
-
console.log(probe);
|
|
10
|
-
});
|
package/src/commands/preview.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
import { program } from "commander";
|
|
3
|
-
|
|
4
|
-
program
|
|
5
|
-
.command("preview [directory]")
|
|
6
|
-
.description("Preview a directory's index.html file")
|
|
7
|
-
.action(async (projectDirectory = ".") => {
|
|
8
|
-
spawn("npx", ["vite", "dev"], { cwd: projectDirectory, stdio: "inherit" });
|
|
9
|
-
});
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createUnprocessedFileFromPath,
|
|
3
|
-
getIsobmffProcessInfo,
|
|
4
|
-
getIsobmffProcessProgress,
|
|
5
|
-
processIsobmffFile,
|
|
6
|
-
uploadUnprocessedFile,
|
|
7
|
-
} from "@editframe/api/node";
|
|
8
|
-
import { program } from "commander";
|
|
9
|
-
import ora from "ora";
|
|
10
|
-
import { getClient } from "../utils/index.js";
|
|
11
|
-
import { withSpinner } from "../utils/withSpinner.js";
|
|
12
|
-
|
|
13
|
-
program
|
|
14
|
-
.command("process-file <file>")
|
|
15
|
-
.description("Upload a audio/video to Editframe for processing.")
|
|
16
|
-
.action(async (path: string) => {
|
|
17
|
-
const client = getClient();
|
|
18
|
-
|
|
19
|
-
const unprocessedFile = await withSpinner(
|
|
20
|
-
"Creating unprocessed file record",
|
|
21
|
-
() => createUnprocessedFileFromPath(client, path),
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
const upload = await uploadUnprocessedFile(client, unprocessedFile, path);
|
|
25
|
-
const uploadSpinner = ora("Uploading file");
|
|
26
|
-
|
|
27
|
-
for await (const event of upload) {
|
|
28
|
-
uploadSpinner.text = `Uploading file: ${(100 * event.progress).toFixed(2)}%`;
|
|
29
|
-
}
|
|
30
|
-
uploadSpinner.succeed("Upload complete");
|
|
31
|
-
const processorRecord = await withSpinner(
|
|
32
|
-
"Marking for processing",
|
|
33
|
-
async () => await processIsobmffFile(client, unprocessedFile.id),
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
const processSpinner = ora("Waiting for processing to complete");
|
|
37
|
-
processSpinner.start();
|
|
38
|
-
const progress = await getIsobmffProcessProgress(
|
|
39
|
-
client,
|
|
40
|
-
processorRecord.id,
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
for await (const event of progress) {
|
|
44
|
-
if (event.type === "progress") {
|
|
45
|
-
processSpinner.text = `Processing: ${(100 * event.data.progress).toFixed(2)}%`;
|
|
46
|
-
} else if (event.type === "complete") {
|
|
47
|
-
processSpinner.succeed("Processing complete");
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const info = await getIsobmffProcessInfo(client, processorRecord.id);
|
|
52
|
-
|
|
53
|
-
console.log("Processed file info");
|
|
54
|
-
console.log(info);
|
|
55
|
-
});
|
package/src/commands/process.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { getRenderInfo } from "@editframe/elements";
|
|
4
|
-
import { program } from "commander";
|
|
5
|
-
import { processRenderInfo } from "../operations/processRenderInfo.js";
|
|
6
|
-
import { launchBrowserAndWaitForSDK } from "../utils/launchBrowserAndWaitForSDK.js";
|
|
7
|
-
import { PreviewServer } from "../utils/startPreviewServer.js";
|
|
8
|
-
import { withSpinner } from "../utils/withSpinner.js";
|
|
9
|
-
|
|
10
|
-
program
|
|
11
|
-
.command("process [directory]")
|
|
12
|
-
.description(
|
|
13
|
-
"Process's a directory's index.html file, analyzing assets and processing them for rendering",
|
|
14
|
-
)
|
|
15
|
-
.action(async (directory) => {
|
|
16
|
-
directory ??= ".";
|
|
17
|
-
|
|
18
|
-
const distDir = path.join(directory, "dist");
|
|
19
|
-
await withSpinner("Building\n", async () => {
|
|
20
|
-
spawnSync("npx", ["vite", "build", directory], {
|
|
21
|
-
stdio: "inherit",
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const previewServer = await PreviewServer.start(distDir);
|
|
26
|
-
process.stderr.write("Preview server started at ");
|
|
27
|
-
process.stderr.write(previewServer.url);
|
|
28
|
-
process.stderr.write("\n");
|
|
29
|
-
await launchBrowserAndWaitForSDK(
|
|
30
|
-
{
|
|
31
|
-
url: previewServer.url,
|
|
32
|
-
efInteractive: false,
|
|
33
|
-
interactive: false,
|
|
34
|
-
headless: true,
|
|
35
|
-
},
|
|
36
|
-
async (page) => {
|
|
37
|
-
const renderInfo = await page.evaluate(getRenderInfo);
|
|
38
|
-
await processRenderInfo(renderInfo);
|
|
39
|
-
},
|
|
40
|
-
);
|
|
41
|
-
});
|
package/src/commands/render.ts
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
-
import path, { basename, join } from "node:path";
|
|
4
|
-
import { PassThrough } from "node:stream";
|
|
5
|
-
import { inspect } from "node:util";
|
|
6
|
-
import { createRender, uploadRender } from "@editframe/api";
|
|
7
|
-
import { md5Directory, md5FilePath } from "@editframe/assets";
|
|
8
|
-
import { getRenderInfo, RenderInfo } from "@editframe/elements";
|
|
9
|
-
import { Option, program } from "commander";
|
|
10
|
-
import debug from "debug";
|
|
11
|
-
import { parse as parseHTML } from "node-html-parser";
|
|
12
|
-
import * as tar from "tar";
|
|
13
|
-
import { processRenderInfo } from "../operations/processRenderInfo.js";
|
|
14
|
-
import { SyncStatus } from "../operations/syncAssetsDirectory/SyncStatus.js";
|
|
15
|
-
import { syncAssetDirectory } from "../operations/syncAssetsDirectory.js";
|
|
16
|
-
import { createReadableStreamFromReadable } from "../utils/createReadableStreamFromReadable.js";
|
|
17
|
-
import { getClient } from "../utils/index.js";
|
|
18
|
-
import { launchBrowserAndWaitForSDK } from "../utils/launchBrowserAndWaitForSDK.js";
|
|
19
|
-
import { PreviewServer } from "../utils/startPreviewServer.js";
|
|
20
|
-
import { validateVideoResolution } from "../utils/validateVideoResolution.js";
|
|
21
|
-
import { withSpinner } from "../utils/withSpinner.js";
|
|
22
|
-
|
|
23
|
-
const log = debug("ef:cli:render");
|
|
24
|
-
|
|
25
|
-
export const buildAssetId = async (
|
|
26
|
-
srcDir: string,
|
|
27
|
-
src: string,
|
|
28
|
-
basename: string,
|
|
29
|
-
) => {
|
|
30
|
-
log(`Building image asset id for ${src}\n`);
|
|
31
|
-
const assetPath = path.join(srcDir, src);
|
|
32
|
-
const assetMd5 = await md5FilePath(assetPath);
|
|
33
|
-
const syncStatus = new SyncStatus(
|
|
34
|
-
join(srcDir, "assets", ".cache", assetMd5, basename),
|
|
35
|
-
);
|
|
36
|
-
const info = await syncStatus.readInfo();
|
|
37
|
-
if (!info) {
|
|
38
|
-
throw new Error(`SyncStatus info is not found for ${syncStatus.infoPath}`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return info.id;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
program
|
|
45
|
-
.command("render [directory]")
|
|
46
|
-
.description(
|
|
47
|
-
"Render a directory's index.html file as a video in the editframe cloud",
|
|
48
|
-
)
|
|
49
|
-
.addOption(
|
|
50
|
-
new Option("-s, --strategy <strategy>", "Render strategy")
|
|
51
|
-
.choices(["v1"])
|
|
52
|
-
.default("v1"),
|
|
53
|
-
)
|
|
54
|
-
.action(async (directory, options) => {
|
|
55
|
-
directory ??= ".";
|
|
56
|
-
|
|
57
|
-
await syncAssetDirectory(
|
|
58
|
-
join(process.cwd(), directory, "src", "assets", ".cache"),
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
const srcDir = path.join(directory, "src");
|
|
62
|
-
const distDir = path.join(directory, "dist");
|
|
63
|
-
await withSpinner("Building\n", async () => {
|
|
64
|
-
try {
|
|
65
|
-
await withSpinner("Building\n", async () => {
|
|
66
|
-
spawnSync(
|
|
67
|
-
"npx",
|
|
68
|
-
// biome-ignore format: Grouping CLI arguments
|
|
69
|
-
[
|
|
70
|
-
"vite", "build", directory,
|
|
71
|
-
"--clearScreen", "false",
|
|
72
|
-
"--logLevel", "debug",
|
|
73
|
-
],
|
|
74
|
-
{
|
|
75
|
-
stdio: "inherit",
|
|
76
|
-
},
|
|
77
|
-
);
|
|
78
|
-
});
|
|
79
|
-
} catch (error) {
|
|
80
|
-
console.error("Build failed:", error);
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
const previewServer = await PreviewServer.start(distDir);
|
|
85
|
-
process.stderr.write("Preview server started at:");
|
|
86
|
-
process.stderr.write(previewServer.url);
|
|
87
|
-
process.stderr.write("\n");
|
|
88
|
-
await launchBrowserAndWaitForSDK(
|
|
89
|
-
{
|
|
90
|
-
url: previewServer.url,
|
|
91
|
-
efInteractive: false,
|
|
92
|
-
interactive: false,
|
|
93
|
-
headless: true,
|
|
94
|
-
},
|
|
95
|
-
async (page) => {
|
|
96
|
-
const renderInfo = RenderInfo.parse(await page.evaluate(getRenderInfo));
|
|
97
|
-
|
|
98
|
-
validateVideoResolution({
|
|
99
|
-
width: renderInfo.width,
|
|
100
|
-
height: renderInfo.height,
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
await processRenderInfo(renderInfo);
|
|
104
|
-
|
|
105
|
-
const doc = parseHTML(
|
|
106
|
-
await readFile(path.join(distDir, "index.html"), "utf-8"),
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
log("Building asset IDs");
|
|
110
|
-
for (const element of doc.querySelectorAll(
|
|
111
|
-
"ef-image, ef-audio, ef-video",
|
|
112
|
-
)) {
|
|
113
|
-
log(`Processing ${element.tagName}`);
|
|
114
|
-
if (element.hasAttribute("asset-id")) {
|
|
115
|
-
log(
|
|
116
|
-
`Asset ID for ${element.tagName} ${element.getAttribute("src")} is ${element.getAttribute("asset-id")}`,
|
|
117
|
-
);
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
const src = element.getAttribute("src");
|
|
121
|
-
if (!src) {
|
|
122
|
-
log(`No src attribute for ${element.tagName}`);
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
switch (element.tagName) {
|
|
127
|
-
case "EF-IMAGE":
|
|
128
|
-
element.setAttribute(
|
|
129
|
-
"asset-id",
|
|
130
|
-
await buildAssetId(srcDir, src, basename(src)),
|
|
131
|
-
);
|
|
132
|
-
break;
|
|
133
|
-
case "EF-AUDIO":
|
|
134
|
-
case "EF-VIDEO":
|
|
135
|
-
element.setAttribute(
|
|
136
|
-
"asset-id",
|
|
137
|
-
await buildAssetId(srcDir, src, "isobmff"),
|
|
138
|
-
);
|
|
139
|
-
break;
|
|
140
|
-
default:
|
|
141
|
-
log(`Unknown element type: ${element.tagName}`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
await writeFile(path.join(distDir, "index.html"), doc.toString());
|
|
146
|
-
|
|
147
|
-
const md5 = await md5Directory(distDir);
|
|
148
|
-
const render = await createRender(getClient(), {
|
|
149
|
-
md5,
|
|
150
|
-
width: renderInfo.width,
|
|
151
|
-
height: renderInfo.height,
|
|
152
|
-
fps: renderInfo.fps,
|
|
153
|
-
duration_ms: renderInfo.durationMs,
|
|
154
|
-
work_slice_ms: 4_000,
|
|
155
|
-
strategy: options.strategy,
|
|
156
|
-
});
|
|
157
|
-
if (render?.status !== "created") {
|
|
158
|
-
process.stderr.write(
|
|
159
|
-
`Render is in '${render?.status}' status. It cannot be recreated while in this status.\n`,
|
|
160
|
-
);
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* This tar stream is created with the dist directory as the root.
|
|
165
|
-
* This is acheived by setting the cwd option to the dist directory.
|
|
166
|
-
* And the files to be included in the tar stream are all files in the dist directory.
|
|
167
|
-
*
|
|
168
|
-
* The renderer expects to find the index.html file at the root of the tar stream.
|
|
169
|
-
*/
|
|
170
|
-
const tarStream = tar.create(
|
|
171
|
-
{
|
|
172
|
-
gzip: true,
|
|
173
|
-
cwd: distDir,
|
|
174
|
-
},
|
|
175
|
-
["."],
|
|
176
|
-
);
|
|
177
|
-
const readable = new PassThrough();
|
|
178
|
-
tarStream.pipe(readable);
|
|
179
|
-
|
|
180
|
-
await uploadRender(
|
|
181
|
-
getClient(),
|
|
182
|
-
render.id,
|
|
183
|
-
createReadableStreamFromReadable(readable),
|
|
184
|
-
);
|
|
185
|
-
process.stderr.write("Render assets uploaded\n");
|
|
186
|
-
process.stderr.write(inspect(render));
|
|
187
|
-
process.stderr.write("\n");
|
|
188
|
-
},
|
|
189
|
-
);
|
|
190
|
-
});
|
package/src/commands/sync.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
|
-
import { program } from "commander";
|
|
3
|
-
import { syncAssetDirectory } from "../operations/syncAssetsDirectory.js";
|
|
4
|
-
|
|
5
|
-
program
|
|
6
|
-
.command("sync")
|
|
7
|
-
.description("Sync assets to Editframe servers for rendering")
|
|
8
|
-
.argument("[directory]", "Path to project directory to sync.")
|
|
9
|
-
.action(async (directory = ".") => {
|
|
10
|
-
await syncAssetDirectory(
|
|
11
|
-
join(process.cwd(), directory, "src", "assets", ".cache"),
|
|
12
|
-
);
|
|
13
|
-
});
|
|
File without changes
|
package/src/commands/webhook.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { input, select } from "@inquirer/prompts";
|
|
2
|
-
import chalk from "chalk";
|
|
3
|
-
import { Option, program } from "commander";
|
|
4
|
-
import debug from "debug";
|
|
5
|
-
import ora from "ora";
|
|
6
|
-
|
|
7
|
-
import { getClient } from "../utils/index.js";
|
|
8
|
-
|
|
9
|
-
const log = debug("ef:cli:auth");
|
|
10
|
-
|
|
11
|
-
export interface APITestWebhhokResult {
|
|
12
|
-
message: string;
|
|
13
|
-
}
|
|
14
|
-
const topics = [
|
|
15
|
-
"render.created",
|
|
16
|
-
"render.rendering",
|
|
17
|
-
"render.pending",
|
|
18
|
-
"render.failed",
|
|
19
|
-
"render.completed",
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
export const testWebhookURL = async ({
|
|
23
|
-
webhookURL,
|
|
24
|
-
topic,
|
|
25
|
-
}: {
|
|
26
|
-
webhookURL: string;
|
|
27
|
-
topic: string;
|
|
28
|
-
}) => {
|
|
29
|
-
const response = await getClient().authenticatedFetch(
|
|
30
|
-
"/api/v1/test_webhook",
|
|
31
|
-
{
|
|
32
|
-
method: "POST",
|
|
33
|
-
body: JSON.stringify({
|
|
34
|
-
webhookURL,
|
|
35
|
-
topic,
|
|
36
|
-
}),
|
|
37
|
-
},
|
|
38
|
-
);
|
|
39
|
-
return response.json() as Promise<APITestWebhhokResult>;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const webhookCommand = program
|
|
43
|
-
.command("webhook")
|
|
44
|
-
.description("Test webhook URL with a topic")
|
|
45
|
-
.option("-u, --webhookURL <webhookURL>", "Webhook URL")
|
|
46
|
-
.addOption(new Option("-t, --topic <topic>", "Topic").choices(topics))
|
|
47
|
-
.action(async () => {
|
|
48
|
-
const options = webhookCommand.opts();
|
|
49
|
-
log("Options:", options);
|
|
50
|
-
let { webhookURL, topic } = options;
|
|
51
|
-
|
|
52
|
-
if (!webhookURL) {
|
|
53
|
-
const answer = await input({ message: "Enter a webhook URL:" });
|
|
54
|
-
webhookURL = answer;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (!topic) {
|
|
58
|
-
const answer = await select({
|
|
59
|
-
message: "Select a topic:",
|
|
60
|
-
choices: [...topics.map((topic) => ({ title: topic, value: topic }))],
|
|
61
|
-
});
|
|
62
|
-
topic = answer;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const spinner = ora("Testing...").start();
|
|
66
|
-
try {
|
|
67
|
-
const apiData = await testWebhookURL({ webhookURL, topic });
|
|
68
|
-
spinner.succeed("Webhook URL is working! 🎉");
|
|
69
|
-
process.stderr.write(chalk.green(`${apiData.message}\n`));
|
|
70
|
-
} catch (error: any) {
|
|
71
|
-
spinner.fail("Webhook URL is not working!");
|
|
72
|
-
process.stderr.write(error?.message);
|
|
73
|
-
process.stderr.write("\n");
|
|
74
|
-
log("Error:", error);
|
|
75
|
-
}
|
|
76
|
-
});
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
cacheImage,
|
|
3
|
-
findOrCreateCaptions,
|
|
4
|
-
generateTrack,
|
|
5
|
-
} from "@editframe/assets";
|
|
6
|
-
import type { getRenderInfo } from "@editframe/elements";
|
|
7
|
-
|
|
8
|
-
export const processRenderInfo = async (
|
|
9
|
-
renderInfo: Awaited<ReturnType<typeof getRenderInfo>>,
|
|
10
|
-
) => {
|
|
11
|
-
for (const [src, tracks] of Object.entries(renderInfo.assets.efMedia)) {
|
|
12
|
-
process.stderr.write("Processing media asset: ");
|
|
13
|
-
process.stderr.write(src);
|
|
14
|
-
process.stderr.write("\n");
|
|
15
|
-
for (const trackId in tracks) {
|
|
16
|
-
process.stderr.write("Generating track: ");
|
|
17
|
-
process.stderr.write(trackId);
|
|
18
|
-
process.stderr.write("\n");
|
|
19
|
-
await generateTrack(
|
|
20
|
-
"./src/assets",
|
|
21
|
-
`./src${src}`,
|
|
22
|
-
`src?trackId=${trackId}`,
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
for (const imageAsset of renderInfo.assets.efImage) {
|
|
28
|
-
process.stderr.write("Processing image asset: ");
|
|
29
|
-
process.stderr.write(imageAsset);
|
|
30
|
-
process.stderr.write("\n");
|
|
31
|
-
await cacheImage("./src/assets", `./src${imageAsset}`);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
for (const captionsAsset of renderInfo.assets.efCaptions) {
|
|
35
|
-
process.stderr.write("Processing captions asset: ");
|
|
36
|
-
process.stderr.write(captionsAsset);
|
|
37
|
-
process.stderr.write("\n");
|
|
38
|
-
await findOrCreateCaptions("./src/assets", `./src${captionsAsset}`);
|
|
39
|
-
}
|
|
40
|
-
};
|