@editframe/cli 0.26.3-beta.0 → 0.26.4-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.js +1 -1
- package/dist/VERSION.js.map +1 -1
- package/package.json +5 -5
- 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
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import { createReadStream } from "node:fs";
|
|
2
|
-
import fs from "node:fs/promises";
|
|
3
|
-
import { basename, dirname, join } from "node:path";
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
type CreateISOBMFFFileResult,
|
|
7
|
-
type CreateISOBMFFTrackPayload,
|
|
8
|
-
type CreateISOBMFFTrackResult,
|
|
9
|
-
createISOBMFFFile,
|
|
10
|
-
createISOBMFFTrack,
|
|
11
|
-
type LookupISOBMFFFileByMd5Result,
|
|
12
|
-
lookupISOBMFFFileByMd5,
|
|
13
|
-
uploadISOBMFFTrack,
|
|
14
|
-
} from "@editframe/api";
|
|
15
|
-
import { Probe } from "@editframe/assets";
|
|
16
|
-
|
|
17
|
-
import { createReadableStreamFromReadable } from "../../utils/createReadableStreamFromReadable.js";
|
|
18
|
-
import { getClient } from "../../utils/index.js";
|
|
19
|
-
import type { SubAssetSync } from "./SubAssetSync.js";
|
|
20
|
-
import { SyncStatus } from "./SyncStatus.js";
|
|
21
|
-
|
|
22
|
-
export class SyncTrack implements SubAssetSync<CreateISOBMFFTrackResult> {
|
|
23
|
-
icon = "📼";
|
|
24
|
-
label = "track";
|
|
25
|
-
syncStatus = new SyncStatus(this.path);
|
|
26
|
-
fileSyncStatus = new SyncStatus(join(dirname(this.path), "isobmff"));
|
|
27
|
-
created: CreateISOBMFFTrackResult | null = null;
|
|
28
|
-
|
|
29
|
-
constructor(
|
|
30
|
-
public path: string,
|
|
31
|
-
public md5: string,
|
|
32
|
-
) {}
|
|
33
|
-
|
|
34
|
-
private _isoFile:
|
|
35
|
-
| CreateISOBMFFFileResult
|
|
36
|
-
| LookupISOBMFFFileByMd5Result
|
|
37
|
-
| null = null;
|
|
38
|
-
|
|
39
|
-
get isoFile() {
|
|
40
|
-
if (this._isoFile) {
|
|
41
|
-
return this._isoFile;
|
|
42
|
-
}
|
|
43
|
-
throw new Error("ISOBMFF file not found. Call prepare() first.");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async byteSize() {
|
|
47
|
-
return (await fs.stat(this.path)).size;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
private _probeResult: Probe | null = null;
|
|
51
|
-
get probeResult() {
|
|
52
|
-
if (this._probeResult) {
|
|
53
|
-
return this._probeResult;
|
|
54
|
-
}
|
|
55
|
-
throw new Error("Probe result not found. Call prepare() first.");
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
get track() {
|
|
59
|
-
const [track] = this.probeResult.streams;
|
|
60
|
-
if (track) {
|
|
61
|
-
return track;
|
|
62
|
-
}
|
|
63
|
-
throw new Error(`No track found in track: ${this.path}`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async prepare() {
|
|
67
|
-
const maybeIsoFile = await lookupISOBMFFFileByMd5(getClient(), this.md5);
|
|
68
|
-
if (maybeIsoFile) {
|
|
69
|
-
this._isoFile = maybeIsoFile;
|
|
70
|
-
} else {
|
|
71
|
-
this._isoFile = await createISOBMFFFile(getClient(), {
|
|
72
|
-
md5: this.md5,
|
|
73
|
-
filename: basename(this.path).replace(/\.track-[\d]+.mp4$/, ""),
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
this._probeResult = await Probe.probePath(this.path);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
get trackId() {
|
|
80
|
-
const trackId = this.path.match(/track-([\d]+).mp4/)?.[1];
|
|
81
|
-
if (!trackId) {
|
|
82
|
-
throw new Error(`No track ID found for track: ${this.path}`);
|
|
83
|
-
}
|
|
84
|
-
return trackId;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
get trackDuration() {
|
|
88
|
-
const track = this.track;
|
|
89
|
-
if (!track.duration) {
|
|
90
|
-
throw new Error(`No duration found in track: ${this.path}`);
|
|
91
|
-
}
|
|
92
|
-
if (typeof track.duration === "string") {
|
|
93
|
-
return Number.parseFloat(track.duration);
|
|
94
|
-
}
|
|
95
|
-
return track.duration;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
async validate() {
|
|
99
|
-
this.trackId;
|
|
100
|
-
this.isoFile;
|
|
101
|
-
this.trackDuration;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async create(): Promise<void> {
|
|
105
|
-
const track = this.track;
|
|
106
|
-
const isoFile = this.isoFile;
|
|
107
|
-
|
|
108
|
-
if (track.codec_type === "data") {
|
|
109
|
-
throw new Error(`Unsupported codec type: ${track.codec_type}`);
|
|
110
|
-
}
|
|
111
|
-
const createPayload: CreateISOBMFFTrackPayload =
|
|
112
|
-
track.codec_type === "audio"
|
|
113
|
-
? {
|
|
114
|
-
type: track.codec_type,
|
|
115
|
-
file_id: isoFile.id,
|
|
116
|
-
track_id: Number(this.trackId),
|
|
117
|
-
probe_info: track,
|
|
118
|
-
duration_ms: Math.round(this.trackDuration * 1000),
|
|
119
|
-
codec_name: track.codec_name,
|
|
120
|
-
byte_size: await this.byteSize(),
|
|
121
|
-
}
|
|
122
|
-
: {
|
|
123
|
-
type: track.codec_type,
|
|
124
|
-
file_id: isoFile.id,
|
|
125
|
-
track_id: Number(this.trackId),
|
|
126
|
-
probe_info: track,
|
|
127
|
-
duration_ms: Math.round(this.trackDuration * 1000),
|
|
128
|
-
codec_name: track.codec_name,
|
|
129
|
-
byte_size: await this.byteSize(),
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
this.created = await createISOBMFFTrack(getClient(), createPayload);
|
|
133
|
-
}
|
|
134
|
-
isComplete() {
|
|
135
|
-
return !!this.created?.complete;
|
|
136
|
-
}
|
|
137
|
-
async upload() {
|
|
138
|
-
if (!this.created) {
|
|
139
|
-
throw new Error(
|
|
140
|
-
"Track not created. Should have been prevented by .isComplete()",
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
await uploadISOBMFFTrack(
|
|
144
|
-
getClient(),
|
|
145
|
-
this.isoFile.id,
|
|
146
|
-
Number(this.trackId),
|
|
147
|
-
createReadableStreamFromReadable(createReadStream(this.path)),
|
|
148
|
-
this.created?.byte_size,
|
|
149
|
-
).whenUploaded();
|
|
150
|
-
}
|
|
151
|
-
async markSynced() {
|
|
152
|
-
if (!this.created) {
|
|
153
|
-
throw new Error(
|
|
154
|
-
"Track not created. Should have been prevented by .isComplete()",
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
const byteSize = await this.byteSize();
|
|
158
|
-
await Promise.all([
|
|
159
|
-
this.syncStatus.markSynced({
|
|
160
|
-
version: "1",
|
|
161
|
-
complete: true,
|
|
162
|
-
id: `${this.created.file_id}:${this.created.track_id}`,
|
|
163
|
-
md5: this.md5,
|
|
164
|
-
byte_size: byteSize,
|
|
165
|
-
}),
|
|
166
|
-
this.fileSyncStatus.markSynced({
|
|
167
|
-
version: "1",
|
|
168
|
-
complete: true,
|
|
169
|
-
id: this.created.file_id,
|
|
170
|
-
md5: this.md5,
|
|
171
|
-
byte_size: byteSize,
|
|
172
|
-
}),
|
|
173
|
-
]);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test, vi } from "vitest";
|
|
2
|
-
import { doAssetSync } from "./doAssetSync.js";
|
|
3
|
-
import type { SubAssetSync } from "./SubAssetSync.js";
|
|
4
|
-
import type { SyncStatusInfo } from "./SyncStatus.js";
|
|
5
|
-
|
|
6
|
-
const collectAsyncGenerator = async (
|
|
7
|
-
generator: SubAssetSync<unknown>,
|
|
8
|
-
): Promise<
|
|
9
|
-
{
|
|
10
|
-
status: "info" | "success";
|
|
11
|
-
message: string;
|
|
12
|
-
}[]
|
|
13
|
-
> => {
|
|
14
|
-
const result = [];
|
|
15
|
-
for await (const item of doAssetSync(generator)) {
|
|
16
|
-
result.push(item);
|
|
17
|
-
}
|
|
18
|
-
return result;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const buildFakeSync = (): SubAssetSync<unknown> => {
|
|
22
|
-
const fakeSyncStatus = {
|
|
23
|
-
isSynced: vi.fn().mockReturnValue(false),
|
|
24
|
-
} as unknown as SyncStatusInfo;
|
|
25
|
-
const fakeSync = {
|
|
26
|
-
label: "TEST_LABEL",
|
|
27
|
-
icon: "🧪",
|
|
28
|
-
path: "TEST_PATH",
|
|
29
|
-
readInfo: vi.fn().mockReturnValue(Promise.resolve(null)),
|
|
30
|
-
syncStatus: fakeSyncStatus,
|
|
31
|
-
markSynced: vi.fn().mockReturnValue(Promise.resolve()),
|
|
32
|
-
isComplete: vi.fn().mockReturnValue(false),
|
|
33
|
-
prepare: vi.fn().mockReturnValue(Promise.resolve()),
|
|
34
|
-
validate: vi.fn().mockReturnValue(Promise.resolve()),
|
|
35
|
-
create: vi.fn().mockReturnValue(Promise.resolve()),
|
|
36
|
-
upload: vi.fn().mockReturnValue(Promise.resolve()),
|
|
37
|
-
} as unknown as SubAssetSync<unknown>;
|
|
38
|
-
return fakeSync;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
describe("doAssetSync", () => {
|
|
42
|
-
test("Succeeds if all steps are executed without error", async () => {
|
|
43
|
-
const fakeSync = buildFakeSync();
|
|
44
|
-
const messages = await collectAsyncGenerator(fakeSync);
|
|
45
|
-
expect(messages).toEqual([
|
|
46
|
-
{
|
|
47
|
-
status: "info",
|
|
48
|
-
message: "🧪 Syncing TEST_LABEL: TEST_PATH",
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
status: "success",
|
|
52
|
-
message: "Synced TEST_LABEL: TEST_PATH",
|
|
53
|
-
},
|
|
54
|
-
]);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test("Succeeds if asset is already synced", async () => {
|
|
58
|
-
const fakeSync = buildFakeSync();
|
|
59
|
-
fakeSync.syncStatus.isSynced = vi.fn().mockReturnValue(true);
|
|
60
|
-
const messages = await collectAsyncGenerator(fakeSync);
|
|
61
|
-
expect(messages).toEqual([
|
|
62
|
-
{
|
|
63
|
-
status: "info",
|
|
64
|
-
message: "Sub-asset has already been synced: TEST_PATH",
|
|
65
|
-
},
|
|
66
|
-
]);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
test("Succeeds if asset is already uploaded", async () => {
|
|
70
|
-
const fakeSync = buildFakeSync();
|
|
71
|
-
fakeSync.isComplete = vi.fn().mockReturnValue(true);
|
|
72
|
-
const messages = await collectAsyncGenerator(fakeSync);
|
|
73
|
-
expect(messages).toEqual([
|
|
74
|
-
{
|
|
75
|
-
status: "info",
|
|
76
|
-
message: "🧪 Syncing TEST_LABEL: TEST_PATH",
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
status: "success",
|
|
80
|
-
message: "Synced TEST_LABEL: TEST_PATH",
|
|
81
|
-
},
|
|
82
|
-
]);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
test("Throws if prepare fails", async () => {
|
|
86
|
-
const fakeSync = buildFakeSync();
|
|
87
|
-
fakeSync.prepare = vi
|
|
88
|
-
.fn()
|
|
89
|
-
.mockReturnValue(Promise.reject(new Error("TEST_ERROR")));
|
|
90
|
-
await expect(collectAsyncGenerator(fakeSync)).rejects.toThrow(
|
|
91
|
-
"Error validating TEST_LABEL: TEST_ERROR",
|
|
92
|
-
);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
test("Throws if validate fails", async () => {
|
|
96
|
-
const fakeSync = buildFakeSync();
|
|
97
|
-
fakeSync.validate = vi
|
|
98
|
-
.fn()
|
|
99
|
-
.mockReturnValue(Promise.reject(new Error("TEST_ERROR")));
|
|
100
|
-
await expect(collectAsyncGenerator(fakeSync)).rejects.toThrow(
|
|
101
|
-
"Error validating TEST_LABEL: TEST_ERROR",
|
|
102
|
-
);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
test("Throws if create fails", async () => {
|
|
106
|
-
const fakeSync = buildFakeSync();
|
|
107
|
-
fakeSync.create = vi
|
|
108
|
-
.fn()
|
|
109
|
-
.mockReturnValue(Promise.reject(new Error("TEST_ERROR")));
|
|
110
|
-
await expect(collectAsyncGenerator(fakeSync)).rejects.toThrow(
|
|
111
|
-
"Error creating TEST_LABEL: TEST_ERROR",
|
|
112
|
-
);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test("Throws if upload fails", async () => {
|
|
116
|
-
const fakeSync = buildFakeSync();
|
|
117
|
-
fakeSync.upload = vi
|
|
118
|
-
.fn()
|
|
119
|
-
.mockReturnValue(Promise.reject(new Error("TEST_ERROR")));
|
|
120
|
-
await expect(collectAsyncGenerator(fakeSync)).rejects.toThrow(
|
|
121
|
-
"Error uploading TEST_LABEL: TEST_ERROR",
|
|
122
|
-
);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
test("Throws if markSynced fails", async () => {
|
|
126
|
-
const fakeSync = buildFakeSync();
|
|
127
|
-
fakeSync.markSynced = vi
|
|
128
|
-
.fn()
|
|
129
|
-
.mockReturnValue(Promise.reject(new Error("TEST_ERROR")));
|
|
130
|
-
await expect(collectAsyncGenerator(fakeSync)).rejects.toThrow(
|
|
131
|
-
"Error marking TEST_LABEL as synced: TEST_ERROR",
|
|
132
|
-
);
|
|
133
|
-
});
|
|
134
|
-
});
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type { SubAssetSync } from "./SubAssetSync.js";
|
|
2
|
-
|
|
3
|
-
export const doAssetSync = async function* (
|
|
4
|
-
assetSync: SubAssetSync<unknown>,
|
|
5
|
-
): AsyncGenerator<{
|
|
6
|
-
status: "info" | "success";
|
|
7
|
-
message: string;
|
|
8
|
-
}> {
|
|
9
|
-
if (await assetSync.syncStatus.isSynced()) {
|
|
10
|
-
yield {
|
|
11
|
-
status: "info",
|
|
12
|
-
message: `Sub-asset has already been synced: ${assetSync.path}`,
|
|
13
|
-
};
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
try {
|
|
18
|
-
await assetSync.prepare();
|
|
19
|
-
await assetSync.validate();
|
|
20
|
-
} catch (error) {
|
|
21
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
22
|
-
|
|
23
|
-
throw new Error(`Error validating ${assetSync.label}: ${message}`);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
yield {
|
|
27
|
-
status: "info",
|
|
28
|
-
message: `${assetSync.icon} Syncing ${assetSync.label}: ${assetSync.path}`,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
await assetSync.create();
|
|
33
|
-
} catch (error) {
|
|
34
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
35
|
-
|
|
36
|
-
throw new Error(`Error creating ${assetSync.label}: ${message}`);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (!assetSync.isComplete()) {
|
|
40
|
-
try {
|
|
41
|
-
await assetSync.upload();
|
|
42
|
-
} catch (error) {
|
|
43
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
44
|
-
|
|
45
|
-
throw new Error(`Error uploading ${assetSync.label}: ${message}`);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
await assetSync.markSynced();
|
|
51
|
-
} catch (error) {
|
|
52
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
53
|
-
|
|
54
|
-
throw new Error(`Error marking ${assetSync.label} as synced: ${message}`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
yield {
|
|
58
|
-
status: "success",
|
|
59
|
-
message: `Synced ${assetSync.label}: ${assetSync.path}`,
|
|
60
|
-
};
|
|
61
|
-
return;
|
|
62
|
-
};
|