blitzreels 0.1.8 → 0.1.9
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 +1 -1
- package/README.md +47 -2
- package/dist/cli-errors.d.ts.map +1 -1
- package/dist/cli-runtime.d.ts +1 -1
- package/dist/cli-runtime.d.ts.map +1 -1
- package/dist/cli-runtime.js +1 -1
- package/dist/cli-runtime.js.map +1 -1
- package/dist/command-metadata.d.ts.map +1 -1
- package/dist/command-registry.d.ts.map +1 -1
- package/dist/command-registry.js +2 -0
- package/dist/command-registry.js.map +1 -1
- package/dist/commands/auth-runtime.js +1 -1
- package/dist/commands/auth-runtime.js.map +1 -1
- package/dist/commands/caption-dry-run.d.ts.map +1 -1
- package/dist/commands/caption-dry-run.js +16 -0
- package/dist/commands/caption-dry-run.js.map +1 -1
- package/dist/commands/captions-specs.d.ts.map +1 -1
- package/dist/commands/captions-specs.js +8 -0
- package/dist/commands/captions-specs.js.map +1 -1
- package/dist/commands/captions.js +16 -0
- package/dist/commands/captions.js.map +1 -1
- package/dist/commands/clips.d.ts +3 -0
- package/dist/commands/clips.d.ts.map +1 -1
- package/dist/commands/clips.js +702 -7
- package/dist/commands/clips.js.map +1 -1
- package/dist/commands/editing-workflows.d.ts.map +1 -1
- package/dist/commands/editing-workflows.js +24 -6
- package/dist/commands/editing-workflows.js.map +1 -1
- package/dist/commands/media-assets.d.ts +4 -7
- package/dist/commands/media-assets.d.ts.map +1 -1
- package/dist/commands/media-assets.js +221 -2
- package/dist/commands/media-assets.js.map +1 -1
- package/dist/commands/media-runtime.d.ts +3 -7
- package/dist/commands/media-runtime.d.ts.map +1 -1
- package/dist/commands/media-runtime.js +6 -2
- package/dist/commands/media-runtime.js.map +1 -1
- package/dist/commands/projects.js +3 -0
- package/dist/commands/projects.js.map +1 -1
- package/dist/commands/recording-sets.d.ts +44 -0
- package/dist/commands/recording-sets.d.ts.map +1 -0
- package/dist/commands/recording-sets.js +385 -0
- package/dist/commands/recording-sets.js.map +1 -0
- package/dist/commands/system.js +1 -1
- package/dist/commands/system.js.map +1 -1
- package/dist/commands/text-overlay-spec.js +62 -2
- package/dist/commands/text-overlay-spec.js.map +1 -1
- package/dist/commands/timeline-runtime.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/preview-first-edit.d.ts.map +1 -1
- package/dist/update-notifier.d.ts.map +1 -1
- package/dist/update-notifier.js +7 -3
- package/dist/update-notifier.js.map +1 -1
- package/package.json +2 -2
package/dist/commands/clips.js
CHANGED
|
@@ -1,7 +1,67 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
|
+
import { CliOperationError, CliUsageError } from "../cli-errors.js";
|
|
3
4
|
import { commandSpec } from "../command-metadata.js";
|
|
4
5
|
export const CLIPS_COMMAND_SPECS = [
|
|
6
|
+
commandSpec({
|
|
7
|
+
command: ["clip-share-pages", "get"],
|
|
8
|
+
usage: "blitzreels clip-share-pages get --asset-id ID [--json]",
|
|
9
|
+
flags: ["asset-id"],
|
|
10
|
+
description: "Inspect the public clip share page and its hidden clip ids.",
|
|
11
|
+
}),
|
|
12
|
+
commandSpec({
|
|
13
|
+
command: ["clip-share-pages", "publish"],
|
|
14
|
+
usage: "blitzreels clip-share-pages publish --asset-id ID --idempotency-key KEY [--dry-run] [--json]",
|
|
15
|
+
flags: ["asset-id", { name: "idempotency-key", required: true }],
|
|
16
|
+
description: "Publish the clip share page for a source asset.",
|
|
17
|
+
mutates: true,
|
|
18
|
+
dryRunSupported: true,
|
|
19
|
+
}),
|
|
20
|
+
commandSpec({
|
|
21
|
+
command: ["clip-share-pages", "unpublish"],
|
|
22
|
+
usage: "blitzreels clip-share-pages unpublish --asset-id ID --idempotency-key KEY [--dry-run] [--json]",
|
|
23
|
+
flags: ["asset-id", { name: "idempotency-key", required: true }],
|
|
24
|
+
description: "Disable the public clip share page for a source asset.",
|
|
25
|
+
mutates: true,
|
|
26
|
+
dryRunSupported: true,
|
|
27
|
+
}),
|
|
28
|
+
commandSpec({
|
|
29
|
+
command: ["clip-share-pages", "set-clip-visibility"],
|
|
30
|
+
usage: "blitzreels clip-share-pages set-clip-visibility --asset-id ID --clip-id ID --visibility visible|hidden --idempotency-key KEY [--dry-run] [--json]",
|
|
31
|
+
flags: [
|
|
32
|
+
"asset-id",
|
|
33
|
+
"clip-id",
|
|
34
|
+
{ name: "visibility", enum: ["visible", "hidden"], required: true },
|
|
35
|
+
{ name: "idempotency-key", required: true },
|
|
36
|
+
],
|
|
37
|
+
description: "Show or hide one clip on its source asset share page.",
|
|
38
|
+
mutates: true,
|
|
39
|
+
dryRunSupported: true,
|
|
40
|
+
}),
|
|
41
|
+
commandSpec({
|
|
42
|
+
command: ["clip-batches", "get"],
|
|
43
|
+
usage: "blitzreels clip-batches get --batch-id ID [--json]",
|
|
44
|
+
flags: ["batch-id"],
|
|
45
|
+
description: "Inspect clip batch progress, Studio Sound status, and terminal errors.",
|
|
46
|
+
}),
|
|
47
|
+
commandSpec({
|
|
48
|
+
command: ["clip-batches", "wait"],
|
|
49
|
+
usage: "blitzreels clip-batches wait --batch-id ID [--interval-ms 3000] [--timeout-ms 1200000] [--json]",
|
|
50
|
+
flags: ["batch-id", "interval-ms", "timeout-ms"],
|
|
51
|
+
description: "Wait for a clip batch to complete or fail, including asynchronous Studio Sound.",
|
|
52
|
+
}),
|
|
53
|
+
commandSpec({
|
|
54
|
+
command: ["clip-batches", "recover"],
|
|
55
|
+
usage: "blitzreels clip-batches recover --batch-id ID [--target-count 10] --idempotency-key KEY [--dry-run] [--json]",
|
|
56
|
+
flags: [
|
|
57
|
+
"batch-id",
|
|
58
|
+
{ name: "target-count", type: "number" },
|
|
59
|
+
{ name: "idempotency-key", required: true },
|
|
60
|
+
],
|
|
61
|
+
description: "Preserve accepted clips and refill a terminal batch in its existing project folder.",
|
|
62
|
+
mutates: true,
|
|
63
|
+
dryRunSupported: true,
|
|
64
|
+
}),
|
|
5
65
|
commandSpec({
|
|
6
66
|
command: ["clip-batches", "delete"],
|
|
7
67
|
usage: "blitzreels clip-batches delete --batch-id ID --retention retain_projects_and_exports|delete_projects_and_exports --idempotency-key KEY --confirm-delete [--dry-run] [--json]",
|
|
@@ -47,9 +107,37 @@ export const CLIPS_COMMAND_SPECS = [
|
|
|
47
107
|
],
|
|
48
108
|
description: "List managed clip runs with bounded output.",
|
|
49
109
|
}),
|
|
110
|
+
commandSpec({
|
|
111
|
+
command: ["clips", "attach-export"],
|
|
112
|
+
usage: "blitzreels clips attach-export --asset-id ID --project-id ID --export-id ID --confirm-visual-qa --idempotency-key KEY [--dry-run] [--json]",
|
|
113
|
+
flags: [
|
|
114
|
+
"asset-id",
|
|
115
|
+
"project-id",
|
|
116
|
+
"export-id",
|
|
117
|
+
{ name: "confirm-visual-qa", required: true },
|
|
118
|
+
{ name: "idempotency-key", required: true },
|
|
119
|
+
],
|
|
120
|
+
description: "Attach one visually accepted completed project export to managed clips.",
|
|
121
|
+
mutates: true,
|
|
122
|
+
destructive: true,
|
|
123
|
+
dryRunSupported: true,
|
|
124
|
+
}),
|
|
125
|
+
commandSpec({
|
|
126
|
+
command: ["clips", "promote-export"],
|
|
127
|
+
usage: "blitzreels clips promote-export --clip-id ID --export-id ID --confirm-visual-qa --idempotency-key KEY [--dry-run] [--json]",
|
|
128
|
+
flags: [
|
|
129
|
+
"clip-id",
|
|
130
|
+
"export-id",
|
|
131
|
+
{ name: "confirm-visual-qa", required: true },
|
|
132
|
+
{ name: "idempotency-key", required: true },
|
|
133
|
+
],
|
|
134
|
+
description: "Promote one visually accepted completed export as the managed clip delivery.",
|
|
135
|
+
mutates: true,
|
|
136
|
+
dryRunSupported: true,
|
|
137
|
+
}),
|
|
50
138
|
commandSpec({
|
|
51
139
|
command: ["clips", "create"],
|
|
52
|
-
usage: "blitzreels clips create [--asset-id ID|--youtube-url URL] [--output ./clips] [--count 5] [--idempotency-key KEY]",
|
|
140
|
+
usage: "blitzreels clips create [--asset-id ID|--youtube-url URL] [--output ./clips] [--count 5] [--layout-mode people_first] [--content-type-hint podcast] [--idempotency-key KEY]",
|
|
53
141
|
flags: [
|
|
54
142
|
{ name: "asset-id", enum: [] },
|
|
55
143
|
"youtube-url",
|
|
@@ -62,7 +150,7 @@ export const CLIPS_COMMAND_SPECS = [
|
|
|
62
150
|
name: "count",
|
|
63
151
|
type: "number",
|
|
64
152
|
default: 5,
|
|
65
|
-
description: "Maximum
|
|
153
|
+
description: "Maximum clips created by the batch.",
|
|
66
154
|
},
|
|
67
155
|
{
|
|
68
156
|
name: "preset",
|
|
@@ -79,6 +167,23 @@ export const CLIPS_COMMAND_SPECS = [
|
|
|
79
167
|
hidden: false,
|
|
80
168
|
},
|
|
81
169
|
{ name: "caption-theme-id" },
|
|
170
|
+
{
|
|
171
|
+
name: "layout-mode",
|
|
172
|
+
enum: [
|
|
173
|
+
"auto",
|
|
174
|
+
"people_first",
|
|
175
|
+
"screen_first",
|
|
176
|
+
"preserve_full_source",
|
|
177
|
+
"prefer_split",
|
|
178
|
+
"prefer_focus",
|
|
179
|
+
"prefer_tutorial",
|
|
180
|
+
"prefer_demo",
|
|
181
|
+
],
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
name: "content-type-hint",
|
|
185
|
+
enum: ["auto", "podcast", "tutorial", "demo", "generic"],
|
|
186
|
+
},
|
|
82
187
|
{
|
|
83
188
|
name: "idempotency-key",
|
|
84
189
|
description: "Stable retry key; reuse only with identical inputs.",
|
|
@@ -90,6 +195,7 @@ export const CLIPS_COMMAND_SPECS = [
|
|
|
90
195
|
examples: [
|
|
91
196
|
"blitzreels clips create --asset-id ID --output ./clips",
|
|
92
197
|
"blitzreels clips create --asset-id ID --logo-asset-id LOGO_ID --output ./clips --count 5",
|
|
198
|
+
"blitzreels clips create --asset-id ID --layout-mode people_first --content-type-hint podcast",
|
|
93
199
|
"blitzreels clips create --youtube-url https://youtube.com/watch?v=...",
|
|
94
200
|
],
|
|
95
201
|
}),
|
|
@@ -107,7 +213,7 @@ export const CLIPS_COMMAND_SPECS = [
|
|
|
107
213
|
}),
|
|
108
214
|
commandSpec({
|
|
109
215
|
command: ["clips", "reselect"],
|
|
110
|
-
usage: "blitzreels clips reselect --clip-id ID [--suggestion-id ID | --start-seconds 52 --end-seconds 64]",
|
|
216
|
+
usage: "blitzreels clips reselect --clip-id ID [--suggestion-id ID | --start-seconds 52 --end-seconds 64] [--layout-mode people_first] [--content-type-hint podcast] [--caption-style-id cinematic-film] [--caption-word-reveal-animation fade] [--caption-max-lines 2] [--caption-words-per-line 8] [--caption-page-combine-ms 3000]",
|
|
111
217
|
flags: [
|
|
112
218
|
"clip-id",
|
|
113
219
|
"suggestion-id",
|
|
@@ -120,8 +226,54 @@ export const CLIPS_COMMAND_SPECS = [
|
|
|
120
226
|
},
|
|
121
227
|
{ name: "min-duration", hidden: true },
|
|
122
228
|
{ name: "max-duration", hidden: true },
|
|
229
|
+
{
|
|
230
|
+
name: "layout-mode",
|
|
231
|
+
enum: [
|
|
232
|
+
"auto",
|
|
233
|
+
"people_first",
|
|
234
|
+
"screen_first",
|
|
235
|
+
"preserve_full_source",
|
|
236
|
+
"prefer_split",
|
|
237
|
+
"prefer_focus",
|
|
238
|
+
"prefer_tutorial",
|
|
239
|
+
"prefer_demo",
|
|
240
|
+
],
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
name: "content-type-hint",
|
|
244
|
+
enum: ["auto", "podcast", "tutorial", "demo", "generic"],
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
name: "tutorial-stack-ratio",
|
|
248
|
+
enum: ["screen_70_face_30", "screen_50_face_50"],
|
|
249
|
+
hidden: true,
|
|
250
|
+
},
|
|
251
|
+
"captions-enabled",
|
|
252
|
+
"caption-style-id",
|
|
253
|
+
{
|
|
254
|
+
name: "caption-word-reveal-animation",
|
|
255
|
+
enum: [
|
|
256
|
+
"none",
|
|
257
|
+
"fade",
|
|
258
|
+
"scale",
|
|
259
|
+
"slide-up",
|
|
260
|
+
"slide-left",
|
|
261
|
+
"slide-mix",
|
|
262
|
+
"pop",
|
|
263
|
+
"drop",
|
|
264
|
+
"slam",
|
|
265
|
+
"typewriter",
|
|
266
|
+
"glitch",
|
|
267
|
+
"mask-reveal",
|
|
268
|
+
"bounce-up",
|
|
269
|
+
"split-reveal",
|
|
270
|
+
],
|
|
271
|
+
},
|
|
272
|
+
"caption-max-lines",
|
|
273
|
+
"caption-words-per-line",
|
|
274
|
+
"caption-page-combine-ms",
|
|
123
275
|
],
|
|
124
|
-
description: "
|
|
276
|
+
description: "Regenerate a clip from a suggestion or time range with optional layout and caption settings.",
|
|
125
277
|
mutates: true,
|
|
126
278
|
}),
|
|
127
279
|
commandSpec({
|
|
@@ -163,10 +315,101 @@ export const CLIPS_COMMAND_SPECS = [
|
|
|
163
315
|
mutates: true,
|
|
164
316
|
}),
|
|
165
317
|
];
|
|
318
|
+
function parseClipShareVisibility({ value, }) {
|
|
319
|
+
if (value === "visible" || value === "hidden") {
|
|
320
|
+
return value;
|
|
321
|
+
}
|
|
322
|
+
throw new CliUsageError({
|
|
323
|
+
code: "invalid_flag_value",
|
|
324
|
+
message: "--visibility must be visible or hidden.",
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
function printClipBatchResult({ context, result, helpers, }) {
|
|
328
|
+
helpers.printResult({
|
|
329
|
+
json: context.json,
|
|
330
|
+
value: result,
|
|
331
|
+
human: [
|
|
332
|
+
`Batch ${result.batch.batch_id}: ${result.batch.status}`,
|
|
333
|
+
`Studio Sound: ${result.batch.studio_sound.status}`,
|
|
334
|
+
`Accepted: ${result.batch.rendered_count}/${result.batch.estimated_clip_count}`,
|
|
335
|
+
...(result.batch.last_error_message === null
|
|
336
|
+
? []
|
|
337
|
+
: [`Error: ${result.batch.last_error_message}`]),
|
|
338
|
+
],
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
async function waitForClipBatch({ context, helpers, }) {
|
|
342
|
+
const batchId = helpers.requireStringFlag({
|
|
343
|
+
flags: context.args.flags,
|
|
344
|
+
name: "batch-id",
|
|
345
|
+
});
|
|
346
|
+
const intervalMs = helpers.getNumberFlag({
|
|
347
|
+
flags: context.args.flags,
|
|
348
|
+
name: "interval-ms",
|
|
349
|
+
}) ?? 3000;
|
|
350
|
+
const timeoutMs = helpers.getNumberFlag({
|
|
351
|
+
flags: context.args.flags,
|
|
352
|
+
name: "timeout-ms",
|
|
353
|
+
}) ?? 20 * 60 * 1000;
|
|
354
|
+
const startedAt = Date.now();
|
|
355
|
+
while (true) {
|
|
356
|
+
const result = await context.client.clipBatches.get({ batchId });
|
|
357
|
+
if (result.batch.studio_sound.status === "failed") {
|
|
358
|
+
throw new CliOperationError({
|
|
359
|
+
code: "studio_sound_failed",
|
|
360
|
+
exitCode: 5,
|
|
361
|
+
message: `Clip batch ${batchId} failed Studio Sound: ${result.batch.studio_sound.error_message ?? result.batch.last_error_message ?? "treatment was not applied"}`,
|
|
362
|
+
retryable: false,
|
|
363
|
+
suggestions: [
|
|
364
|
+
`blitzreels clip-batches recover --batch-id ${batchId} --idempotency-key NEW_KEY --json`,
|
|
365
|
+
],
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
if (result.batch.status === "failed") {
|
|
369
|
+
throw new CliOperationError({
|
|
370
|
+
code: "clip_batch_failed",
|
|
371
|
+
exitCode: 5,
|
|
372
|
+
message: `Clip batch ${batchId} failed: ${result.batch.last_error_message ?? result.batch.studio_sound.error_message ?? "clip processing failed"}`,
|
|
373
|
+
retryable: false,
|
|
374
|
+
suggestions: [
|
|
375
|
+
`blitzreels clip-batches recover --batch-id ${batchId} --idempotency-key NEW_KEY --json`,
|
|
376
|
+
],
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
if (result.batch.status === "completed_with_errors") {
|
|
380
|
+
throw new CliOperationError({
|
|
381
|
+
code: "clip_batch_incomplete",
|
|
382
|
+
exitCode: 5,
|
|
383
|
+
message: `Clip batch ${batchId} completed with ${result.batch.failed_count + result.batch.review_count} clips needing recovery.`,
|
|
384
|
+
retryable: false,
|
|
385
|
+
suggestions: [
|
|
386
|
+
`blitzreels clip-batches recover --batch-id ${batchId} --idempotency-key NEW_KEY --json`,
|
|
387
|
+
],
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
if (result.batch.status === "completed") {
|
|
391
|
+
return result;
|
|
392
|
+
}
|
|
393
|
+
if (Date.now() - startedAt >= timeoutMs) {
|
|
394
|
+
throw new CliOperationError({
|
|
395
|
+
code: "clip_batch_wait_timeout",
|
|
396
|
+
exitCode: 7,
|
|
397
|
+
message: `Timed out waiting for clip batch ${batchId}.`,
|
|
398
|
+
retryable: true,
|
|
399
|
+
suggestions: [
|
|
400
|
+
`blitzreels clip-batches get --batch-id ${batchId} --json`,
|
|
401
|
+
],
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
await helpers.sleep({ ms: intervalMs });
|
|
405
|
+
}
|
|
406
|
+
}
|
|
166
407
|
export function createClipsCommandOperation({ helpers, }) {
|
|
167
408
|
return {
|
|
168
409
|
name: "clips",
|
|
169
|
-
matches: ({ command }) => command[0] === "clips" ||
|
|
410
|
+
matches: ({ command }) => command[0] === "clips" ||
|
|
411
|
+
command[0] === "clip-batches" ||
|
|
412
|
+
command[0] === "clip-share-pages",
|
|
170
413
|
handle: ({ context }) => handleClipsCommand({ context, helpers }),
|
|
171
414
|
buildDryRun: ({ context, spec }) => buildClipsDryRun({ context, spec, helpers }),
|
|
172
415
|
};
|
|
@@ -174,6 +417,114 @@ export function createClipsCommandOperation({ helpers, }) {
|
|
|
174
417
|
async function handleClipsCommand({ context, helpers, }) {
|
|
175
418
|
const action = context.args.command[1];
|
|
176
419
|
const flags = context.args.flags;
|
|
420
|
+
if (context.args.command[0] === "clip-share-pages") {
|
|
421
|
+
const assetId = helpers.requireStringFlag({ flags, name: "asset-id" });
|
|
422
|
+
if (action === "get") {
|
|
423
|
+
const result = await context.client.clipSharePages.get({ assetId });
|
|
424
|
+
helpers.printResult({
|
|
425
|
+
json: context.json,
|
|
426
|
+
value: result,
|
|
427
|
+
human: [
|
|
428
|
+
result.enabled
|
|
429
|
+
? `Published: ${result.share_url}`
|
|
430
|
+
: "Share page is not published.",
|
|
431
|
+
`Hidden clips: ${result.hidden_clip_ids.length}`,
|
|
432
|
+
],
|
|
433
|
+
});
|
|
434
|
+
return true;
|
|
435
|
+
}
|
|
436
|
+
if (action === "publish" || action === "unpublish") {
|
|
437
|
+
const result = await context.client.clipSharePages.setEnabled({
|
|
438
|
+
assetId,
|
|
439
|
+
enabled: action === "publish",
|
|
440
|
+
idempotencyKey: helpers.requireStringFlag({
|
|
441
|
+
flags,
|
|
442
|
+
name: "idempotency-key",
|
|
443
|
+
}),
|
|
444
|
+
});
|
|
445
|
+
helpers.printResult({
|
|
446
|
+
json: context.json,
|
|
447
|
+
value: result,
|
|
448
|
+
human: [
|
|
449
|
+
result.enabled
|
|
450
|
+
? `Published: ${result.share_url}`
|
|
451
|
+
: "Share page unpublished.",
|
|
452
|
+
],
|
|
453
|
+
});
|
|
454
|
+
return true;
|
|
455
|
+
}
|
|
456
|
+
if (action === "set-clip-visibility") {
|
|
457
|
+
const visibility = parseClipShareVisibility({
|
|
458
|
+
value: helpers.requireStringFlag({
|
|
459
|
+
flags,
|
|
460
|
+
name: "visibility",
|
|
461
|
+
}),
|
|
462
|
+
});
|
|
463
|
+
const result = await context.client.clipSharePages.setClipVisibility({
|
|
464
|
+
assetId,
|
|
465
|
+
clipId: helpers.requireStringFlag({ flags, name: "clip-id" }),
|
|
466
|
+
visibility,
|
|
467
|
+
idempotencyKey: helpers.requireStringFlag({
|
|
468
|
+
flags,
|
|
469
|
+
name: "idempotency-key",
|
|
470
|
+
}),
|
|
471
|
+
});
|
|
472
|
+
helpers.printResult({
|
|
473
|
+
json: context.json,
|
|
474
|
+
value: result,
|
|
475
|
+
human: [`Clip ${result.clip_id}: ${result.visibility}`],
|
|
476
|
+
});
|
|
477
|
+
return true;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
if (context.args.command[0] === "clip-batches" && action === "get") {
|
|
481
|
+
const result = await context.client.clipBatches.get({
|
|
482
|
+
batchId: helpers.requireStringFlag({ flags, name: "batch-id" }),
|
|
483
|
+
});
|
|
484
|
+
printClipBatchResult({ context, result, helpers });
|
|
485
|
+
return true;
|
|
486
|
+
}
|
|
487
|
+
if (context.args.command[0] === "clip-batches" && action === "wait") {
|
|
488
|
+
const result = await waitForClipBatch({ context, helpers });
|
|
489
|
+
printClipBatchResult({ context, result, helpers });
|
|
490
|
+
return true;
|
|
491
|
+
}
|
|
492
|
+
if (context.args.command[0] === "clip-batches" && action === "recover") {
|
|
493
|
+
const result = await context.client.clipBatches.recover({
|
|
494
|
+
batchId: helpers.requireStringFlag({ flags, name: "batch-id" }),
|
|
495
|
+
targetClipCount: helpers.getNumberFlag({ flags, name: "target-count" }) ?? null,
|
|
496
|
+
idempotencyKey: helpers.requireStringFlag({
|
|
497
|
+
flags,
|
|
498
|
+
name: "idempotency-key",
|
|
499
|
+
}),
|
|
500
|
+
});
|
|
501
|
+
if (result.status === "failed") {
|
|
502
|
+
throw new CliOperationError({
|
|
503
|
+
code: "clip_batch_recovery_failed",
|
|
504
|
+
exitCode: 5,
|
|
505
|
+
message: `Recovery batch ${result.recovery_batch_id ?? result.source_batch_id} failed: ${result.queue_reason ?? "clip recovery failed"}`,
|
|
506
|
+
retryable: false,
|
|
507
|
+
suggestions: [
|
|
508
|
+
'blitzreels agent-context --command "clip-batches recover" --json',
|
|
509
|
+
],
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
const statusLine = result.status === "satisfied"
|
|
513
|
+
? `Batch ${result.source_batch_id} already has ${result.retained_clip_count}/${result.target_clip_count} accepted clips.`
|
|
514
|
+
: result.status === "queued"
|
|
515
|
+
? `Recovery batch ${result.recovery_batch_id} queued for ${result.refill_clip_count} missing clips.`
|
|
516
|
+
: `Recovery batch ${result.recovery_batch_id} created; waiting: ${result.queue_reason ?? "not ready to queue"}.`;
|
|
517
|
+
helpers.printResult({
|
|
518
|
+
json: context.json,
|
|
519
|
+
value: result,
|
|
520
|
+
human: [
|
|
521
|
+
statusLine,
|
|
522
|
+
`Folder: ${result.project_folder_id}`,
|
|
523
|
+
"Duration policy: quality first; suggestion boundaries preserved.",
|
|
524
|
+
],
|
|
525
|
+
});
|
|
526
|
+
return true;
|
|
527
|
+
}
|
|
177
528
|
if (context.args.command[0] === "clip-batches" && action === "delete") {
|
|
178
529
|
if (helpers.getOptionalBooleanFlag({ flags, name: "confirm-delete" }) !== true) {
|
|
179
530
|
throw new Error("Pass --confirm-delete to delete a clip batch.");
|
|
@@ -216,6 +567,66 @@ async function handleClipsCommand({ context, helpers, }) {
|
|
|
216
567
|
});
|
|
217
568
|
return true;
|
|
218
569
|
}
|
|
570
|
+
if (action === "attach-export") {
|
|
571
|
+
if (helpers.getOptionalBooleanFlag({
|
|
572
|
+
flags,
|
|
573
|
+
name: "confirm-visual-qa",
|
|
574
|
+
}) !== true) {
|
|
575
|
+
throw new CliUsageError({
|
|
576
|
+
code: "missing_visual_qa_confirmation",
|
|
577
|
+
message: "Pass --confirm-visual-qa only after reviewing the completed MP4.",
|
|
578
|
+
usage: "blitzreels clips attach-export --asset-id ID --project-id ID --export-id ID --confirm-visual-qa --idempotency-key KEY",
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
const result = await context.client.clips.attachExport({
|
|
582
|
+
assetId: helpers.requireStringFlag({ flags, name: "asset-id" }),
|
|
583
|
+
projectId: helpers.requireStringFlag({ flags, name: "project-id" }),
|
|
584
|
+
exportId: helpers.requireStringFlag({ flags, name: "export-id" }),
|
|
585
|
+
confirmVisualQa: true,
|
|
586
|
+
idempotencyKey: helpers.requireStringFlag({
|
|
587
|
+
flags,
|
|
588
|
+
name: "idempotency-key",
|
|
589
|
+
}),
|
|
590
|
+
});
|
|
591
|
+
helpers.printResult({
|
|
592
|
+
json: context.json,
|
|
593
|
+
value: result,
|
|
594
|
+
human: [
|
|
595
|
+
`Attached export ${result.export_id} to managed clip ${result.clip_id}.`,
|
|
596
|
+
],
|
|
597
|
+
});
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
600
|
+
if (action === "promote-export") {
|
|
601
|
+
if (helpers.getOptionalBooleanFlag({
|
|
602
|
+
flags,
|
|
603
|
+
name: "confirm-visual-qa",
|
|
604
|
+
}) !== true) {
|
|
605
|
+
throw new CliUsageError({
|
|
606
|
+
code: "missing_visual_qa_confirmation",
|
|
607
|
+
message: "Pass --confirm-visual-qa only after reviewing the completed MP4.",
|
|
608
|
+
usage: "blitzreels clips promote-export --clip-id ID --export-id ID --confirm-visual-qa --idempotency-key KEY",
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
const result = await context.client.clips.promoteExport({
|
|
612
|
+
clipId: helpers.requireStringFlag({ flags, name: "clip-id" }),
|
|
613
|
+
exportId: helpers.requireStringFlag({ flags, name: "export-id" }),
|
|
614
|
+
confirmVisualQa: true,
|
|
615
|
+
idempotencyKey: helpers.requireStringFlag({
|
|
616
|
+
flags,
|
|
617
|
+
name: "idempotency-key",
|
|
618
|
+
}),
|
|
619
|
+
});
|
|
620
|
+
helpers.printResult({
|
|
621
|
+
json: context.json,
|
|
622
|
+
value: result,
|
|
623
|
+
human: [
|
|
624
|
+
`Promoted export ${result.export_id} for managed clip ${result.clip_id}.`,
|
|
625
|
+
`Previous export retained: ${result.previous_export_id}.`,
|
|
626
|
+
],
|
|
627
|
+
});
|
|
628
|
+
return true;
|
|
629
|
+
}
|
|
219
630
|
if (action === "list") {
|
|
220
631
|
const result = await context.client.clips.list({
|
|
221
632
|
assetId: helpers.getStringFlag({ flags, name: "asset-id" }),
|
|
@@ -259,6 +670,8 @@ async function handleClipsCommand({ context, helpers, }) {
|
|
|
259
670
|
flags,
|
|
260
671
|
name: "selection-mode",
|
|
261
672
|
});
|
|
673
|
+
const layout = buildReselectLayout({ flags, helpers });
|
|
674
|
+
const captions = buildReselectCaptions({ flags, helpers });
|
|
262
675
|
const result = await context.client.clips.reselect({
|
|
263
676
|
clipId,
|
|
264
677
|
...(selectionMode === undefined
|
|
@@ -267,10 +680,14 @@ async function handleClipsCommand({ context, helpers, }) {
|
|
|
267
680
|
startSeconds: selection.startSeconds,
|
|
268
681
|
endSeconds: selection.endSeconds,
|
|
269
682
|
target,
|
|
683
|
+
layout,
|
|
684
|
+
captions,
|
|
270
685
|
}
|
|
271
686
|
: {
|
|
272
687
|
selection,
|
|
273
688
|
target,
|
|
689
|
+
layout,
|
|
690
|
+
captions,
|
|
274
691
|
}),
|
|
275
692
|
});
|
|
276
693
|
helpers.printClipResult({ context, result });
|
|
@@ -342,6 +759,122 @@ function formatClipListLine({ clip }) {
|
|
|
342
759
|
function buildClipsDryRun({ context, spec, helpers, }) {
|
|
343
760
|
const action = context.args.command[1];
|
|
344
761
|
const flags = context.args.flags;
|
|
762
|
+
if (context.args.command[0] === "clips" && action === "attach-export") {
|
|
763
|
+
if (helpers.getOptionalBooleanFlag({
|
|
764
|
+
flags,
|
|
765
|
+
name: "confirm-visual-qa",
|
|
766
|
+
}) !== true) {
|
|
767
|
+
throw new CliUsageError({
|
|
768
|
+
code: "missing_visual_qa_confirmation",
|
|
769
|
+
message: "Pass --confirm-visual-qa only after reviewing the completed MP4.",
|
|
770
|
+
usage: "blitzreels clips attach-export --asset-id ID --project-id ID --export-id ID --confirm-visual-qa --idempotency-key KEY",
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
return helpers.dryRunRequest({
|
|
774
|
+
spec,
|
|
775
|
+
method: "POST",
|
|
776
|
+
path: "/clips/attach-export",
|
|
777
|
+
headers: {
|
|
778
|
+
"Idempotency-Key": helpers.requireStringFlag({
|
|
779
|
+
flags,
|
|
780
|
+
name: "idempotency-key",
|
|
781
|
+
}),
|
|
782
|
+
},
|
|
783
|
+
body: {
|
|
784
|
+
asset_id: helpers.requireStringFlag({ flags, name: "asset-id" }),
|
|
785
|
+
project_id: helpers.requireStringFlag({ flags, name: "project-id" }),
|
|
786
|
+
export_id: helpers.requireStringFlag({ flags, name: "export-id" }),
|
|
787
|
+
confirm_visual_qa: true,
|
|
788
|
+
},
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
if (context.args.command[0] === "clips" && action === "promote-export") {
|
|
792
|
+
if (helpers.getOptionalBooleanFlag({
|
|
793
|
+
flags,
|
|
794
|
+
name: "confirm-visual-qa",
|
|
795
|
+
}) !== true) {
|
|
796
|
+
throw new CliUsageError({
|
|
797
|
+
code: "missing_visual_qa_confirmation",
|
|
798
|
+
message: "Pass --confirm-visual-qa only after reviewing the completed MP4.",
|
|
799
|
+
usage: "blitzreels clips promote-export --clip-id ID --export-id ID --confirm-visual-qa --idempotency-key KEY",
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
const clipId = helpers.requireStringFlag({ flags, name: "clip-id" });
|
|
803
|
+
return helpers.dryRunRequest({
|
|
804
|
+
spec,
|
|
805
|
+
method: "POST",
|
|
806
|
+
path: `/clips/${encodeURIComponent(clipId)}/promote-export`,
|
|
807
|
+
headers: {
|
|
808
|
+
"Idempotency-Key": helpers.requireStringFlag({
|
|
809
|
+
flags,
|
|
810
|
+
name: "idempotency-key",
|
|
811
|
+
}),
|
|
812
|
+
},
|
|
813
|
+
body: {
|
|
814
|
+
export_id: helpers.requireStringFlag({ flags, name: "export-id" }),
|
|
815
|
+
confirm_visual_qa: true,
|
|
816
|
+
},
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
if (context.args.command[0] === "clip-share-pages") {
|
|
820
|
+
const assetId = helpers.requireStringFlag({ flags, name: "asset-id" });
|
|
821
|
+
if (action === "publish" || action === "unpublish") {
|
|
822
|
+
return helpers.dryRunRequest({
|
|
823
|
+
spec,
|
|
824
|
+
method: "POST",
|
|
825
|
+
path: `/clip-share-pages/${encodeURIComponent(assetId)}`,
|
|
826
|
+
headers: {
|
|
827
|
+
"Idempotency-Key": helpers.requireStringFlag({
|
|
828
|
+
flags,
|
|
829
|
+
name: "idempotency-key",
|
|
830
|
+
}),
|
|
831
|
+
},
|
|
832
|
+
body: { enabled: action === "publish" },
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
if (action === "set-clip-visibility") {
|
|
836
|
+
const clipId = helpers.requireStringFlag({ flags, name: "clip-id" });
|
|
837
|
+
return helpers.dryRunRequest({
|
|
838
|
+
spec,
|
|
839
|
+
method: "POST",
|
|
840
|
+
path: `/clip-share-pages/${encodeURIComponent(assetId)}/clips/${encodeURIComponent(clipId)}/visibility`,
|
|
841
|
+
headers: {
|
|
842
|
+
"Idempotency-Key": helpers.requireStringFlag({
|
|
843
|
+
flags,
|
|
844
|
+
name: "idempotency-key",
|
|
845
|
+
}),
|
|
846
|
+
},
|
|
847
|
+
body: {
|
|
848
|
+
visibility: parseClipShareVisibility({
|
|
849
|
+
value: helpers.requireStringFlag({
|
|
850
|
+
flags,
|
|
851
|
+
name: "visibility",
|
|
852
|
+
}),
|
|
853
|
+
}),
|
|
854
|
+
},
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
if (context.args.command[0] === "clip-batches" && action === "recover") {
|
|
859
|
+
return helpers.dryRunRequest({
|
|
860
|
+
spec,
|
|
861
|
+
method: "POST",
|
|
862
|
+
path: `/clip-batches/${encodeURIComponent(helpers.requireStringFlag({ flags, name: "batch-id" }))}/recover`,
|
|
863
|
+
headers: {
|
|
864
|
+
"Idempotency-Key": helpers.requireStringFlag({
|
|
865
|
+
flags,
|
|
866
|
+
name: "idempotency-key",
|
|
867
|
+
}),
|
|
868
|
+
},
|
|
869
|
+
body: {
|
|
870
|
+
target_clip_count: helpers.getNumberFlag({ flags, name: "target-count" }) ?? null,
|
|
871
|
+
},
|
|
872
|
+
notes: [
|
|
873
|
+
"Accepted exports remain linked; only the missing accepted count is refilled.",
|
|
874
|
+
"Suggestion boundaries are preserved even when a coherent clip exceeds the target duration.",
|
|
875
|
+
],
|
|
876
|
+
});
|
|
877
|
+
}
|
|
345
878
|
if (context.args.command[0] === "clip-batches" && action === "delete") {
|
|
346
879
|
return helpers.dryRunRequest({
|
|
347
880
|
spec,
|
|
@@ -392,8 +925,9 @@ function buildClipsDryRun({ context, spec, helpers, }) {
|
|
|
392
925
|
quality: null,
|
|
393
926
|
},
|
|
394
927
|
clip_preset_id: options.clipPresetId,
|
|
928
|
+
max_clip_count: options.count,
|
|
395
929
|
caption_theme_id: options.captionThemeId,
|
|
396
|
-
create_flow_options: {},
|
|
930
|
+
create_flow_options: buildClipWorkflowCreateFlowOptions({ options }),
|
|
397
931
|
branding_options: buildClipWorkflowBrandingOptions({
|
|
398
932
|
logoAssetId: options.logoAssetId,
|
|
399
933
|
}),
|
|
@@ -426,6 +960,8 @@ function buildClipsDryRun({ context, spec, helpers, }) {
|
|
|
426
960
|
flags,
|
|
427
961
|
name: "selection-mode",
|
|
428
962
|
});
|
|
963
|
+
const layout = buildReselectLayout({ flags, helpers });
|
|
964
|
+
const captions = buildReselectCaptions({ flags, helpers });
|
|
429
965
|
return helpers.dryRunRequest({
|
|
430
966
|
spec,
|
|
431
967
|
method: "POST",
|
|
@@ -449,6 +985,12 @@ function buildClipsDryRun({ context, spec, helpers, }) {
|
|
|
449
985
|
max_duration_seconds: target.maxDurationSeconds,
|
|
450
986
|
},
|
|
451
987
|
}),
|
|
988
|
+
...(layout === null
|
|
989
|
+
? {}
|
|
990
|
+
: { layout: toApiClipLayout({ layout }) }),
|
|
991
|
+
...(captions === null
|
|
992
|
+
? {}
|
|
993
|
+
: { captions: toApiClipCaptions({ captions }) }),
|
|
452
994
|
}
|
|
453
995
|
: {
|
|
454
996
|
selection: toApiClipSelection({ selection }),
|
|
@@ -458,6 +1000,8 @@ function buildClipsDryRun({ context, spec, helpers, }) {
|
|
|
458
1000
|
min_duration_seconds: target.minDurationSeconds,
|
|
459
1001
|
max_duration_seconds: target.maxDurationSeconds,
|
|
460
1002
|
},
|
|
1003
|
+
layout: layout === null ? null : toApiClipLayout({ layout }),
|
|
1004
|
+
captions: captions === null ? null : toApiClipCaptions({ captions }),
|
|
461
1005
|
},
|
|
462
1006
|
});
|
|
463
1007
|
}
|
|
@@ -501,6 +1045,16 @@ function parseClipBatchDeleteRetention({ value, }) {
|
|
|
501
1045
|
}
|
|
502
1046
|
throw new Error("--retention must be retain_projects_and_exports or delete_projects_and_exports.");
|
|
503
1047
|
}
|
|
1048
|
+
function buildClipWorkflowCreateFlowOptions({ options, }) {
|
|
1049
|
+
return {
|
|
1050
|
+
...(options.layoutMode === undefined
|
|
1051
|
+
? {}
|
|
1052
|
+
: { reframeLayoutMode: options.layoutMode }),
|
|
1053
|
+
...(options.contentTypeHint === undefined
|
|
1054
|
+
? {}
|
|
1055
|
+
: { reframeContentTypeHint: options.contentTypeHint }),
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
504
1058
|
function parseClipWorkflowOptions({ flags, helpers, }) {
|
|
505
1059
|
const count = helpers.getNumberFlag({ flags, name: "count" }) ?? 5;
|
|
506
1060
|
if (!Number.isInteger(count) || count < 1 || count > 10) {
|
|
@@ -540,6 +1094,12 @@ function parseClipWorkflowOptions({ flags, helpers, }) {
|
|
|
540
1094
|
captionThemeId: parseNullableWorkflowString({
|
|
541
1095
|
value: helpers.getStringFlag({ flags, name: "caption-theme-id" }),
|
|
542
1096
|
}),
|
|
1097
|
+
layoutMode: parseClipLayoutMode({
|
|
1098
|
+
value: helpers.getStringFlag({ flags, name: "layout-mode" }),
|
|
1099
|
+
}),
|
|
1100
|
+
contentTypeHint: parseClipContentTypeHint({
|
|
1101
|
+
value: helpers.getStringFlag({ flags, name: "content-type-hint" }),
|
|
1102
|
+
}),
|
|
543
1103
|
idempotencyKey: helpers.getStringFlag({ flags, name: "idempotency-key" }) ?? null,
|
|
544
1104
|
};
|
|
545
1105
|
}
|
|
@@ -574,8 +1134,9 @@ async function createClipWorkflow({ context, helpers, }) {
|
|
|
574
1134
|
quality: null,
|
|
575
1135
|
},
|
|
576
1136
|
clipPresetId: options.clipPresetId,
|
|
1137
|
+
maxClipCount: options.count,
|
|
577
1138
|
captionThemeId: options.captionThemeId,
|
|
578
|
-
createFlowOptions: {},
|
|
1139
|
+
createFlowOptions: buildClipWorkflowCreateFlowOptions({ options }),
|
|
579
1140
|
brandingOptions: buildClipWorkflowBrandingOptions({
|
|
580
1141
|
logoAssetId: options.logoAssetId,
|
|
581
1142
|
}),
|
|
@@ -695,4 +1256,138 @@ function toApiClipSelection({ selection, }) {
|
|
|
695
1256
|
end_seconds: selection.endSeconds,
|
|
696
1257
|
};
|
|
697
1258
|
}
|
|
1259
|
+
function parseClipLayoutMode({ value, }) {
|
|
1260
|
+
if (value === undefined ||
|
|
1261
|
+
value === "auto" ||
|
|
1262
|
+
value === "people_first" ||
|
|
1263
|
+
value === "screen_first" ||
|
|
1264
|
+
value === "preserve_full_source" ||
|
|
1265
|
+
value === "prefer_split" ||
|
|
1266
|
+
value === "prefer_focus" ||
|
|
1267
|
+
value === "prefer_tutorial" ||
|
|
1268
|
+
value === "prefer_demo") {
|
|
1269
|
+
return value;
|
|
1270
|
+
}
|
|
1271
|
+
throw new Error(`Unsupported clip layout mode: ${value}`);
|
|
1272
|
+
}
|
|
1273
|
+
function parseClipContentTypeHint({ value, }) {
|
|
1274
|
+
if (value === undefined ||
|
|
1275
|
+
value === "auto" ||
|
|
1276
|
+
value === "podcast" ||
|
|
1277
|
+
value === "tutorial" ||
|
|
1278
|
+
value === "demo" ||
|
|
1279
|
+
value === "generic") {
|
|
1280
|
+
return value;
|
|
1281
|
+
}
|
|
1282
|
+
throw new Error(`Unsupported clip content type hint: ${value}`);
|
|
1283
|
+
}
|
|
1284
|
+
function parseTutorialStackRatio({ value, }) {
|
|
1285
|
+
if (value === undefined ||
|
|
1286
|
+
value === "screen_70_face_30" ||
|
|
1287
|
+
value === "screen_50_face_50") {
|
|
1288
|
+
return value;
|
|
1289
|
+
}
|
|
1290
|
+
throw new Error(`Unsupported tutorial stack ratio: ${value}`);
|
|
1291
|
+
}
|
|
1292
|
+
function buildReselectLayout({ flags, helpers, }) {
|
|
1293
|
+
const mode = parseClipLayoutMode({
|
|
1294
|
+
value: helpers.getStringFlag({ flags, name: "layout-mode" }),
|
|
1295
|
+
});
|
|
1296
|
+
const contentTypeHint = parseClipContentTypeHint({
|
|
1297
|
+
value: helpers.getStringFlag({ flags, name: "content-type-hint" }),
|
|
1298
|
+
});
|
|
1299
|
+
const tutorialStackRatio = parseTutorialStackRatio({
|
|
1300
|
+
value: helpers.getStringFlag({ flags, name: "tutorial-stack-ratio" }),
|
|
1301
|
+
});
|
|
1302
|
+
if (mode === undefined &&
|
|
1303
|
+
contentTypeHint === undefined &&
|
|
1304
|
+
tutorialStackRatio === undefined) {
|
|
1305
|
+
return null;
|
|
1306
|
+
}
|
|
1307
|
+
return { mode, contentTypeHint, tutorialStackRatio };
|
|
1308
|
+
}
|
|
1309
|
+
function buildReselectCaptions({ flags, helpers, }) {
|
|
1310
|
+
const enabled = helpers.getOptionalBooleanFlag({
|
|
1311
|
+
flags,
|
|
1312
|
+
name: "captions-enabled",
|
|
1313
|
+
});
|
|
1314
|
+
const styleId = helpers.getStringFlag({
|
|
1315
|
+
flags,
|
|
1316
|
+
name: "caption-style-id",
|
|
1317
|
+
});
|
|
1318
|
+
const wordRevealAnimation = parseCaptionWordRevealAnimation({
|
|
1319
|
+
value: helpers.getStringFlag({
|
|
1320
|
+
flags,
|
|
1321
|
+
name: "caption-word-reveal-animation",
|
|
1322
|
+
}),
|
|
1323
|
+
});
|
|
1324
|
+
const maxLinesPerCaption = helpers.getNumberFlag({
|
|
1325
|
+
flags,
|
|
1326
|
+
name: "caption-max-lines",
|
|
1327
|
+
});
|
|
1328
|
+
const wordsPerLineLimit = helpers.getNumberFlag({
|
|
1329
|
+
flags,
|
|
1330
|
+
name: "caption-words-per-line",
|
|
1331
|
+
});
|
|
1332
|
+
const pageCombineMs = helpers.getNumberFlag({
|
|
1333
|
+
flags,
|
|
1334
|
+
name: "caption-page-combine-ms",
|
|
1335
|
+
});
|
|
1336
|
+
if (enabled === undefined &&
|
|
1337
|
+
styleId === undefined &&
|
|
1338
|
+
wordRevealAnimation === undefined &&
|
|
1339
|
+
maxLinesPerCaption === undefined &&
|
|
1340
|
+
wordsPerLineLimit === undefined &&
|
|
1341
|
+
pageCombineMs === undefined) {
|
|
1342
|
+
return null;
|
|
1343
|
+
}
|
|
1344
|
+
return {
|
|
1345
|
+
enabled,
|
|
1346
|
+
styleId,
|
|
1347
|
+
wordRevealAnimation,
|
|
1348
|
+
maxLinesPerCaption,
|
|
1349
|
+
wordsPerLineLimit,
|
|
1350
|
+
pageCombineMs,
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
function parseCaptionWordRevealAnimation({ value, }) {
|
|
1354
|
+
const supported = [
|
|
1355
|
+
"none",
|
|
1356
|
+
"fade",
|
|
1357
|
+
"scale",
|
|
1358
|
+
"slide-up",
|
|
1359
|
+
"slide-left",
|
|
1360
|
+
"slide-mix",
|
|
1361
|
+
"pop",
|
|
1362
|
+
"drop",
|
|
1363
|
+
"slam",
|
|
1364
|
+
"typewriter",
|
|
1365
|
+
"glitch",
|
|
1366
|
+
"mask-reveal",
|
|
1367
|
+
"bounce-up",
|
|
1368
|
+
"split-reveal",
|
|
1369
|
+
];
|
|
1370
|
+
if (value === undefined ||
|
|
1371
|
+
supported.some((candidate) => candidate === value)) {
|
|
1372
|
+
return value;
|
|
1373
|
+
}
|
|
1374
|
+
throw new Error(`Unsupported caption word reveal animation: ${value}`);
|
|
1375
|
+
}
|
|
1376
|
+
function toApiClipLayout({ layout }) {
|
|
1377
|
+
return {
|
|
1378
|
+
layout_mode: layout.mode,
|
|
1379
|
+
content_type_hint: layout.contentTypeHint,
|
|
1380
|
+
tutorial_stack_ratio: layout.tutorialStackRatio,
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
function toApiClipCaptions({ captions }) {
|
|
1384
|
+
return {
|
|
1385
|
+
enabled: captions.enabled,
|
|
1386
|
+
style_id: captions.styleId,
|
|
1387
|
+
word_reveal_animation: captions.wordRevealAnimation,
|
|
1388
|
+
max_lines_per_caption: captions.maxLinesPerCaption,
|
|
1389
|
+
words_per_line_limit: captions.wordsPerLineLimit,
|
|
1390
|
+
page_combine_ms: captions.pageCombineMs,
|
|
1391
|
+
};
|
|
1392
|
+
}
|
|
698
1393
|
//# sourceMappingURL=clips.js.map
|