@editframe/cli 0.16.7-beta.0 → 0.17.6-beta.0
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 +1 -1
- package/dist/VERSION.js +2 -4
- package/dist/commands/auth.js +16 -25
- package/dist/commands/check.js +81 -108
- package/dist/commands/mux.d.ts +1 -0
- package/dist/commands/preview.js +4 -1
- package/dist/commands/process-file.js +18 -34
- package/dist/commands/process.js +28 -31
- package/dist/commands/render.js +117 -157
- package/dist/commands/sync.js +3 -5
- package/dist/commands/webhook.js +48 -52
- package/dist/index.js +3 -7
- package/dist/operations/processRenderInfo.js +25 -31
- package/dist/operations/syncAssetsDirectory/SubAssetSync.js +11 -18
- package/dist/operations/syncAssetsDirectory/SyncCaption.js +46 -73
- package/dist/operations/syncAssetsDirectory/SyncFragmentIndex.js +53 -83
- package/dist/operations/syncAssetsDirectory/SyncImage.js +72 -99
- package/dist/operations/syncAssetsDirectory/SyncStatus.js +30 -37
- package/dist/operations/syncAssetsDirectory/SyncTrack.js +107 -143
- package/dist/operations/syncAssetsDirectory/doAssetSync.js +42 -46
- package/dist/operations/syncAssetsDirectory.js +55 -78
- package/dist/utils/createReadableStreamFromReadable.js +61 -78
- package/dist/utils/index.js +10 -16
- package/dist/utils/launchBrowserAndWaitForSDK.js +31 -43
- package/dist/utils/startDevServer.d.ts +1 -1
- package/dist/utils/startPreviewServer.d.ts +1 -1
- package/dist/utils/startPreviewServer.js +28 -34
- package/dist/utils/validateVideoResolution.js +19 -23
- package/dist/utils/withSpinner.js +10 -12
- package/package.json +8 -8
- package/src/commands/check.ts +2 -2
- package/src/commands/mux.ts +10 -0
- package/src/utils/createReadableStreamFromReadable.ts +3 -7
- package/src/utils/startDevServer.ts +5 -5
- package/src/utils/startPreviewServer.ts +1 -1
- package/test-fixtures/network.ts +38 -9
|
@@ -1,77 +1,50 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import { lookupCaptionFileByMd5, createCaptionFile, uploadCaptionFile } from "@editframe/api";
|
|
3
|
-
import { Readable } from "node:stream";
|
|
4
1
|
import { getClient } from "../../utils/index.js";
|
|
5
|
-
import { basename } from "node:path";
|
|
6
2
|
import { createReadableStreamFromReadable } from "../../utils/createReadableStreamFromReadable.js";
|
|
7
3
|
import { SyncStatus } from "./SyncStatus.js";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
createReadableStreamFromReadable(
|
|
54
|
-
Readable.from(await fs.readFile(this.path))
|
|
55
|
-
),
|
|
56
|
-
await this.byteSize()
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
async markSynced() {
|
|
60
|
-
if (!this.created) {
|
|
61
|
-
throw new Error(
|
|
62
|
-
"Caption not created. Should have been prevented by .isComplete()"
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
const byteSize = await this.byteSize();
|
|
66
|
-
await this.syncStatus.markSynced({
|
|
67
|
-
version: "1",
|
|
68
|
-
complete: true,
|
|
69
|
-
id: this.created.id,
|
|
70
|
-
md5: this.md5,
|
|
71
|
-
byte_size: byteSize
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
export {
|
|
76
|
-
SyncCaption
|
|
4
|
+
import { createCaptionFile, lookupCaptionFileByMd5, uploadCaptionFile } from "@editframe/api";
|
|
5
|
+
import { basename } from "node:path";
|
|
6
|
+
import fs from "node:fs/promises";
|
|
7
|
+
import { Readable } from "node:stream";
|
|
8
|
+
var SyncCaption = class {
|
|
9
|
+
constructor(path$1, md5) {
|
|
10
|
+
this.path = path$1;
|
|
11
|
+
this.md5 = md5;
|
|
12
|
+
this.icon = "📝";
|
|
13
|
+
this.label = "captions";
|
|
14
|
+
this.syncStatus = new SyncStatus(this.path);
|
|
15
|
+
this.created = null;
|
|
16
|
+
}
|
|
17
|
+
async byteSize() {
|
|
18
|
+
return (await fs.stat(this.path)).size;
|
|
19
|
+
}
|
|
20
|
+
async prepare() {}
|
|
21
|
+
async validate() {}
|
|
22
|
+
async create() {
|
|
23
|
+
const maybeCaptionFile = await lookupCaptionFileByMd5(getClient(), this.md5);
|
|
24
|
+
if (maybeCaptionFile) this.created = maybeCaptionFile;
|
|
25
|
+
else this.created = await createCaptionFile(getClient(), {
|
|
26
|
+
md5: this.md5,
|
|
27
|
+
filename: basename(this.path).replace(/\.captions.json$/, ""),
|
|
28
|
+
byte_size: await this.byteSize()
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
isComplete() {
|
|
32
|
+
return !!this.created?.complete;
|
|
33
|
+
}
|
|
34
|
+
async upload() {
|
|
35
|
+
if (!this.created) throw new Error("Caption not created. Should have been prevented by .isComplete()");
|
|
36
|
+
await uploadCaptionFile(getClient(), this.created.id, createReadableStreamFromReadable(Readable.from(await fs.readFile(this.path))), await this.byteSize());
|
|
37
|
+
}
|
|
38
|
+
async markSynced() {
|
|
39
|
+
if (!this.created) throw new Error("Caption not created. Should have been prevented by .isComplete()");
|
|
40
|
+
const byteSize = await this.byteSize();
|
|
41
|
+
await this.syncStatus.markSynced({
|
|
42
|
+
version: "1",
|
|
43
|
+
complete: true,
|
|
44
|
+
id: this.created.id,
|
|
45
|
+
md5: this.md5,
|
|
46
|
+
byte_size: byteSize
|
|
47
|
+
});
|
|
48
|
+
}
|
|
77
49
|
};
|
|
50
|
+
export { SyncCaption };
|
|
@@ -1,86 +1,56 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import { join, dirname, basename } from "node:path";
|
|
3
|
-
import { Readable } from "node:stream";
|
|
4
|
-
import { lookupISOBMFFFileByMd5, createISOBMFFFile, uploadFragmentIndex } from "@editframe/api";
|
|
5
|
-
import { createReadableStreamFromReadable } from "../../utils/createReadableStreamFromReadable.js";
|
|
6
1
|
import { getClient } from "../../utils/index.js";
|
|
2
|
+
import { createReadableStreamFromReadable } from "../../utils/createReadableStreamFromReadable.js";
|
|
7
3
|
import { SyncStatus } from "./SyncStatus.js";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
async markSynced() {
|
|
60
|
-
if (!this.created) {
|
|
61
|
-
throw new Error(
|
|
62
|
-
"Fragment index not created. Should have been prevented by .isComplete()"
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
const byteSize = await this.byteSize();
|
|
66
|
-
await Promise.all([
|
|
67
|
-
this.syncStatus.markSynced({
|
|
68
|
-
version: "1",
|
|
69
|
-
complete: true,
|
|
70
|
-
id: this.created.id,
|
|
71
|
-
md5: this.md5,
|
|
72
|
-
byte_size: byteSize
|
|
73
|
-
}),
|
|
74
|
-
this.fileSyncStatus.markSynced({
|
|
75
|
-
version: "1",
|
|
76
|
-
complete: true,
|
|
77
|
-
id: this.created.id,
|
|
78
|
-
md5: this.md5,
|
|
79
|
-
byte_size: byteSize
|
|
80
|
-
})
|
|
81
|
-
]);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
export {
|
|
85
|
-
SyncFragmentIndex
|
|
4
|
+
import { createISOBMFFFile, lookupISOBMFFFileByMd5, uploadFragmentIndex } from "@editframe/api";
|
|
5
|
+
import { basename, dirname, join } from "node:path";
|
|
6
|
+
import fs from "node:fs/promises";
|
|
7
|
+
import { Readable } from "node:stream";
|
|
8
|
+
var SyncFragmentIndex = class {
|
|
9
|
+
constructor(path$1, md5) {
|
|
10
|
+
this.path = path$1;
|
|
11
|
+
this.md5 = md5;
|
|
12
|
+
this.icon = "📋";
|
|
13
|
+
this.label = "fragment index";
|
|
14
|
+
this.syncStatus = new SyncStatus(this.path);
|
|
15
|
+
this.fileSyncStatus = new SyncStatus(join(dirname(this.path), "isobmff"));
|
|
16
|
+
this.created = null;
|
|
17
|
+
}
|
|
18
|
+
async byteSize() {
|
|
19
|
+
return (await fs.stat(this.path)).size;
|
|
20
|
+
}
|
|
21
|
+
async prepare() {}
|
|
22
|
+
async validate() {}
|
|
23
|
+
async create() {
|
|
24
|
+
const maybeISOBMFFFile = await lookupISOBMFFFileByMd5(getClient(), this.md5);
|
|
25
|
+
if (maybeISOBMFFFile) this.created = maybeISOBMFFFile;
|
|
26
|
+
else this.created = await createISOBMFFFile(getClient(), {
|
|
27
|
+
md5: this.md5,
|
|
28
|
+
filename: basename(this.path).replace(/\.tracks.json$/, "")
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
isComplete() {
|
|
32
|
+
return !!this.created?.fragment_index_complete;
|
|
33
|
+
}
|
|
34
|
+
async upload() {
|
|
35
|
+
if (!this.created) throw new Error("Fragment index not created. Should have been prevented by .isComplete()");
|
|
36
|
+
await uploadFragmentIndex(getClient(), this.created.id, createReadableStreamFromReadable(Readable.from(await fs.readFile(this.path))), await this.byteSize());
|
|
37
|
+
}
|
|
38
|
+
async markSynced() {
|
|
39
|
+
if (!this.created) throw new Error("Fragment index not created. Should have been prevented by .isComplete()");
|
|
40
|
+
const byteSize = await this.byteSize();
|
|
41
|
+
await Promise.all([this.syncStatus.markSynced({
|
|
42
|
+
version: "1",
|
|
43
|
+
complete: true,
|
|
44
|
+
id: this.created.id,
|
|
45
|
+
md5: this.md5,
|
|
46
|
+
byte_size: byteSize
|
|
47
|
+
}), this.fileSyncStatus.markSynced({
|
|
48
|
+
version: "1",
|
|
49
|
+
complete: true,
|
|
50
|
+
id: this.created.id,
|
|
51
|
+
md5: this.md5,
|
|
52
|
+
byte_size: byteSize
|
|
53
|
+
})]);
|
|
54
|
+
}
|
|
86
55
|
};
|
|
56
|
+
export { SyncFragmentIndex };
|
|
@@ -1,102 +1,75 @@
|
|
|
1
|
-
import { createReadStream } from "node:fs";
|
|
2
|
-
import fs from "node:fs/promises";
|
|
3
|
-
import path, { basename } from "node:path";
|
|
4
|
-
import { lookupImageFileByMd5, createImageFile, uploadImageFile } from "@editframe/api";
|
|
5
|
-
import { Probe } from "@editframe/assets";
|
|
6
|
-
import { createReadableStreamFromReadable } from "../../utils/createReadableStreamFromReadable.js";
|
|
7
1
|
import { getClient } from "../../utils/index.js";
|
|
2
|
+
import { createReadableStreamFromReadable } from "../../utils/createReadableStreamFromReadable.js";
|
|
8
3
|
import { SyncStatus } from "./SyncStatus.js";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
byte_size: Number.parseInt(this.probeResult.format.size || "0")
|
|
80
|
-
},
|
|
81
|
-
createReadableStreamFromReadable(createReadStream(this.path))
|
|
82
|
-
).whenUploaded();
|
|
83
|
-
}
|
|
84
|
-
async markSynced() {
|
|
85
|
-
if (!this.created) {
|
|
86
|
-
throw new Error(
|
|
87
|
-
"Image not created. Should have been prevented by .isComplete()"
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
const byteSize = await this.byteSize();
|
|
91
|
-
return this.syncStatus.markSynced({
|
|
92
|
-
version: "1",
|
|
93
|
-
complete: true,
|
|
94
|
-
id: this.created.id,
|
|
95
|
-
md5: this.md5,
|
|
96
|
-
byte_size: byteSize
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
export {
|
|
101
|
-
SyncImage
|
|
4
|
+
import { createImageFile, lookupImageFileByMd5, uploadImageFile } from "@editframe/api";
|
|
5
|
+
import path, { basename } from "node:path";
|
|
6
|
+
import fs from "node:fs/promises";
|
|
7
|
+
import { createReadStream } from "node:fs";
|
|
8
|
+
import { Probe } from "@editframe/assets";
|
|
9
|
+
var SyncImage = class {
|
|
10
|
+
constructor(path$1, md5) {
|
|
11
|
+
this.path = path$1;
|
|
12
|
+
this.md5 = md5;
|
|
13
|
+
this.icon = "🖼️";
|
|
14
|
+
this.label = "image";
|
|
15
|
+
this.syncStatus = new SyncStatus(this.path);
|
|
16
|
+
this.created = null;
|
|
17
|
+
this._probeResult = null;
|
|
18
|
+
}
|
|
19
|
+
async prepare() {
|
|
20
|
+
this._probeResult = await Probe.probePath(this.path);
|
|
21
|
+
}
|
|
22
|
+
get probeResult() {
|
|
23
|
+
if (!this._probeResult) throw new Error("Probe result not found. Call prepare() first.");
|
|
24
|
+
return this._probeResult;
|
|
25
|
+
}
|
|
26
|
+
get extension() {
|
|
27
|
+
return path.extname(this.path).slice(1);
|
|
28
|
+
}
|
|
29
|
+
async byteSize() {
|
|
30
|
+
return (await fs.stat(this.path)).size;
|
|
31
|
+
}
|
|
32
|
+
async validate() {
|
|
33
|
+
const [videoProbe] = this.probeResult.videoStreams;
|
|
34
|
+
if (!videoProbe) throw new Error(`No media info found in image: ${this.path}`);
|
|
35
|
+
const ext = this.extension;
|
|
36
|
+
if (!(ext === "jpg" || ext === "jpeg" || ext === "png" || ext === "webp")) throw new Error(`Invalid image format: ${this.path}`);
|
|
37
|
+
}
|
|
38
|
+
async create() {
|
|
39
|
+
const byteSize = (await fs.stat(this.path)).size;
|
|
40
|
+
const [videoProbe] = this.probeResult.videoStreams;
|
|
41
|
+
if (!videoProbe) throw new Error("No video stream found in image. Should have been prevented by .validate()");
|
|
42
|
+
const maybeImageFile = await lookupImageFileByMd5(getClient(), this.md5);
|
|
43
|
+
if (maybeImageFile) this.created = maybeImageFile;
|
|
44
|
+
else this.created = await createImageFile(getClient(), {
|
|
45
|
+
md5: this.md5,
|
|
46
|
+
filename: basename(this.path),
|
|
47
|
+
width: videoProbe.width,
|
|
48
|
+
height: videoProbe.height,
|
|
49
|
+
mime_type: `image/${this.extension}`,
|
|
50
|
+
byte_size: byteSize
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
isComplete() {
|
|
54
|
+
return !!this.created?.complete;
|
|
55
|
+
}
|
|
56
|
+
async upload() {
|
|
57
|
+
if (!this.created) throw new Error("Image not created. Should have been prevented by .isComplete()");
|
|
58
|
+
await uploadImageFile(getClient(), {
|
|
59
|
+
id: this.created.id,
|
|
60
|
+
byte_size: Number.parseInt(this.probeResult.format.size || "0")
|
|
61
|
+
}, createReadableStreamFromReadable(createReadStream(this.path))).whenUploaded();
|
|
62
|
+
}
|
|
63
|
+
async markSynced() {
|
|
64
|
+
if (!this.created) throw new Error("Image not created. Should have been prevented by .isComplete()");
|
|
65
|
+
const byteSize = await this.byteSize();
|
|
66
|
+
return this.syncStatus.markSynced({
|
|
67
|
+
version: "1",
|
|
68
|
+
complete: true,
|
|
69
|
+
id: this.created.id,
|
|
70
|
+
md5: this.md5,
|
|
71
|
+
byte_size: byteSize
|
|
72
|
+
});
|
|
73
|
+
}
|
|
102
74
|
};
|
|
75
|
+
export { SyncImage };
|
|
@@ -2,42 +2,35 @@ import fs from "node:fs/promises";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
const SYNC_VERSION = "1";
|
|
4
4
|
const SyncStatusSchema = z.object({
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
version: z.string(),
|
|
6
|
+
complete: z.boolean(),
|
|
7
|
+
id: z.string(),
|
|
8
|
+
md5: z.string(),
|
|
9
|
+
byte_size: z.number()
|
|
10
10
|
});
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
async markSynced(info) {
|
|
36
|
-
process.stderr.write(`✏️ Marking asset as synced: ${this.basePath}
|
|
37
|
-
`);
|
|
38
|
-
await fs.writeFile(this.infoPath, JSON.stringify(info, null, 2), "utf-8");
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
export {
|
|
42
|
-
SyncStatus
|
|
11
|
+
var SyncStatus = class {
|
|
12
|
+
constructor(basePath) {
|
|
13
|
+
this.basePath = basePath;
|
|
14
|
+
this.infoPath = `${this.basePath}.info`;
|
|
15
|
+
}
|
|
16
|
+
async isSynced() {
|
|
17
|
+
const syncInfo = await this.readInfo();
|
|
18
|
+
if (!syncInfo) return false;
|
|
19
|
+
console.log("syncInfo.infoPath", this.infoPath);
|
|
20
|
+
return syncInfo.version === SYNC_VERSION && syncInfo.complete;
|
|
21
|
+
}
|
|
22
|
+
async readInfo() {
|
|
23
|
+
try {
|
|
24
|
+
const info = await fs.readFile(this.infoPath, "utf-8");
|
|
25
|
+
return SyncStatusSchema.parse(JSON.parse(info));
|
|
26
|
+
} catch (error) {
|
|
27
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return null;
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async markSynced(info) {
|
|
32
|
+
process.stderr.write(`✏️ Marking asset as synced: ${this.basePath}\n`);
|
|
33
|
+
await fs.writeFile(this.infoPath, JSON.stringify(info, null, 2), "utf-8");
|
|
34
|
+
}
|
|
43
35
|
};
|
|
36
|
+
export { SyncStatus };
|