@editframe/cli 0.8.0-beta.5 → 0.8.0-beta.7

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.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.8.0-beta.5";
1
+ export declare const VERSION = "0.8.0-beta.7";
package/dist/VERSION.js CHANGED
@@ -1,4 +1,4 @@
1
- const VERSION = "0.8.0-beta.5";
1
+ const VERSION = "0.8.0-beta.7";
2
2
  export {
3
3
  VERSION
4
4
  };
@@ -1,23 +1,26 @@
1
1
  import { basename } from "node:path";
2
+ import { stat } from "node:fs/promises";
3
+ import { createReadStream } from "node:fs";
2
4
  import { program } from "commander";
3
5
  import { withSpinner } from "../utils/withSpinner.js";
4
6
  import { getClient } from "../utils/index.js";
5
- import { createReadStream } from "node:fs";
6
7
  import { createUnprocessedFile, uploadUnprocessedFile, updateUnprocessedFile } from "@editframe/api";
7
8
  import { md5FilePath } from "@editframe/assets";
8
9
  program.command("process-file <file>").description("Upload a audio/video to Editframe for processing.").action(async (path) => {
9
10
  const client = getClient();
10
11
  const fileId = await md5FilePath(path);
12
+ const byte_size = (await stat(path)).size;
11
13
  await withSpinner("Creating unprocessed file record", async () => {
12
14
  await createUnprocessedFile(client, {
13
15
  id: fileId,
14
16
  processes: [],
15
- filename: basename(path)
17
+ filename: basename(path),
18
+ byte_size
16
19
  });
17
20
  });
18
21
  const readStream = createReadStream(path);
19
22
  await withSpinner("Uploading file", async () => {
20
- await uploadUnprocessedFile(client, fileId, readStream);
23
+ await uploadUnprocessedFile(client, fileId, readStream, byte_size);
21
24
  });
22
25
  const unprocessedFile = await withSpinner(
23
26
  "Marking for processing",
@@ -16,6 +16,7 @@ import { getClient } from "../utils/index.js";
16
16
  import { getRenderInfo } from "../operations/getRenderInfo.js";
17
17
  import { processRenderInfo } from "../operations/processRenderInfo.js";
18
18
  import { validateVideoResolution } from "../utils/validateVideoResolution.js";
19
+ import { getFolderSize } from "../utils/getFolderSize.js";
19
20
  const buildProductionUrl = async (origin, tagName, assetPath) => {
20
21
  const md5Sum = await md5FilePath(assetPath);
21
22
  const basename = path.basename(assetPath);
@@ -142,7 +143,8 @@ program.command("render [directory]").description(
142
143
  );
143
144
  const readable = new PassThrough();
144
145
  tarStream.pipe(readable);
145
- await uploadRender(getClient(), md5, readable);
146
+ const folderSize = await getFolderSize(distDir);
147
+ await uploadRender(getClient(), md5, readable, folderSize);
146
148
  process.stderr.write("Render assets uploaded\n");
147
149
  process.stderr.write(inspect(render));
148
150
  process.stderr.write("\n");
@@ -26,7 +26,6 @@ const testWebhookURL = async ({
26
26
  })
27
27
  }
28
28
  );
29
- console.log(response);
30
29
  return response.json();
31
30
  };
32
31
  const webhookCommand = program.command("webhook").description("Test webhook URL with a topic").option("-u, --webhookURL <webhookURL>", "Webhook URL").addOption(new Option("-t, --topic <topic>", "Topic").choices(topics)).action(async () => {
package/dist/index.d.ts CHANGED
@@ -1 +0,0 @@
1
-
@@ -1,3 +1,2 @@
1
1
  import { getRenderInfo } from './getRenderInfo.ts';
2
-
3
2
  export declare const processRenderInfo: (renderInfo: Awaited<ReturnType<typeof getRenderInfo>>) => Promise<void>;
@@ -2,7 +2,7 @@ import { Probe } from "@editframe/assets";
2
2
  import fs from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { createCaptionFile, uploadCaptionFile, createISOBMFFFile, uploadFragmentIndex, createISOBMFFTrack, uploadISOBMFFTrack, createImageFile, uploadImageFile } from "@editframe/api";
5
- import { createReadStream } from "node:fs";
5
+ import { createReadStream, statSync } from "node:fs";
6
6
  import { getClient } from "../utils/index.js";
7
7
  const imageMatch = /\.(png|jpe?g|gif|webp)$/i;
8
8
  const trackMatch = /\.track-[\d]+.mp4$/i;
@@ -76,6 +76,7 @@ const syncAssetDirectory = async (projectDirectory) => {
76
76
  case imageMatch.test(subAsset): {
77
77
  const probeResult = await Probe.probePath(subAssetPath);
78
78
  const [videoProbe] = probeResult.videoStreams;
79
+ const { format } = probeResult;
79
80
  if (!videoProbe) {
80
81
  process.stderr.write(
81
82
  `🚫 No video stream found in image: ${subAsset}
@@ -96,7 +97,8 @@ const syncAssetDirectory = async (projectDirectory) => {
96
97
  filename: subAsset,
97
98
  width: videoProbe.width,
98
99
  height: videoProbe.height,
99
- mime_type: `image/${ext}`
100
+ mime_type: `image/${ext}`,
101
+ byte_size: (await fs.stat(subAssetPath)).size
100
102
  });
101
103
  if (created) {
102
104
  if (created.complete) {
@@ -105,7 +107,8 @@ const syncAssetDirectory = async (projectDirectory) => {
105
107
  await uploadImageFile(
106
108
  getClient(),
107
109
  created.id,
108
- createReadStream(subAssetPath)
110
+ createReadStream(subAssetPath),
111
+ Number.parseInt(format.size || "0")
109
112
  );
110
113
  process.stderr.write(" ✅ Image has been synced.\n");
111
114
  }
@@ -168,14 +171,15 @@ const syncAssetDirectory = async (projectDirectory) => {
168
171
  createPayload
169
172
  );
170
173
  if (createdTrack) {
171
- if (createdTrack.last_received_byte === createdTrack.byte_size - 1) {
174
+ if (createdTrack.next_byte === createdTrack.byte_size - 1) {
172
175
  process.stderr.write(" ✔ Track has already been synced.\n");
173
176
  } else {
174
177
  await uploadISOBMFFTrack(
175
178
  getClient(),
176
179
  createdFile.id,
177
180
  Number(trackId),
178
- createReadStream(subAssetPath)
181
+ createReadStream(subAssetPath),
182
+ createdTrack.byte_size
179
183
  );
180
184
  process.stderr.write(" ✅ Track has been synced.\n");
181
185
  }
@@ -197,8 +201,14 @@ const syncAssetDirectory = async (projectDirectory) => {
197
201
  " ✔ Fragment index has already been synced.\n"
198
202
  );
199
203
  } else {
204
+ const stats = statSync(subAssetPath);
200
205
  const readStream = createReadStream(subAssetPath);
201
- await uploadFragmentIndex(getClient(), asset, readStream);
206
+ await uploadFragmentIndex(
207
+ getClient(),
208
+ asset,
209
+ readStream,
210
+ stats.size
211
+ );
202
212
  process.stderr.write(" ✅ Fragment index has been synced.\n");
203
213
  }
204
214
  await syncStatus.markSynced();
@@ -216,15 +226,28 @@ const syncAssetDirectory = async (projectDirectory) => {
216
226
  `);
217
227
  const createdFile = await createCaptionFile(getClient(), {
218
228
  id: asset,
219
- filename: subAsset.replace(/\.captions.json$/, "")
229
+ filename: subAsset.replace(/\.captions.json$/, ""),
230
+ byte_size: (await fs.stat(subAsset)).size
220
231
  });
221
232
  if (createdFile) {
222
233
  if (createdFile.complete) {
223
234
  process.stderr.write(" ✔ Captions have already been synced.\n");
224
235
  } else {
225
236
  const readStream = createReadStream(subAssetPath);
226
- await uploadCaptionFile(getClient(), asset, readStream);
227
- process.stderr.write(" ✅ Captions have been synced.\n");
237
+ const stats = statSync(subAssetPath);
238
+ await uploadCaptionFile(
239
+ getClient(),
240
+ asset,
241
+ readStream,
242
+ stats.size
243
+ ).catch((error) => {
244
+ process.stderr.write(
245
+ `🚫 Error uploading captions: ${error.message}
246
+ `
247
+ );
248
+ }).then(() => {
249
+ process.stderr.write(" ✅ Captions have been synced.\n");
250
+ });
228
251
  }
229
252
  await syncStatus.markSynced();
230
253
  } else {
@@ -1,3 +1,2 @@
1
1
  import { Page } from 'playwright';
2
-
3
2
  export declare const attachWorkbench: (page: Page) => void;
@@ -0,0 +1 @@
1
+ export declare const getFolderSize: (folderPath: string) => Promise<number>;
@@ -0,0 +1,22 @@
1
+ import { promises } from "node:fs";
2
+ import path from "node:path";
3
+ const getFolderSize = async (folderPath) => {
4
+ let totalSize = 0;
5
+ async function calculateSize(dir) {
6
+ const files = await promises.readdir(dir);
7
+ for (const file of files) {
8
+ const filePath = path.join(dir, file);
9
+ const stats = await promises.stat(filePath);
10
+ if (stats.isDirectory()) {
11
+ await calculateSize(filePath);
12
+ } else {
13
+ totalSize += stats.size;
14
+ }
15
+ }
16
+ }
17
+ await calculateSize(folderPath);
18
+ return totalSize;
19
+ };
20
+ export {
21
+ getFolderSize
22
+ };
@@ -1,3 +1,2 @@
1
1
  import { Client } from '../../../api/src';
2
-
3
2
  export declare const getClient: () => Client;
@@ -1,5 +1,4 @@
1
1
  import { Page } from 'playwright';
2
-
3
2
  interface LaunchOptions {
4
3
  url: string;
5
4
  headless?: boolean;
@@ -1,5 +1,4 @@
1
1
  import { ViteDevServer } from 'vite';
2
-
3
2
  export declare class DevServer {
4
3
  private devServer;
5
4
  static start(directory: string): Promise<DevServer>;
@@ -1,5 +1,4 @@
1
1
  import { ViteDevServer } from 'vite';
2
-
3
2
  export declare class PreviewServer {
4
3
  private previewServer;
5
4
  static start(directory: string): Promise<PreviewServer>;
@@ -3,7 +3,7 @@ type VideoPayload = {
3
3
  height: number;
4
4
  };
5
5
  export declare const validateVideoResolution: (rawPayload: VideoPayload) => Promise<{
6
- width: number;
7
6
  height: number;
7
+ width: number;
8
8
  }>;
9
9
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@editframe/cli",
3
- "version": "0.8.0-beta.5",
3
+ "version": "0.8.0-beta.7",
4
4
  "description": "Command line interface for EditFrame",
5
5
  "bin": {
6
6
  "editframe": "./dist/index.js"
@@ -19,14 +19,14 @@
19
19
  "@types/promptly": "^3.0.5",
20
20
  "@types/tar": "^6.1.13",
21
21
  "typescript": "^5.5.4",
22
- "vite-plugin-dts": "^3.9.1",
22
+ "vite-plugin-dts": "^4.0.3",
23
23
  "vite-tsconfig-paths": "^4.3.2"
24
24
  },
25
25
  "dependencies": {
26
- "@editframe/api": "0.8.0-beta.5",
27
- "@editframe/assets": "0.8.0-beta.5",
28
- "@editframe/elements": "0.8.0-beta.5",
29
- "@editframe/vite-plugin": "0.8.0-beta.5",
26
+ "@editframe/api": "0.8.0-beta.7",
27
+ "@editframe/assets": "0.8.0-beta.7",
28
+ "@editframe/elements": "0.8.0-beta.7",
29
+ "@editframe/vite-plugin": "0.8.0-beta.7",
30
30
  "axios": "^1.6.8",
31
31
  "chalk": "^5.3.0",
32
32
  "commander": "^12.0.0",
@@ -1,11 +1,12 @@
1
1
  import { basename } from "node:path";
2
+ import { stat } from "node:fs/promises";
3
+ import { createReadStream } from "node:fs";
2
4
 
3
5
  import { program } from "commander";
4
6
 
5
7
  import { withSpinner } from "../utils/withSpinner.ts";
6
8
 
7
9
  import { getClient } from "../utils/index.ts";
8
- import { createReadStream } from "node:fs";
9
10
  import {
10
11
  createUnprocessedFile,
11
12
  updateUnprocessedFile,
@@ -21,18 +22,21 @@ program
21
22
 
22
23
  const fileId = await md5FilePath(path);
23
24
 
25
+ const byte_size = (await stat(path)).size;
26
+
24
27
  await withSpinner("Creating unprocessed file record", async () => {
25
28
  await createUnprocessedFile(client, {
26
29
  id: fileId,
27
30
  processes: [],
28
31
  filename: basename(path),
32
+ byte_size,
29
33
  });
30
34
  });
31
35
 
32
36
  const readStream = createReadStream(path);
33
37
 
34
38
  await withSpinner("Uploading file", async () => {
35
- await uploadUnprocessedFile(client, fileId, readStream);
39
+ await uploadUnprocessedFile(client, fileId, readStream, byte_size);
36
40
  });
37
41
 
38
42
  const unprocessedFile = await withSpinner(
@@ -19,6 +19,7 @@ import { getClient } from "../utils/index.ts";
19
19
  import { getRenderInfo } from "../operations/getRenderInfo.ts";
20
20
  import { processRenderInfo } from "../operations/processRenderInfo.ts";
21
21
  import { validateVideoResolution } from "../utils/validateVideoResolution.ts";
22
+ import { getFolderSize } from "../utils/getFolderSize.ts";
22
23
 
23
24
  interface StrategyBuilder {
24
25
  buildProductionUrl: (tagName: string, assetPath: string) => Promise<string>;
@@ -179,7 +180,8 @@ program
179
180
  );
180
181
  const readable = new PassThrough();
181
182
  tarStream.pipe(readable);
182
- await uploadRender(getClient(), md5, readable);
183
+ const folderSize = await getFolderSize(distDir);
184
+ await uploadRender(getClient(), md5, readable, folderSize);
183
185
  process.stderr.write("Render assets uploaded\n");
184
186
  process.stderr.write(inspect(render));
185
187
  process.stderr.write("\n");
@@ -36,7 +36,6 @@ export const testWebhookURL = async ({
36
36
  }),
37
37
  },
38
38
  );
39
- console.log(response);
40
39
  return response.json() as Promise<APITestWebhhokResult>;
41
40
  };
42
41
 
@@ -12,6 +12,7 @@ import {
12
12
  uploadISOBMFFTrack,
13
13
  type CreateISOBMFFTrackPayload,
14
14
  } from "@editframe/api";
15
+ import { statSync } from "node:fs";
15
16
 
16
17
  import { createReadStream } from "node:fs";
17
18
  import type { z } from "zod";
@@ -97,6 +98,7 @@ export const syncAssetDirectory = async (
97
98
  case imageMatch.test(subAsset): {
98
99
  const probeResult = await Probe.probePath(subAssetPath);
99
100
  const [videoProbe] = probeResult.videoStreams;
101
+ const { format } = probeResult;
100
102
  if (!videoProbe) {
101
103
  process.stderr.write(
102
104
  `🚫 No video stream found in image: ${subAsset}\n`,
@@ -122,6 +124,7 @@ export const syncAssetDirectory = async (
122
124
  width: videoProbe.width,
123
125
  height: videoProbe.height,
124
126
  mime_type: `image/${ext}`,
127
+ byte_size: (await fs.stat(subAssetPath)).size,
125
128
  });
126
129
  if (created) {
127
130
  if (created.complete) {
@@ -131,6 +134,7 @@ export const syncAssetDirectory = async (
131
134
  getClient(),
132
135
  created.id,
133
136
  createReadStream(subAssetPath),
137
+ Number.parseInt(format.size || "0"),
134
138
  );
135
139
  process.stderr.write(" ✅ Image has been synced.\n");
136
140
  }
@@ -170,7 +174,7 @@ export const syncAssetDirectory = async (
170
174
  const stat = await fs.stat(subAssetPath);
171
175
 
172
176
  /**
173
- * Because the payload is a discriminated union, we nede to create these objects
177
+ * Because the payload is a discriminated union, we need to create these objects
174
178
  * only after the value for type has been narrowed, otherwise the object will
175
179
  * have type: "audio" | "video" which doesnt' match the payload type that
176
180
  * looks more like { type: "audio", ... } | { type: "video", ... }
@@ -201,10 +205,7 @@ export const syncAssetDirectory = async (
201
205
  );
202
206
 
203
207
  if (createdTrack) {
204
- if (
205
- createdTrack.last_received_byte ===
206
- createdTrack.byte_size - 1
207
- ) {
208
+ if (createdTrack.next_byte === createdTrack.byte_size - 1) {
208
209
  process.stderr.write(" ✔ Track has already been synced.\n");
209
210
  } else {
210
211
  await uploadISOBMFFTrack(
@@ -212,6 +213,7 @@ export const syncAssetDirectory = async (
212
213
  createdFile.id,
213
214
  Number(trackId),
214
215
  createReadStream(subAssetPath),
216
+ createdTrack.byte_size,
215
217
  );
216
218
  process.stderr.write(" ✅ Track has been synced.\n");
217
219
  }
@@ -233,8 +235,14 @@ export const syncAssetDirectory = async (
233
235
  " ✔ Fragment index has already been synced.\n",
234
236
  );
235
237
  } else {
238
+ const stats = statSync(subAssetPath);
236
239
  const readStream = createReadStream(subAssetPath);
237
- await uploadFragmentIndex(getClient(), asset, readStream);
240
+ await uploadFragmentIndex(
241
+ getClient(),
242
+ asset,
243
+ readStream,
244
+ stats.size,
245
+ );
238
246
  process.stderr.write(" ✅ Fragment index has been synced.\n");
239
247
  }
240
248
  await syncStatus.markSynced();
@@ -251,14 +259,28 @@ export const syncAssetDirectory = async (
251
259
  const createdFile = await createCaptionFile(getClient(), {
252
260
  id: asset,
253
261
  filename: subAsset.replace(/\.captions.json$/, ""),
262
+ byte_size: (await fs.stat(subAsset)).size,
254
263
  });
255
264
  if (createdFile) {
256
265
  if (createdFile.complete) {
257
266
  process.stderr.write(" ✔ Captions have already been synced.\n");
258
267
  } else {
259
268
  const readStream = createReadStream(subAssetPath);
260
- await uploadCaptionFile(getClient(), asset, readStream);
261
- process.stderr.write(" ✅ Captions have been synced.\n");
269
+ const stats = statSync(subAssetPath);
270
+ await uploadCaptionFile(
271
+ getClient(),
272
+ asset,
273
+ readStream,
274
+ stats.size,
275
+ )
276
+ .catch((error) => {
277
+ process.stderr.write(
278
+ `🚫 Error uploading captions: ${error.message}\n`,
279
+ );
280
+ })
281
+ .then(() => {
282
+ process.stderr.write(" ✅ Captions have been synced.\n");
283
+ });
262
284
  }
263
285
  await syncStatus.markSynced();
264
286
  } else {
@@ -0,0 +1,24 @@
1
+ import { promises as fs } from "node:fs";
2
+ import path from "node:path";
3
+
4
+ export const getFolderSize = async (folderPath: string): Promise<number> => {
5
+ let totalSize = 0;
6
+
7
+ async function calculateSize(dir: string): Promise<void> {
8
+ const files = await fs.readdir(dir);
9
+
10
+ for (const file of files) {
11
+ const filePath = path.join(dir, file);
12
+ const stats = await fs.stat(filePath);
13
+
14
+ if (stats.isDirectory()) {
15
+ await calculateSize(filePath);
16
+ } else {
17
+ totalSize += stats.size;
18
+ }
19
+ }
20
+ }
21
+
22
+ await calculateSize(folderPath);
23
+ return totalSize;
24
+ };