@vibeframe/cli 0.27.0 → 0.30.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/LICENSE +21 -0
- package/dist/agent/adapters/index.d.ts +1 -0
- package/dist/agent/adapters/index.d.ts.map +1 -1
- package/dist/agent/adapters/index.js +5 -0
- package/dist/agent/adapters/index.js.map +1 -1
- package/dist/agent/adapters/openrouter.d.ts +16 -0
- package/dist/agent/adapters/openrouter.d.ts.map +1 -0
- package/dist/agent/adapters/openrouter.js +100 -0
- package/dist/agent/adapters/openrouter.js.map +1 -0
- package/dist/agent/types.d.ts +1 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +3 -1
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/ai-edit-cli.d.ts.map +1 -1
- package/dist/commands/ai-edit-cli.js +18 -0
- package/dist/commands/ai-edit-cli.js.map +1 -1
- package/dist/commands/generate.js +14 -0
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/schema.d.ts +1 -0
- package/dist/commands/schema.d.ts.map +1 -1
- package/dist/commands/schema.js +122 -21
- package/dist/commands/schema.js.map +1 -1
- package/dist/commands/setup.js +5 -2
- package/dist/commands/setup.js.map +1 -1
- package/dist/config/schema.d.ts +2 -1
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +2 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/index.js +0 -0
- package/package.json +16 -12
- package/.turbo/turbo-build.log +0 -4
- package/.turbo/turbo-lint.log +0 -21
- package/.turbo/turbo-test.log +0 -689
- package/src/agent/adapters/claude.ts +0 -143
- package/src/agent/adapters/gemini.ts +0 -159
- package/src/agent/adapters/index.ts +0 -61
- package/src/agent/adapters/ollama.ts +0 -231
- package/src/agent/adapters/openai.ts +0 -116
- package/src/agent/adapters/xai.ts +0 -119
- package/src/agent/index.ts +0 -251
- package/src/agent/memory/index.ts +0 -151
- package/src/agent/prompts/system.ts +0 -106
- package/src/agent/tools/ai-editing.ts +0 -845
- package/src/agent/tools/ai-generation.ts +0 -1073
- package/src/agent/tools/ai-pipeline.ts +0 -1055
- package/src/agent/tools/ai.ts +0 -21
- package/src/agent/tools/batch.ts +0 -429
- package/src/agent/tools/e2e.test.ts +0 -545
- package/src/agent/tools/export.ts +0 -184
- package/src/agent/tools/filesystem.ts +0 -237
- package/src/agent/tools/index.ts +0 -150
- package/src/agent/tools/integration.test.ts +0 -775
- package/src/agent/tools/media.ts +0 -697
- package/src/agent/tools/project.ts +0 -313
- package/src/agent/tools/timeline.ts +0 -951
- package/src/agent/types.ts +0 -68
- package/src/commands/agent.ts +0 -340
- package/src/commands/ai-analyze.ts +0 -429
- package/src/commands/ai-animated-caption.ts +0 -390
- package/src/commands/ai-audio.ts +0 -941
- package/src/commands/ai-broll.ts +0 -490
- package/src/commands/ai-edit-cli.ts +0 -658
- package/src/commands/ai-edit.ts +0 -1542
- package/src/commands/ai-fill-gaps.ts +0 -566
- package/src/commands/ai-helpers.ts +0 -65
- package/src/commands/ai-highlights.ts +0 -1303
- package/src/commands/ai-image.ts +0 -761
- package/src/commands/ai-motion.ts +0 -347
- package/src/commands/ai-narrate.ts +0 -451
- package/src/commands/ai-review.ts +0 -309
- package/src/commands/ai-script-pipeline-cli.ts +0 -1710
- package/src/commands/ai-script-pipeline.ts +0 -1365
- package/src/commands/ai-suggest-edit.ts +0 -264
- package/src/commands/ai-video-fx.ts +0 -445
- package/src/commands/ai-video.ts +0 -915
- package/src/commands/ai-viral.ts +0 -595
- package/src/commands/ai-visual-fx.ts +0 -601
- package/src/commands/ai.test.ts +0 -627
- package/src/commands/ai.ts +0 -307
- package/src/commands/analyze.ts +0 -282
- package/src/commands/audio.ts +0 -644
- package/src/commands/batch.test.ts +0 -279
- package/src/commands/batch.ts +0 -440
- package/src/commands/detect.ts +0 -329
- package/src/commands/doctor.ts +0 -237
- package/src/commands/edit-cmd.ts +0 -1014
- package/src/commands/export.ts +0 -918
- package/src/commands/generate.ts +0 -2146
- package/src/commands/media.ts +0 -177
- package/src/commands/output.ts +0 -142
- package/src/commands/pipeline.ts +0 -398
- package/src/commands/project.test.ts +0 -127
- package/src/commands/project.ts +0 -149
- package/src/commands/sanitize.ts +0 -60
- package/src/commands/schema.ts +0 -130
- package/src/commands/setup.ts +0 -509
- package/src/commands/timeline.test.ts +0 -499
- package/src/commands/timeline.ts +0 -529
- package/src/commands/validate.ts +0 -77
- package/src/config/config.test.ts +0 -197
- package/src/config/index.ts +0 -125
- package/src/config/schema.ts +0 -82
- package/src/engine/index.ts +0 -2
- package/src/engine/project.test.ts +0 -702
- package/src/engine/project.ts +0 -439
- package/src/index.ts +0 -146
- package/src/utils/api-key.test.ts +0 -41
- package/src/utils/api-key.ts +0 -247
- package/src/utils/audio.ts +0 -83
- package/src/utils/exec-safe.ts +0 -75
- package/src/utils/first-run.ts +0 -52
- package/src/utils/provider-resolver.ts +0 -56
- package/src/utils/remotion.ts +0 -951
- package/src/utils/subtitle.test.ts +0 -227
- package/src/utils/subtitle.ts +0 -169
- package/src/utils/tty.ts +0 -196
- package/tsconfig.json +0 -20
|
@@ -1,499 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import { execSync } from "child_process";
|
|
3
|
-
import { readFileSync, writeFileSync, mkdtempSync, rmSync } from "fs";
|
|
4
|
-
import { join, resolve } from "path";
|
|
5
|
-
import { tmpdir } from "os";
|
|
6
|
-
|
|
7
|
-
const CLI = `npx tsx ${resolve(__dirname, "../index.ts")}`;
|
|
8
|
-
|
|
9
|
-
describe("timeline commands", () => {
|
|
10
|
-
let tempDir: string;
|
|
11
|
-
let projectFile: string;
|
|
12
|
-
let mediaFile: string;
|
|
13
|
-
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
tempDir = mkdtempSync(join(tmpdir(), "vibe-test-"));
|
|
16
|
-
projectFile = join(tempDir, "test.vibe.json");
|
|
17
|
-
mediaFile = join(tempDir, "sample.mp4");
|
|
18
|
-
|
|
19
|
-
// Create project
|
|
20
|
-
execSync(`${CLI} project create "Timeline Test" -o "${projectFile}"`, {
|
|
21
|
-
cwd: process.cwd(),
|
|
22
|
-
encoding: "utf-8",
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// Create dummy media file
|
|
26
|
-
writeFileSync(mediaFile, "dummy video content");
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
afterEach(() => {
|
|
30
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
describe("timeline add-source", () => {
|
|
34
|
-
it("adds a media source to project", () => {
|
|
35
|
-
execSync(
|
|
36
|
-
`${CLI} timeline add-source "${projectFile}" "${mediaFile}" --duration 10`,
|
|
37
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
41
|
-
expect(content.state.sources).toHaveLength(1);
|
|
42
|
-
expect(content.state.sources[0].name).toBe("sample.mp4");
|
|
43
|
-
expect(content.state.sources[0].type).toBe("video");
|
|
44
|
-
expect(content.state.sources[0].duration).toBe(10);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it("adds source with custom name", () => {
|
|
48
|
-
execSync(
|
|
49
|
-
`${CLI} timeline add-source "${projectFile}" "${mediaFile}" -n "My Video" -d 5`,
|
|
50
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
54
|
-
expect(content.state.sources[0].name).toBe("My Video");
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it("detects media type from extension", () => {
|
|
58
|
-
const audioFile = join(tempDir, "audio.mp3");
|
|
59
|
-
writeFileSync(audioFile, "dummy audio");
|
|
60
|
-
|
|
61
|
-
execSync(
|
|
62
|
-
`${CLI} timeline add-source "${projectFile}" "${audioFile}" -d 30`,
|
|
63
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
67
|
-
expect(content.state.sources[0].type).toBe("audio");
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
describe("timeline add-clip", () => {
|
|
72
|
-
let sourceId: string;
|
|
73
|
-
|
|
74
|
-
beforeEach(() => {
|
|
75
|
-
execSync(
|
|
76
|
-
`${CLI} timeline add-source "${projectFile}" "${mediaFile}" -d 10`,
|
|
77
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
81
|
-
sourceId = content.state.sources[0].id;
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it("adds a clip to timeline", () => {
|
|
85
|
-
execSync(`${CLI} timeline add-clip "${projectFile}" ${sourceId}`, {
|
|
86
|
-
cwd: process.cwd(),
|
|
87
|
-
encoding: "utf-8",
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
91
|
-
expect(content.state.clips).toHaveLength(1);
|
|
92
|
-
expect(content.state.clips[0].sourceId).toBe(sourceId);
|
|
93
|
-
expect(content.state.clips[0].trackId).toBe("video-track-1");
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it("adds clip with custom start time", () => {
|
|
97
|
-
execSync(
|
|
98
|
-
`${CLI} timeline add-clip "${projectFile}" ${sourceId} --start 5`,
|
|
99
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
103
|
-
expect(content.state.clips[0].startTime).toBe(5);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it("adds clip with custom duration", () => {
|
|
107
|
-
execSync(
|
|
108
|
-
`${CLI} timeline add-clip "${projectFile}" ${sourceId} --duration 3`,
|
|
109
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
113
|
-
expect(content.state.clips[0].duration).toBe(3);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it("updates project duration after adding clip", () => {
|
|
117
|
-
execSync(
|
|
118
|
-
`${CLI} timeline add-clip "${projectFile}" ${sourceId} --start 5 --duration 10`,
|
|
119
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
123
|
-
expect(content.state.project.duration).toBe(15);
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
describe("timeline add-track", () => {
|
|
128
|
-
it("adds a video track", () => {
|
|
129
|
-
execSync(`${CLI} timeline add-track "${projectFile}" video`, {
|
|
130
|
-
cwd: process.cwd(),
|
|
131
|
-
encoding: "utf-8",
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
135
|
-
expect(content.state.tracks).toHaveLength(3);
|
|
136
|
-
expect(content.state.tracks[2].type).toBe("video");
|
|
137
|
-
expect(content.state.tracks[2].name).toBe("Video 2");
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it("adds an audio track", () => {
|
|
141
|
-
execSync(`${CLI} timeline add-track "${projectFile}" audio`, {
|
|
142
|
-
cwd: process.cwd(),
|
|
143
|
-
encoding: "utf-8",
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
147
|
-
expect(content.state.tracks).toHaveLength(3);
|
|
148
|
-
expect(content.state.tracks[2].type).toBe("audio");
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it("adds track with custom name", () => {
|
|
152
|
-
execSync(
|
|
153
|
-
`${CLI} timeline add-track "${projectFile}" video -n "Overlay"`,
|
|
154
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
158
|
-
expect(content.state.tracks[2].name).toBe("Overlay");
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
describe("timeline add-effect", () => {
|
|
163
|
-
let clipId: string;
|
|
164
|
-
|
|
165
|
-
beforeEach(() => {
|
|
166
|
-
execSync(
|
|
167
|
-
`${CLI} timeline add-source "${projectFile}" "${mediaFile}" -d 10`,
|
|
168
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
let content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
172
|
-
const sourceId = content.state.sources[0].id;
|
|
173
|
-
|
|
174
|
-
execSync(`${CLI} timeline add-clip "${projectFile}" ${sourceId}`, {
|
|
175
|
-
cwd: process.cwd(),
|
|
176
|
-
encoding: "utf-8",
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
180
|
-
clipId = content.state.clips[0].id;
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
it("adds fadeIn effect to clip", () => {
|
|
184
|
-
execSync(
|
|
185
|
-
`${CLI} timeline add-effect "${projectFile}" ${clipId} fadeIn`,
|
|
186
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
187
|
-
);
|
|
188
|
-
|
|
189
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
190
|
-
expect(content.state.clips[0].effects).toHaveLength(1);
|
|
191
|
-
expect(content.state.clips[0].effects[0].type).toBe("fadeIn");
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it("adds effect with custom duration", () => {
|
|
195
|
-
execSync(
|
|
196
|
-
`${CLI} timeline add-effect "${projectFile}" ${clipId} fadeOut --duration 2`,
|
|
197
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
198
|
-
);
|
|
199
|
-
|
|
200
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
201
|
-
expect(content.state.clips[0].effects[0].duration).toBe(2);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it("adds multiple effects to same clip", () => {
|
|
205
|
-
execSync(
|
|
206
|
-
`${CLI} timeline add-effect "${projectFile}" ${clipId} fadeIn`,
|
|
207
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
208
|
-
);
|
|
209
|
-
execSync(
|
|
210
|
-
`${CLI} timeline add-effect "${projectFile}" ${clipId} fadeOut`,
|
|
211
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
215
|
-
expect(content.state.clips[0].effects).toHaveLength(2);
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
describe("timeline trim", () => {
|
|
220
|
-
let clipId: string;
|
|
221
|
-
|
|
222
|
-
beforeEach(() => {
|
|
223
|
-
execSync(
|
|
224
|
-
`${CLI} timeline add-source "${projectFile}" "${mediaFile}" -d 10`,
|
|
225
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
226
|
-
);
|
|
227
|
-
|
|
228
|
-
let content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
229
|
-
const sourceId = content.state.sources[0].id;
|
|
230
|
-
|
|
231
|
-
execSync(
|
|
232
|
-
`${CLI} timeline add-clip "${projectFile}" ${sourceId} --duration 10`,
|
|
233
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
234
|
-
);
|
|
235
|
-
|
|
236
|
-
content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
237
|
-
clipId = content.state.clips[0].id;
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
it("trims clip duration", () => {
|
|
241
|
-
execSync(
|
|
242
|
-
`${CLI} timeline trim "${projectFile}" ${clipId} --duration 5`,
|
|
243
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
244
|
-
);
|
|
245
|
-
|
|
246
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
247
|
-
expect(content.state.clips[0].duration).toBe(5);
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
it("trims clip start", () => {
|
|
251
|
-
execSync(
|
|
252
|
-
`${CLI} timeline trim "${projectFile}" ${clipId} --start 2`,
|
|
253
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
254
|
-
);
|
|
255
|
-
|
|
256
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
257
|
-
expect(content.state.clips[0].startTime).toBe(2);
|
|
258
|
-
});
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
describe("timeline list", () => {
|
|
262
|
-
beforeEach(() => {
|
|
263
|
-
execSync(
|
|
264
|
-
`${CLI} timeline add-source "${projectFile}" "${mediaFile}" -d 10`,
|
|
265
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
266
|
-
);
|
|
267
|
-
|
|
268
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
269
|
-
const sourceId = content.state.sources[0].id;
|
|
270
|
-
|
|
271
|
-
execSync(`${CLI} timeline add-clip "${projectFile}" ${sourceId}`, {
|
|
272
|
-
cwd: process.cwd(),
|
|
273
|
-
encoding: "utf-8",
|
|
274
|
-
});
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
it("lists all timeline contents", () => {
|
|
278
|
-
const output = execSync(`${CLI} timeline list "${projectFile}"`, {
|
|
279
|
-
cwd: process.cwd(),
|
|
280
|
-
encoding: "utf-8",
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
expect(output).toContain("Sources");
|
|
284
|
-
expect(output).toContain("sample.mp4");
|
|
285
|
-
expect(output).toContain("Tracks");
|
|
286
|
-
expect(output).toContain("Video 1");
|
|
287
|
-
expect(output).toContain("Clips");
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
it("lists only sources", () => {
|
|
291
|
-
const output = execSync(
|
|
292
|
-
`${CLI} timeline list "${projectFile}" --sources`,
|
|
293
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
294
|
-
);
|
|
295
|
-
|
|
296
|
-
expect(output).toContain("Sources");
|
|
297
|
-
expect(output).toContain("sample.mp4");
|
|
298
|
-
expect(output).not.toContain("Tracks");
|
|
299
|
-
expect(output).not.toContain("Clips");
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
it("lists only tracks", () => {
|
|
303
|
-
const output = execSync(
|
|
304
|
-
`${CLI} timeline list "${projectFile}" --tracks`,
|
|
305
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
306
|
-
);
|
|
307
|
-
|
|
308
|
-
expect(output).toContain("Tracks");
|
|
309
|
-
expect(output).toContain("Video 1");
|
|
310
|
-
expect(output).not.toContain("Sources");
|
|
311
|
-
expect(output).not.toContain("Clips");
|
|
312
|
-
});
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
describe("timeline split", () => {
|
|
316
|
-
let clipId: string;
|
|
317
|
-
|
|
318
|
-
beforeEach(() => {
|
|
319
|
-
execSync(
|
|
320
|
-
`${CLI} timeline add-source "${projectFile}" "${mediaFile}" -d 10`,
|
|
321
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
322
|
-
);
|
|
323
|
-
|
|
324
|
-
let content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
325
|
-
const sourceId = content.state.sources[0].id;
|
|
326
|
-
|
|
327
|
-
execSync(
|
|
328
|
-
`${CLI} timeline add-clip "${projectFile}" ${sourceId} --duration 10`,
|
|
329
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
330
|
-
);
|
|
331
|
-
|
|
332
|
-
content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
333
|
-
clipId = content.state.clips[0].id;
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
it("splits a clip at given time", () => {
|
|
337
|
-
execSync(`${CLI} timeline split "${projectFile}" ${clipId} --time 4`, {
|
|
338
|
-
cwd: process.cwd(),
|
|
339
|
-
encoding: "utf-8",
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
343
|
-
expect(content.state.clips).toHaveLength(2);
|
|
344
|
-
expect(content.state.clips[0].duration).toBe(4);
|
|
345
|
-
expect(content.state.clips[1].duration).toBe(6);
|
|
346
|
-
expect(content.state.clips[1].startTime).toBe(4);
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
it("fails with invalid split time", () => {
|
|
350
|
-
expect(() => {
|
|
351
|
-
execSync(`${CLI} timeline split "${projectFile}" ${clipId} --time 0`, {
|
|
352
|
-
cwd: process.cwd(),
|
|
353
|
-
encoding: "utf-8",
|
|
354
|
-
stdio: "pipe",
|
|
355
|
-
});
|
|
356
|
-
}).toThrow();
|
|
357
|
-
});
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
describe("timeline duplicate", () => {
|
|
361
|
-
let clipId: string;
|
|
362
|
-
|
|
363
|
-
beforeEach(() => {
|
|
364
|
-
execSync(
|
|
365
|
-
`${CLI} timeline add-source "${projectFile}" "${mediaFile}" -d 10`,
|
|
366
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
367
|
-
);
|
|
368
|
-
|
|
369
|
-
let content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
370
|
-
const sourceId = content.state.sources[0].id;
|
|
371
|
-
|
|
372
|
-
execSync(
|
|
373
|
-
`${CLI} timeline add-clip "${projectFile}" ${sourceId} --duration 5`,
|
|
374
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
375
|
-
);
|
|
376
|
-
|
|
377
|
-
content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
378
|
-
clipId = content.state.clips[0].id;
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
it("duplicates a clip after original", () => {
|
|
382
|
-
execSync(`${CLI} timeline duplicate "${projectFile}" ${clipId}`, {
|
|
383
|
-
cwd: process.cwd(),
|
|
384
|
-
encoding: "utf-8",
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
388
|
-
expect(content.state.clips).toHaveLength(2);
|
|
389
|
-
expect(content.state.clips[1].startTime).toBe(5);
|
|
390
|
-
expect(content.state.clips[1].duration).toBe(5);
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
it("duplicates a clip at specified time", () => {
|
|
394
|
-
execSync(
|
|
395
|
-
`${CLI} timeline duplicate "${projectFile}" ${clipId} --time 20`,
|
|
396
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
397
|
-
);
|
|
398
|
-
|
|
399
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
400
|
-
expect(content.state.clips[1].startTime).toBe(20);
|
|
401
|
-
});
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
describe("timeline delete", () => {
|
|
405
|
-
let clipId: string;
|
|
406
|
-
|
|
407
|
-
beforeEach(() => {
|
|
408
|
-
execSync(
|
|
409
|
-
`${CLI} timeline add-source "${projectFile}" "${mediaFile}" -d 10`,
|
|
410
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
411
|
-
);
|
|
412
|
-
|
|
413
|
-
let content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
414
|
-
const sourceId = content.state.sources[0].id;
|
|
415
|
-
|
|
416
|
-
execSync(`${CLI} timeline add-clip "${projectFile}" ${sourceId}`, {
|
|
417
|
-
cwd: process.cwd(),
|
|
418
|
-
encoding: "utf-8",
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
422
|
-
clipId = content.state.clips[0].id;
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
it("deletes a clip", () => {
|
|
426
|
-
const contentBefore = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
427
|
-
expect(contentBefore.state.clips).toHaveLength(1);
|
|
428
|
-
|
|
429
|
-
execSync(`${CLI} timeline delete "${projectFile}" ${clipId}`, {
|
|
430
|
-
cwd: process.cwd(),
|
|
431
|
-
encoding: "utf-8",
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
435
|
-
expect(content.state.clips).toHaveLength(0);
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
it("fails with non-existent clip", () => {
|
|
439
|
-
expect(() => {
|
|
440
|
-
execSync(`${CLI} timeline delete "${projectFile}" non-existent`, {
|
|
441
|
-
cwd: process.cwd(),
|
|
442
|
-
encoding: "utf-8",
|
|
443
|
-
stdio: "pipe",
|
|
444
|
-
});
|
|
445
|
-
}).toThrow();
|
|
446
|
-
});
|
|
447
|
-
});
|
|
448
|
-
|
|
449
|
-
describe("timeline move", () => {
|
|
450
|
-
let clipId: string;
|
|
451
|
-
|
|
452
|
-
beforeEach(() => {
|
|
453
|
-
execSync(
|
|
454
|
-
`${CLI} timeline add-source "${projectFile}" "${mediaFile}" -d 10`,
|
|
455
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
456
|
-
);
|
|
457
|
-
|
|
458
|
-
let content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
459
|
-
const sourceId = content.state.sources[0].id;
|
|
460
|
-
|
|
461
|
-
execSync(`${CLI} timeline add-clip "${projectFile}" ${sourceId}`, {
|
|
462
|
-
cwd: process.cwd(),
|
|
463
|
-
encoding: "utf-8",
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
467
|
-
clipId = content.state.clips[0].id;
|
|
468
|
-
});
|
|
469
|
-
|
|
470
|
-
it("moves a clip to new time", () => {
|
|
471
|
-
execSync(`${CLI} timeline move "${projectFile}" ${clipId} --time 15`, {
|
|
472
|
-
cwd: process.cwd(),
|
|
473
|
-
encoding: "utf-8",
|
|
474
|
-
});
|
|
475
|
-
|
|
476
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
477
|
-
expect(content.state.clips[0].startTime).toBe(15);
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
it("moves a clip to different track", () => {
|
|
481
|
-
// Add audio track
|
|
482
|
-
execSync(`${CLI} timeline add-track "${projectFile}" audio -n "Audio 2"`, {
|
|
483
|
-
cwd: process.cwd(),
|
|
484
|
-
encoding: "utf-8",
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
const content = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
488
|
-
const newTrackId = content.state.tracks[2].id;
|
|
489
|
-
|
|
490
|
-
execSync(
|
|
491
|
-
`${CLI} timeline move "${projectFile}" ${clipId} --track ${newTrackId}`,
|
|
492
|
-
{ cwd: process.cwd(), encoding: "utf-8" }
|
|
493
|
-
);
|
|
494
|
-
|
|
495
|
-
const updated = JSON.parse(readFileSync(projectFile, "utf-8"));
|
|
496
|
-
expect(updated.state.clips[0].trackId).toBe(newTrackId);
|
|
497
|
-
});
|
|
498
|
-
});
|
|
499
|
-
});
|