@editframe/cli 0.11.0-beta.9 → 0.12.0-beta.2

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.
Files changed (37) hide show
  1. package/dist/VERSION.d.ts +1 -1
  2. package/dist/VERSION.js +1 -1
  3. package/dist/commands/process-file.js +32 -21
  4. package/dist/commands/render.js +8 -2
  5. package/dist/operations/syncAssetsDirectory/SubAssetSync.js +3 -0
  6. package/dist/operations/syncAssetsDirectory/SyncCaption.d.ts +2 -2
  7. package/dist/operations/syncAssetsDirectory/SyncCaption.js +19 -8
  8. package/dist/operations/syncAssetsDirectory/SyncFragmentIndex.d.ts +2 -2
  9. package/dist/operations/syncAssetsDirectory/SyncFragmentIndex.js +19 -12
  10. package/dist/operations/syncAssetsDirectory/SyncImage.d.ts +2 -2
  11. package/dist/operations/syncAssetsDirectory/SyncImage.js +16 -11
  12. package/dist/operations/syncAssetsDirectory/SyncStatus.d.ts +7 -11
  13. package/dist/operations/syncAssetsDirectory/SyncStatus.js +1 -1
  14. package/dist/operations/syncAssetsDirectory/SyncTrack.d.ts +2 -2
  15. package/dist/operations/syncAssetsDirectory/SyncTrack.js +14 -12
  16. package/dist/utils/createReadableStreamFromReadable.d.ts +4 -0
  17. package/dist/utils/createReadableStreamFromReadable.js +82 -0
  18. package/dist/utils/launchBrowserAndWaitForSDK.js +2 -2
  19. package/package.json +5 -5
  20. package/src/commands/process-file.ts +36 -22
  21. package/src/commands/render.ts +9 -2
  22. package/src/operations/syncAssetsDirectory/SubAssetSync.ts +4 -0
  23. package/src/operations/syncAssetsDirectory/SyncCaption.test.ts +29 -3
  24. package/src/operations/syncAssetsDirectory/SyncCaption.ts +22 -9
  25. package/src/operations/syncAssetsDirectory/SyncFragmentIndex.test.ts +30 -4
  26. package/src/operations/syncAssetsDirectory/SyncFragmentIndex.ts +22 -13
  27. package/src/operations/syncAssetsDirectory/SyncImage.test.ts +27 -3
  28. package/src/operations/syncAssetsDirectory/SyncImage.ts +23 -15
  29. package/src/operations/syncAssetsDirectory/SyncStatus.ts +3 -3
  30. package/src/operations/syncAssetsDirectory/SyncTrack.test.ts +38 -3
  31. package/src/operations/syncAssetsDirectory/SyncTrack.ts +20 -13
  32. package/src/operations/syncAssetsDirectory.test.ts +22 -1
  33. package/src/utils/createReadableStreamFromReadable.ts +117 -0
  34. package/src/utils/launchBrowserAndWaitForSDK.ts +2 -2
  35. package/src/utils/startDevServer.ts +1 -1
  36. package/test-fixtures/fixture.ts +0 -1
  37. package/test-fixtures/network.ts +72 -29
package/dist/VERSION.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.11.0-beta.9";
1
+ export declare const VERSION = "0.12.0-beta.2";
package/dist/VERSION.js CHANGED
@@ -1,4 +1,4 @@
1
- const VERSION = "0.11.0-beta.9";
1
+ const VERSION = "0.12.0-beta.2";
2
2
  export {
3
3
  VERSION
4
4
  };
@@ -1,11 +1,13 @@
1
- import { basename } from "node:path";
2
- import { stat } from "node:fs/promises";
3
1
  import { createReadStream } from "node:fs";
2
+ import { stat } from "node:fs/promises";
3
+ import { basename } from "node:path";
4
4
  import { program } from "commander";
5
5
  import { withSpinner } from "../utils/withSpinner.js";
6
- import { getClient } from "../utils/index.js";
7
- import { createUnprocessedFile, uploadUnprocessedFile, updateUnprocessedFile } from "@editframe/api";
6
+ import { uploadUnprocessedFile, getIsobmffProcessProgress, getIsobmffProcessInfo, createUnprocessedFile, processIsobmffFile } from "@editframe/api";
8
7
  import { md5FilePath } from "@editframe/assets";
8
+ import ora from "ora";
9
+ import { createReadableStreamFromReadable } from "../utils/createReadableStreamFromReadable.js";
10
+ import { getClient } from "../utils/index.js";
9
11
  program.command("process-file <file>").description("Upload a audio/video to Editframe for processing.").action(async (path) => {
10
12
  const client = getClient();
11
13
  const md5 = await md5FilePath(path);
@@ -14,28 +16,37 @@ program.command("process-file <file>").description("Upload a audio/video to Edit
14
16
  "Creating unprocessed file record",
15
17
  async () => await createUnprocessedFile(client, {
16
18
  md5,
17
- processes: [],
18
19
  filename: basename(path),
19
20
  byte_size
20
21
  })
21
22
  );
22
23
  const readStream = createReadStream(path);
23
- await withSpinner("Uploading file", async () => {
24
- await uploadUnprocessedFile(
25
- client,
26
- unprocessedFile.id,
27
- readStream,
28
- byte_size
29
- );
30
- });
31
- const updatedUnprocessedFile = await withSpinner(
24
+ const upload = uploadUnprocessedFile(
25
+ client,
26
+ unprocessedFile.id,
27
+ createReadableStreamFromReadable(readStream),
28
+ byte_size
29
+ );
30
+ const uploadSpinner = ora("Uploading file");
31
+ for await (const event of upload) {
32
+ uploadSpinner.text = `Uploading file: ${(100 * event.progress).toFixed(2)}%`;
33
+ }
34
+ uploadSpinner.succeed("Upload complete");
35
+ const processor = await withSpinner(
32
36
  "Marking for processing",
33
- async () => {
34
- return await updateUnprocessedFile(client, unprocessedFile.id, {
35
- processes: ["isobmff"]
36
- });
37
- }
37
+ async () => await processIsobmffFile(client, unprocessedFile.id)
38
38
  );
39
- process.stderr.write("File uploaded and marked for processing.\n");
40
- console.log(JSON.stringify(updatedUnprocessedFile, null, 2));
39
+ const processSpinner = ora("Waiting for processing to complete");
40
+ processSpinner.start();
41
+ const progress = await getIsobmffProcessProgress(client, processor.id);
42
+ for await (const event of progress) {
43
+ if (event.type === "progress") {
44
+ processSpinner.text = `Processing: ${(100 * event.data.progress).toFixed(2)}%`;
45
+ } else if (event.type === "complete") {
46
+ processSpinner.succeed("Processing complete");
47
+ }
48
+ }
49
+ const info = await getIsobmffProcessInfo(client, processor.id);
50
+ console.log("Processed file info");
51
+ console.log(info);
41
52
  });
@@ -13,6 +13,7 @@ import { RenderInfo, getRenderInfo } from "../operations/getRenderInfo.js";
13
13
  import { processRenderInfo } from "../operations/processRenderInfo.js";
14
14
  import { syncAssetDirectory } from "../operations/syncAssetsDirectory.js";
15
15
  import { SyncStatus } from "../operations/syncAssetsDirectory/SyncStatus.js";
16
+ import { createReadableStreamFromReadable } from "../utils/createReadableStreamFromReadable.js";
16
17
  import { getFolderSize } from "../utils/getFolderSize.js";
17
18
  import { getClient } from "../utils/index.js";
18
19
  import { launchBrowserAndWaitForSDK } from "../utils/launchBrowserAndWaitForSDK.js";
@@ -32,7 +33,7 @@ const buildAssetId = async (srcDir, src, basename2) => {
32
33
  if (!info) {
33
34
  throw new Error(`SyncStatus info is not found for ${syncStatus.infoPath}`);
34
35
  }
35
- return info.asset_id;
36
+ return info.id;
36
37
  };
37
38
  program.command("render [directory]").description(
38
39
  "Render a directory's index.html file as a video in the editframe cloud"
@@ -152,7 +153,12 @@ program.command("render [directory]").description(
152
153
  const readable = new PassThrough();
153
154
  tarStream.pipe(readable);
154
155
  const folderSize = await getFolderSize(distDir);
155
- await uploadRender(getClient(), render.id, readable, folderSize);
156
+ await uploadRender(
157
+ getClient(),
158
+ render.id,
159
+ createReadableStreamFromReadable(readable),
160
+ folderSize
161
+ );
156
162
  process.stderr.write("Render assets uploaded\n");
157
163
  process.stderr.write(inspect(render));
158
164
  process.stderr.write("\n");
@@ -1,3 +1,4 @@
1
+ import debug from "debug";
1
2
  import { SyncCaption } from "./SyncCaption.js";
2
3
  import { SyncFragmentIndex } from "./SyncFragmentIndex.js";
3
4
  import { SyncImage } from "./SyncImage.js";
@@ -6,7 +7,9 @@ const trackMatch = /\.track-[\d]+.mp4$/i;
6
7
  const fragmentIndexMatch = /\.tracks.json$/i;
7
8
  const captionsMatch = /\.captions.json$/i;
8
9
  const imageMatch = /\.(png|jpe?g|gif|webp)$/i;
10
+ const log = debug("ef:SubAssetSync");
9
11
  const getAssetSync = (subAssetPath, md5) => {
12
+ log("getAssetSync", { subAssetPath, md5 });
10
13
  if (imageMatch.test(subAssetPath)) {
11
14
  return new SyncImage(subAssetPath, md5);
12
15
  }
@@ -1,4 +1,4 @@
1
- import { CreateCaptionFileResult } from '../../../../api/src/index.ts';
1
+ import { CreateCaptionFileResult, LookupCaptionFileByMd5Result } from '../../../../api/src/index.ts';
2
2
  import { SubAssetSync } from './SubAssetSync.ts';
3
3
  import { SyncStatus } from './SyncStatus.ts';
4
4
  export declare class SyncCaption implements SubAssetSync<CreateCaptionFileResult> {
@@ -7,7 +7,7 @@ export declare class SyncCaption implements SubAssetSync<CreateCaptionFileResult
7
7
  icon: string;
8
8
  label: string;
9
9
  syncStatus: SyncStatus;
10
- created: CreateCaptionFileResult | null;
10
+ created: CreateCaptionFileResult | LookupCaptionFileByMd5Result | null;
11
11
  constructor(path: string, md5: string);
12
12
  byteSize(): Promise<number>;
13
13
  prepare(): Promise<void>;
@@ -1,7 +1,9 @@
1
1
  import fs from "node:fs/promises";
2
- import { createCaptionFile, uploadCaptionFile } from "@editframe/api";
2
+ import { lookupCaptionFileByMd5, createCaptionFile, uploadCaptionFile } from "@editframe/api";
3
3
  import { Readable } from "node:stream";
4
4
  import { getClient } from "../../utils/index.js";
5
+ import { basename } from "node:path";
6
+ import { createReadableStreamFromReadable } from "../../utils/createReadableStreamFromReadable.js";
5
7
  import { SyncStatus } from "./SyncStatus.js";
6
8
  class SyncCaption {
7
9
  constructor(path, md5) {
@@ -20,11 +22,19 @@ class SyncCaption {
20
22
  async validate() {
21
23
  }
22
24
  async create() {
23
- this.created = await createCaptionFile(getClient(), {
24
- md5: this.md5,
25
- filename: this.path.replace(/\.captions.json$/, ""),
26
- byte_size: await this.byteSize()
27
- });
25
+ const maybeCaptionFile = await lookupCaptionFileByMd5(
26
+ getClient(),
27
+ this.md5
28
+ );
29
+ if (maybeCaptionFile) {
30
+ this.created = maybeCaptionFile;
31
+ } else {
32
+ this.created = await createCaptionFile(getClient(), {
33
+ md5: this.md5,
34
+ filename: basename(this.path).replace(/\.captions.json$/, ""),
35
+ byte_size: await this.byteSize()
36
+ });
37
+ }
28
38
  }
29
39
  isComplete() {
30
40
  return !!this.created?.complete;
@@ -40,7 +50,9 @@ class SyncCaption {
40
50
  this.created.id,
41
51
  // It's not clear why we need to use Readable.from here, but it seems
42
52
  // to fix an issue where the request is closed early in tests
43
- Readable.from(await fs.readFile(this.path)),
53
+ createReadableStreamFromReadable(
54
+ Readable.from(await fs.readFile(this.path))
55
+ ),
44
56
  await this.byteSize()
45
57
  );
46
58
  }
@@ -56,7 +68,6 @@ class SyncCaption {
56
68
  complete: true,
57
69
  id: this.created.id,
58
70
  md5: this.md5,
59
- asset_id: this.created.asset_id,
60
71
  byte_size: byteSize
61
72
  });
62
73
  }
@@ -1,4 +1,4 @@
1
- import { CreateISOBMFFFileResult } from '../../../../api/src/index.ts';
1
+ import { CreateISOBMFFFileResult, LookupISOBMFFFileByMd5Result } from '../../../../api/src/index.ts';
2
2
  import { SubAssetSync } from './SubAssetSync.ts';
3
3
  import { SyncStatus } from './SyncStatus.ts';
4
4
  export declare class SyncFragmentIndex implements SubAssetSync<CreateISOBMFFFileResult> {
@@ -8,7 +8,7 @@ export declare class SyncFragmentIndex implements SubAssetSync<CreateISOBMFFFile
8
8
  label: string;
9
9
  syncStatus: SyncStatus;
10
10
  fileSyncStatus: SyncStatus;
11
- created: CreateISOBMFFFileResult | null;
11
+ created: CreateISOBMFFFileResult | LookupISOBMFFFileByMd5Result | null;
12
12
  constructor(path: string, md5: string);
13
13
  byteSize(): Promise<number>;
14
14
  prepare(): Promise<void>;
@@ -1,7 +1,8 @@
1
1
  import fs from "node:fs/promises";
2
- import { join, dirname } from "node:path";
2
+ import { join, dirname, basename } from "node:path";
3
3
  import { Readable } from "node:stream";
4
- import { createISOBMFFFile, uploadFragmentIndex } from "@editframe/api";
4
+ import { lookupISOBMFFFileByMd5, createISOBMFFFile, uploadFragmentIndex } from "@editframe/api";
5
+ import { createReadableStreamFromReadable } from "../../utils/createReadableStreamFromReadable.js";
5
6
  import { getClient } from "../../utils/index.js";
6
7
  import { SyncStatus } from "./SyncStatus.js";
7
8
  class SyncFragmentIndex {
@@ -11,9 +12,7 @@ class SyncFragmentIndex {
11
12
  this.icon = "📋";
12
13
  this.label = "fragment index";
13
14
  this.syncStatus = new SyncStatus(this.path);
14
- this.fileSyncStatus = new SyncStatus(
15
- join(dirname(this.path), "isobmff")
16
- );
15
+ this.fileSyncStatus = new SyncStatus(join(dirname(this.path), "isobmff"));
17
16
  this.created = null;
18
17
  }
19
18
  async byteSize() {
@@ -24,10 +23,18 @@ class SyncFragmentIndex {
24
23
  async validate() {
25
24
  }
26
25
  async create() {
27
- this.created = await createISOBMFFFile(getClient(), {
28
- md5: this.md5,
29
- filename: this.path.replace(/\.tracks.json$/, "")
30
- });
26
+ const maybeISOBMFFFile = await lookupISOBMFFFileByMd5(
27
+ getClient(),
28
+ this.md5
29
+ );
30
+ if (maybeISOBMFFFile) {
31
+ this.created = maybeISOBMFFFile;
32
+ } else {
33
+ this.created = await createISOBMFFFile(getClient(), {
34
+ md5: this.md5,
35
+ filename: basename(this.path).replace(/\.tracks.json$/, "")
36
+ });
37
+ }
31
38
  }
32
39
  isComplete() {
33
40
  return !!this.created?.fragment_index_complete;
@@ -43,7 +50,9 @@ class SyncFragmentIndex {
43
50
  this.created.id,
44
51
  // It is unclear why we need to use Readable.from here
45
52
  // Tests fail when using createReadStream
46
- Readable.from(await fs.readFile(this.path)),
53
+ createReadableStreamFromReadable(
54
+ Readable.from(await fs.readFile(this.path))
55
+ ),
47
56
  await this.byteSize()
48
57
  );
49
58
  }
@@ -60,7 +69,6 @@ class SyncFragmentIndex {
60
69
  complete: true,
61
70
  id: this.created.id,
62
71
  md5: this.md5,
63
- asset_id: this.created.asset_id,
64
72
  byte_size: byteSize
65
73
  }),
66
74
  this.fileSyncStatus.markSynced({
@@ -68,7 +76,6 @@ class SyncFragmentIndex {
68
76
  complete: true,
69
77
  id: this.created.id,
70
78
  md5: this.md5,
71
- asset_id: this.created.asset_id,
72
79
  byte_size: byteSize
73
80
  })
74
81
  ]);
@@ -1,4 +1,4 @@
1
- import { CreateImageFileResult } from '../../../../api/src/index.ts';
1
+ import { CreateImageFileResult, LookupImageFileByMd5Result } from '../../../../api/src/index.ts';
2
2
  import { Probe } from '../../../../assets/src/index.ts';
3
3
  import { SubAssetSync } from './SubAssetSync.ts';
4
4
  import { SyncStatus } from './SyncStatus.ts';
@@ -8,7 +8,7 @@ export declare class SyncImage implements SubAssetSync<CreateImageFileResult> {
8
8
  icon: string;
9
9
  label: string;
10
10
  syncStatus: SyncStatus;
11
- created: CreateImageFileResult | null;
11
+ created: CreateImageFileResult | LookupImageFileByMd5Result | null;
12
12
  constructor(path: string, md5: string);
13
13
  private _probeResult;
14
14
  prepare(): Promise<void>;
@@ -1,8 +1,9 @@
1
1
  import { createReadStream } from "node:fs";
2
2
  import fs from "node:fs/promises";
3
3
  import path, { basename } from "node:path";
4
- import { createImageFile, uploadImageFile } from "@editframe/api";
4
+ import { lookupImageFileByMd5, createImageFile, uploadImageFile } from "@editframe/api";
5
5
  import { Probe } from "@editframe/assets";
6
+ import { createReadableStreamFromReadable } from "../../utils/createReadableStreamFromReadable.js";
6
7
  import { getClient } from "../../utils/index.js";
7
8
  import { SyncStatus } from "./SyncStatus.js";
8
9
  class SyncImage {
@@ -48,14 +49,19 @@ class SyncImage {
48
49
  "No video stream found in image. Should have been prevented by .validate()"
49
50
  );
50
51
  }
51
- this.created = await createImageFile(getClient(), {
52
- md5: this.md5,
53
- filename: basename(this.path),
54
- width: videoProbe.width,
55
- height: videoProbe.height,
56
- mime_type: `image/${this.extension}`,
57
- byte_size: byteSize
58
- });
52
+ const maybeImageFile = await lookupImageFileByMd5(getClient(), this.md5);
53
+ if (maybeImageFile) {
54
+ this.created = maybeImageFile;
55
+ } else {
56
+ this.created = await createImageFile(getClient(), {
57
+ md5: this.md5,
58
+ filename: basename(this.path),
59
+ width: videoProbe.width,
60
+ height: videoProbe.height,
61
+ mime_type: `image/${this.extension}`,
62
+ byte_size: byteSize
63
+ });
64
+ }
59
65
  }
60
66
  isComplete() {
61
67
  return !!this.created?.complete;
@@ -69,7 +75,7 @@ class SyncImage {
69
75
  await uploadImageFile(
70
76
  getClient(),
71
77
  this.created.id,
72
- createReadStream(this.path),
78
+ createReadableStreamFromReadable(createReadStream(this.path)),
73
79
  Number.parseInt(this.probeResult.format.size || "0")
74
80
  ).whenUploaded();
75
81
  }
@@ -85,7 +91,6 @@ class SyncImage {
85
91
  complete: true,
86
92
  id: this.created.id,
87
93
  md5: this.md5,
88
- asset_id: this.created.asset_id,
89
94
  byte_size: byteSize
90
95
  });
91
96
  }
@@ -4,37 +4,33 @@ declare const SyncStatusSchema: z.ZodObject<{
4
4
  complete: z.ZodBoolean;
5
5
  id: z.ZodString;
6
6
  md5: z.ZodString;
7
- asset_id: z.ZodString;
8
7
  byte_size: z.ZodNumber;
9
8
  }, "strip", z.ZodTypeAny, {
9
+ complete: boolean;
10
+ id: string;
10
11
  md5: string;
11
12
  byte_size: number;
12
- complete: boolean;
13
13
  version: string;
14
- id: string;
15
- asset_id: string;
16
14
  }, {
15
+ complete: boolean;
16
+ id: string;
17
17
  md5: string;
18
18
  byte_size: number;
19
- complete: boolean;
20
19
  version: string;
21
- id: string;
22
- asset_id: string;
23
20
  }>;
24
21
  export interface SyncStatusInfo extends z.infer<typeof SyncStatusSchema> {
25
22
  }
26
23
  export declare class SyncStatus {
27
24
  private basePath;
28
- constructor(basePath: string);
29
25
  infoPath: string;
26
+ constructor(basePath: string);
30
27
  isSynced(): Promise<boolean>;
31
28
  readInfo(): Promise<{
29
+ complete: boolean;
30
+ id: string;
32
31
  md5: string;
33
32
  byte_size: number;
34
- complete: boolean;
35
33
  version: string;
36
- id: string;
37
- asset_id: string;
38
34
  } | null>;
39
35
  markSynced(info: SyncStatusInfo): Promise<void>;
40
36
  }
@@ -6,7 +6,6 @@ const SyncStatusSchema = z.object({
6
6
  complete: z.boolean(),
7
7
  id: z.string(),
8
8
  md5: z.string(),
9
- asset_id: z.string(),
10
9
  byte_size: z.number()
11
10
  });
12
11
  class SyncStatus {
@@ -19,6 +18,7 @@ class SyncStatus {
19
18
  if (!syncInfo) {
20
19
  return false;
21
20
  }
21
+ console.log("syncInfo.infoPath", this.infoPath);
22
22
  return syncInfo.version === SYNC_VERSION && syncInfo.complete;
23
23
  }
24
24
  async readInfo() {
@@ -1,4 +1,4 @@
1
- import { CreateISOBMFFFileResult, CreateISOBMFFTrackResult } from '../../../../api/src/index.ts';
1
+ import { CreateISOBMFFFileResult, CreateISOBMFFTrackResult, LookupISOBMFFFileByMd5Result } from '../../../../api/src/index.ts';
2
2
  import { Probe } from '../../../../assets/src/index.ts';
3
3
  import { SubAssetSync } from './SubAssetSync.ts';
4
4
  import { SyncStatus } from './SyncStatus.ts';
@@ -12,7 +12,7 @@ export declare class SyncTrack implements SubAssetSync<CreateISOBMFFTrackResult>
12
12
  created: CreateISOBMFFTrackResult | null;
13
13
  constructor(path: string, md5: string);
14
14
  private _isoFile;
15
- get isoFile(): CreateISOBMFFFileResult;
15
+ get isoFile(): CreateISOBMFFFileResult | LookupISOBMFFFileByMd5Result;
16
16
  byteSize(): Promise<number>;
17
17
  private _probeResult;
18
18
  get probeResult(): Probe;
@@ -1,8 +1,9 @@
1
1
  import { createReadStream } from "node:fs";
2
2
  import fs from "node:fs/promises";
3
- import { join, dirname } from "node:path";
4
- import { createISOBMFFFile, createISOBMFFTrack, uploadISOBMFFTrack } from "@editframe/api";
3
+ import { join, dirname, basename } from "node:path";
4
+ import { lookupISOBMFFFileByMd5, createISOBMFFFile, createISOBMFFTrack, uploadISOBMFFTrack } from "@editframe/api";
5
5
  import { Probe } from "@editframe/assets";
6
+ import { createReadableStreamFromReadable } from "../../utils/createReadableStreamFromReadable.js";
6
7
  import { getClient } from "../../utils/index.js";
7
8
  import { SyncStatus } from "./SyncStatus.js";
8
9
  class SyncTrack {
@@ -12,9 +13,7 @@ class SyncTrack {
12
13
  this.icon = "📼";
13
14
  this.label = "track";
14
15
  this.syncStatus = new SyncStatus(this.path);
15
- this.fileSyncStatus = new SyncStatus(
16
- join(dirname(this.path), "isobmff")
17
- );
16
+ this.fileSyncStatus = new SyncStatus(join(dirname(this.path), "isobmff"));
18
17
  this.created = null;
19
18
  this._isoFile = null;
20
19
  this._probeResult = null;
@@ -42,10 +41,15 @@ class SyncTrack {
42
41
  throw new Error(`No track found in track: ${this.path}`);
43
42
  }
44
43
  async prepare() {
45
- this._isoFile = await createISOBMFFFile(getClient(), {
46
- md5: this.md5,
47
- filename: this.path.replace(/\.track-[\d]+.mp4$/, "")
48
- });
44
+ const maybeIsoFile = await lookupISOBMFFFileByMd5(getClient(), this.md5);
45
+ if (maybeIsoFile) {
46
+ this._isoFile = maybeIsoFile;
47
+ } else {
48
+ this._isoFile = await createISOBMFFFile(getClient(), {
49
+ md5: this.md5,
50
+ filename: basename(this.path).replace(/\.track-[\d]+.mp4$/, "")
51
+ });
52
+ }
49
53
  this._probeResult = await Probe.probePath(this.path);
50
54
  }
51
55
  get trackId() {
@@ -102,7 +106,7 @@ class SyncTrack {
102
106
  getClient(),
103
107
  this.isoFile.id,
104
108
  Number(this.trackId),
105
- createReadStream(this.path),
109
+ createReadableStreamFromReadable(createReadStream(this.path)),
106
110
  this.created?.byte_size
107
111
  ).whenUploaded();
108
112
  }
@@ -119,7 +123,6 @@ class SyncTrack {
119
123
  complete: true,
120
124
  id: `${this.created.file_id}:${this.created.track_id}`,
121
125
  md5: this.md5,
122
- asset_id: this.created.asset_id,
123
126
  byte_size: byteSize
124
127
  }),
125
128
  this.fileSyncStatus.markSynced({
@@ -127,7 +130,6 @@ class SyncTrack {
127
130
  complete: true,
128
131
  id: this.created.file_id,
129
132
  md5: this.md5,
130
- asset_id: this.created.asset_id,
131
133
  byte_size: byteSize
132
134
  })
133
135
  ]);
@@ -0,0 +1,4 @@
1
+ import { Readable } from 'node:stream';
2
+ export declare const createReadableStreamFromReadable: (source: Readable & {
3
+ readableHighWaterMark?: number;
4
+ }) => ReadableStream<Uint8Array>;
@@ -0,0 +1,82 @@
1
+ import { Stream } from "node:stream";
2
+ const createReadableStreamFromReadable = (source) => {
3
+ const pump = new StreamPump(source);
4
+ const stream = new ReadableStream(pump, pump);
5
+ return stream;
6
+ };
7
+ class StreamPump {
8
+ constructor(stream) {
9
+ this.highWaterMark = stream.readableHighWaterMark || new Stream.Readable().readableHighWaterMark;
10
+ this.accumalatedSize = 0;
11
+ this.stream = stream;
12
+ this.enqueue = this.enqueue.bind(this);
13
+ this.error = this.error.bind(this);
14
+ this.close = this.close.bind(this);
15
+ }
16
+ size(chunk) {
17
+ return chunk?.byteLength || 0;
18
+ }
19
+ start(controller) {
20
+ this.controller = controller;
21
+ this.stream.on("data", this.enqueue);
22
+ this.stream.once("error", this.error);
23
+ this.stream.once("end", this.close);
24
+ this.stream.once("close", this.close);
25
+ }
26
+ pull() {
27
+ this.resume();
28
+ }
29
+ cancel(reason) {
30
+ if (this.stream.destroy) {
31
+ this.stream.destroy(reason);
32
+ }
33
+ this.stream.off("data", this.enqueue);
34
+ this.stream.off("error", this.error);
35
+ this.stream.off("end", this.close);
36
+ this.stream.off("close", this.close);
37
+ }
38
+ enqueue(chunk) {
39
+ if (this.controller) {
40
+ try {
41
+ const bytes = chunk instanceof Uint8Array ? chunk : Buffer.from(chunk);
42
+ const available = (this.controller.desiredSize || 0) - bytes.byteLength;
43
+ this.controller.enqueue(bytes);
44
+ if (available <= 0) {
45
+ this.pause();
46
+ }
47
+ } catch (error) {
48
+ this.controller.error(
49
+ new Error(
50
+ "Could not create Buffer, chunk must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object"
51
+ )
52
+ );
53
+ this.cancel();
54
+ }
55
+ }
56
+ }
57
+ pause() {
58
+ if (this.stream.pause) {
59
+ this.stream.pause();
60
+ }
61
+ }
62
+ resume() {
63
+ if (this.stream.readable && this.stream.resume) {
64
+ this.stream.resume();
65
+ }
66
+ }
67
+ close() {
68
+ if (this.controller) {
69
+ this.controller.close();
70
+ delete this.controller;
71
+ }
72
+ }
73
+ error(error) {
74
+ if (this.controller) {
75
+ this.controller.error(error);
76
+ delete this.controller;
77
+ }
78
+ }
79
+ }
80
+ export {
81
+ createReadableStreamFromReadable
82
+ };
@@ -1,6 +1,6 @@
1
1
  import chalk from "chalk";
2
- import { chromium } from "playwright";
3
2
  import debug from "debug";
3
+ import { chromium } from "playwright";
4
4
  import { withSpinner } from "./withSpinner.js";
5
5
  const browserLog = debug("ef:cli::browser");
6
6
  async function launchBrowserAndWaitForSDK(options, fn) {
@@ -12,7 +12,7 @@ async function launchBrowserAndWaitForSDK(options, fn) {
12
12
  devtools: options.interactive === true
13
13
  });
14
14
  });
15
- const page = await withSpinner("Loading EditFrame SDK", async () => {
15
+ const page = await withSpinner("Loading Editframe SDK", async () => {
16
16
  const pageOptions = {};
17
17
  if (options.interactive === true) {
18
18
  pageOptions.viewport = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@editframe/cli",
3
- "version": "0.11.0-beta.9",
3
+ "version": "0.12.0-beta.2",
4
4
  "description": "Command line interface for EditFrame",
5
5
  "bin": {
6
6
  "editframe": "./dist/index.js"
@@ -23,10 +23,10 @@
23
23
  "vite-tsconfig-paths": "^4.3.2"
24
24
  },
25
25
  "dependencies": {
26
- "@editframe/api": "0.11.0-beta.9",
27
- "@editframe/assets": "0.11.0-beta.9",
28
- "@editframe/elements": "0.11.0-beta.9",
29
- "@editframe/vite-plugin": "0.11.0-beta.9",
26
+ "@editframe/api": "0.12.0-beta.2",
27
+ "@editframe/assets": "0.12.0-beta.2",
28
+ "@editframe/elements": "0.12.0-beta.2",
29
+ "@editframe/vite-plugin": "0.12.0-beta.2",
30
30
  "@inquirer/prompts": "^5.3.8",
31
31
  "axios": "^1.6.8",
32
32
  "chalk": "^5.3.0",