blitzreels 0.1.2 → 0.1.3
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/README.md +45 -2
- package/dist/index.js +1331 -58
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -9,13 +9,465 @@ const KEYCHAIN_SERVICE = "BlitzReels CLI";
|
|
|
9
9
|
const KEYCHAIN_ACCOUNT = "api-key";
|
|
10
10
|
const DEFAULT_WAIT_INTERVAL_MS = 3000;
|
|
11
11
|
const DEFAULT_WAIT_TIMEOUT_MS = 20 * 60 * 1000;
|
|
12
|
+
const GLOBAL_FLAGS = ["api-key", "base-url", "json", "help"];
|
|
13
|
+
const TEXT_STYLE_FLAGS = [
|
|
14
|
+
"spec-json",
|
|
15
|
+
"font-family",
|
|
16
|
+
"font-size",
|
|
17
|
+
"font-weight",
|
|
18
|
+
"color",
|
|
19
|
+
"background-color",
|
|
20
|
+
"padding-x",
|
|
21
|
+
"padding-y",
|
|
22
|
+
"border-radius",
|
|
23
|
+
"top",
|
|
24
|
+
"left",
|
|
25
|
+
"text-align",
|
|
26
|
+
"text-shadow",
|
|
27
|
+
"no-background",
|
|
28
|
+
];
|
|
29
|
+
const CAPTION_WORD_SELECTOR_FLAGS = [
|
|
30
|
+
"word-id",
|
|
31
|
+
"word-ids",
|
|
32
|
+
"timeline-item-id",
|
|
33
|
+
"match-text",
|
|
34
|
+
"match-pattern",
|
|
35
|
+
];
|
|
36
|
+
const CAPTION_WORD_STYLE_FLAGS = [
|
|
37
|
+
"style-json",
|
|
38
|
+
"font-family",
|
|
39
|
+
"font-weight",
|
|
40
|
+
"font-style",
|
|
41
|
+
"color",
|
|
42
|
+
"active-color",
|
|
43
|
+
"background-color",
|
|
44
|
+
"active-animation",
|
|
45
|
+
"text-transform",
|
|
46
|
+
"text-shadow",
|
|
47
|
+
"glow-color",
|
|
48
|
+
"glow-blur-px",
|
|
49
|
+
"scale",
|
|
50
|
+
"offset-x",
|
|
51
|
+
"offset-y",
|
|
52
|
+
"rotation-deg",
|
|
53
|
+
"letter-spacing",
|
|
54
|
+
"opacity",
|
|
55
|
+
"clear-existing",
|
|
56
|
+
];
|
|
57
|
+
function commandSpec({ command, usage, flags = [], }) {
|
|
58
|
+
return { command, usage, flags };
|
|
59
|
+
}
|
|
60
|
+
const COMMAND_SPECS = [
|
|
61
|
+
commandSpec({
|
|
62
|
+
command: ["auth", "login"],
|
|
63
|
+
usage: "blitzreels auth login [--no-browser] [--timeout-ms 120000]",
|
|
64
|
+
flags: ["no-browser", "timeout-ms"],
|
|
65
|
+
}),
|
|
66
|
+
commandSpec({
|
|
67
|
+
command: ["auth", "set-key"],
|
|
68
|
+
usage: "blitzreels auth set-key --api-key KEY [--base-url URL]",
|
|
69
|
+
}),
|
|
70
|
+
commandSpec({
|
|
71
|
+
command: ["auth", "whoami"],
|
|
72
|
+
usage: "blitzreels auth whoami [--json]",
|
|
73
|
+
}),
|
|
74
|
+
commandSpec({
|
|
75
|
+
command: ["workspace", "settings", "get"],
|
|
76
|
+
usage: "blitzreels workspace settings get [--json]",
|
|
77
|
+
}),
|
|
78
|
+
commandSpec({
|
|
79
|
+
command: ["workspace", "settings", "update"],
|
|
80
|
+
usage: "blitzreels workspace settings update [--name NAME] [--description TEXT|null] [--protected-words foo,bar] [--icon-storage-key KEY|null] [--aspect-ratio 9:16] [--orientation portrait] [--resolution 1080p] [--frame-rate 30] [--auto-manage-broll true] [--caption-theme-id ID|null]",
|
|
81
|
+
flags: [
|
|
82
|
+
"name",
|
|
83
|
+
"description",
|
|
84
|
+
"protected-words",
|
|
85
|
+
"icon-storage-key",
|
|
86
|
+
"aspect-ratio",
|
|
87
|
+
"orientation",
|
|
88
|
+
"resolution",
|
|
89
|
+
"frame-rate",
|
|
90
|
+
"auto-manage-broll",
|
|
91
|
+
"caption-theme-id",
|
|
92
|
+
],
|
|
93
|
+
}),
|
|
94
|
+
commandSpec({
|
|
95
|
+
command: ["projects", "list"],
|
|
96
|
+
usage: "blitzreels projects list [--search QUERY] [--status active|archived|all] [--limit 50] [--offset 0] [--cursor CURSOR] [--json]",
|
|
97
|
+
flags: ["search", "status", "limit", "offset", "cursor"],
|
|
98
|
+
}),
|
|
99
|
+
commandSpec({
|
|
100
|
+
command: ["projects", "create"],
|
|
101
|
+
usage: "blitzreels projects create --name NAME [--description TEXT] [--aspect-ratio 9:16] [--project-type video|carousel] [--carousel-settings-json JSON]",
|
|
102
|
+
flags: [
|
|
103
|
+
"name",
|
|
104
|
+
"description",
|
|
105
|
+
"aspect-ratio",
|
|
106
|
+
"project-type",
|
|
107
|
+
"carousel-settings-json",
|
|
108
|
+
],
|
|
109
|
+
}),
|
|
110
|
+
commandSpec({
|
|
111
|
+
command: ["projects", "get"],
|
|
112
|
+
usage: "blitzreels projects get --project-id ID [--json]",
|
|
113
|
+
flags: ["project-id"],
|
|
114
|
+
}),
|
|
115
|
+
commandSpec({
|
|
116
|
+
command: ["projects", "rename"],
|
|
117
|
+
usage: "blitzreels projects rename --project-id ID --name NAME",
|
|
118
|
+
flags: ["project-id", "name"],
|
|
119
|
+
}),
|
|
120
|
+
commandSpec({
|
|
121
|
+
command: ["projects", "update"],
|
|
122
|
+
usage: "blitzreels projects update --project-id ID [--name NAME] [--description TEXT|null]",
|
|
123
|
+
flags: ["project-id", "name", "description"],
|
|
124
|
+
}),
|
|
125
|
+
commandSpec({
|
|
126
|
+
command: ["projects", "delete"],
|
|
127
|
+
usage: "blitzreels projects delete --project-id ID --confirm-delete",
|
|
128
|
+
flags: ["project-id", "confirm-delete"],
|
|
129
|
+
}),
|
|
130
|
+
commandSpec({
|
|
131
|
+
command: ["media", "list"],
|
|
132
|
+
usage: "blitzreels media list [--folder-id ID] [--asset-type video|audio|image|document] [--search QUERY] [--limit 100] [--offset 0] [--json]",
|
|
133
|
+
flags: ["folder-id", "asset-type", "search", "limit", "offset"],
|
|
134
|
+
}),
|
|
135
|
+
commandSpec({
|
|
136
|
+
command: ["media", "get"],
|
|
137
|
+
usage: "blitzreels media get --asset-id ID [--json]",
|
|
138
|
+
flags: ["asset-id"],
|
|
139
|
+
}),
|
|
140
|
+
commandSpec({
|
|
141
|
+
command: ["media", "delete"],
|
|
142
|
+
usage: "blitzreels media delete --asset-id ID --confirm-delete",
|
|
143
|
+
flags: ["asset-id", "confirm-delete"],
|
|
144
|
+
}),
|
|
145
|
+
commandSpec({
|
|
146
|
+
command: ["media", "upload"],
|
|
147
|
+
usage: "blitzreels media upload --file ./video.mp4 [--name NAME] [--content-type video/mp4] [--auto-process true] [--auto-transcribe true] [--auto-describe true] [--auto-suggest-shorts true]",
|
|
148
|
+
flags: [
|
|
149
|
+
"file",
|
|
150
|
+
"name",
|
|
151
|
+
"content-type",
|
|
152
|
+
"auto-process",
|
|
153
|
+
"auto-transcribe",
|
|
154
|
+
"auto-describe",
|
|
155
|
+
"auto-suggest-shorts",
|
|
156
|
+
],
|
|
157
|
+
}),
|
|
158
|
+
commandSpec({
|
|
159
|
+
command: ["media", "import-youtube"],
|
|
160
|
+
usage: "blitzreels media import-youtube --url URL [--folder-id ID|root] [--quality 1080p] [--fps 30] [--audio-language fr|null]",
|
|
161
|
+
flags: ["url", "folder-id", "quality", "fps", "audio-language"],
|
|
162
|
+
}),
|
|
163
|
+
commandSpec({
|
|
164
|
+
command: ["media", "rename"],
|
|
165
|
+
usage: "blitzreels media rename --asset-id ID --name NAME",
|
|
166
|
+
flags: ["asset-id", "name"],
|
|
167
|
+
}),
|
|
168
|
+
commandSpec({
|
|
169
|
+
command: ["media", "update"],
|
|
170
|
+
usage: "blitzreels media update --asset-id ID [--name NAME] [--description TEXT|null] [--folder-id ID|root] [--allow-broll true]",
|
|
171
|
+
flags: ["asset-id", "name", "description", "folder-id", "allow-broll"],
|
|
172
|
+
}),
|
|
173
|
+
commandSpec({
|
|
174
|
+
command: ["media", "move"],
|
|
175
|
+
usage: "blitzreels media move --asset-id ID|--asset-ids ID1,ID2 --target-folder-id ID|root",
|
|
176
|
+
flags: ["asset-id", "asset-ids", "target-folder-id"],
|
|
177
|
+
}),
|
|
178
|
+
commandSpec({
|
|
179
|
+
command: ["media", "attach"],
|
|
180
|
+
usage: "blitzreels media attach --project-id ID --asset-id ID [--at 0] [--duration 4] [--layer-index 2] [--allow-duplicate true] [--position-preset center] [--position-x 0] [--position-y 0] [--width-px 320] [--height-px 180] [--scale 1.2] [--opacity 0.9] [--animation-preset popIn]",
|
|
181
|
+
flags: [
|
|
182
|
+
"project-id",
|
|
183
|
+
"asset-id",
|
|
184
|
+
"at",
|
|
185
|
+
"duration",
|
|
186
|
+
"layer-index",
|
|
187
|
+
"allow-duplicate",
|
|
188
|
+
"position-preset",
|
|
189
|
+
"position-x",
|
|
190
|
+
"position-y",
|
|
191
|
+
"width-px",
|
|
192
|
+
"height-px",
|
|
193
|
+
"scale",
|
|
194
|
+
"opacity",
|
|
195
|
+
"animation-preset",
|
|
196
|
+
],
|
|
197
|
+
}),
|
|
198
|
+
commandSpec({
|
|
199
|
+
command: ["media", "folders", "list"],
|
|
200
|
+
usage: "blitzreels media folders list [--parent-folder-id ID] [--json]",
|
|
201
|
+
flags: ["parent-folder-id"],
|
|
202
|
+
}),
|
|
203
|
+
commandSpec({
|
|
204
|
+
command: ["media", "folders", "create"],
|
|
205
|
+
usage: "blitzreels media folders create --name NAME [--parent-folder-id ID] [--description TEXT|null] [--icon-type video]",
|
|
206
|
+
flags: ["name", "parent-folder-id", "description", "icon-type"],
|
|
207
|
+
}),
|
|
208
|
+
commandSpec({
|
|
209
|
+
command: ["media", "folders", "rename"],
|
|
210
|
+
usage: "blitzreels media folders rename --folder-id ID --name NAME",
|
|
211
|
+
flags: ["folder-id", "name"],
|
|
212
|
+
}),
|
|
213
|
+
commandSpec({
|
|
214
|
+
command: ["media", "folders", "update"],
|
|
215
|
+
usage: "blitzreels media folders update --folder-id ID [--name NAME] [--parent-folder-id ID|root] [--description TEXT|null] [--icon-type video]",
|
|
216
|
+
flags: [
|
|
217
|
+
"folder-id",
|
|
218
|
+
"name",
|
|
219
|
+
"parent-folder-id",
|
|
220
|
+
"description",
|
|
221
|
+
"icon-type",
|
|
222
|
+
],
|
|
223
|
+
}),
|
|
224
|
+
commandSpec({
|
|
225
|
+
command: ["media", "folders", "delete"],
|
|
226
|
+
usage: "blitzreels media folders delete --folder-id ID --confirm-delete [--cascade true]",
|
|
227
|
+
flags: ["folder-id", "confirm-delete", "cascade"],
|
|
228
|
+
}),
|
|
229
|
+
commandSpec({
|
|
230
|
+
command: ["project", "inspect"],
|
|
231
|
+
usage: "blitzreels project inspect --project-id ID [--mode full] [--json]",
|
|
232
|
+
flags: ["project-id", "mode"],
|
|
233
|
+
}),
|
|
234
|
+
commandSpec({
|
|
235
|
+
command: ["project", "timeline"],
|
|
236
|
+
usage: "blitzreels project timeline --project-id ID [--json]",
|
|
237
|
+
flags: ["project-id"],
|
|
238
|
+
}),
|
|
239
|
+
commandSpec({
|
|
240
|
+
command: ["project", "snapshot"],
|
|
241
|
+
usage: "blitzreels project snapshot --project-id ID --at 00:03 [--target-width 608] [--image-format jpeg|png|webp] [--json]",
|
|
242
|
+
flags: ["project-id", "at", "target-width", "image-format"],
|
|
243
|
+
}),
|
|
244
|
+
commandSpec({
|
|
245
|
+
command: ["project", "snapshots"],
|
|
246
|
+
usage: "blitzreels project snapshots --project-id ID --at 00:01,00:03 [--target-width 608] [--image-format jpeg|png|webp] [--json]",
|
|
247
|
+
flags: ["project-id", "at", "target-width", "image-format"],
|
|
248
|
+
}),
|
|
249
|
+
commandSpec({
|
|
250
|
+
command: ["timeline", "transform"],
|
|
251
|
+
usage: "blitzreels timeline transform --project-id ID --timeline-item-id ID [--position-x 0] [--position-y 0] [--width-px 320|null] [--height-px 180|null] [--keep-aspect-ratio true]",
|
|
252
|
+
flags: [
|
|
253
|
+
"project-id",
|
|
254
|
+
"timeline-item-id",
|
|
255
|
+
"position-x",
|
|
256
|
+
"position-y",
|
|
257
|
+
"width-px",
|
|
258
|
+
"height-px",
|
|
259
|
+
"keep-aspect-ratio",
|
|
260
|
+
],
|
|
261
|
+
}),
|
|
262
|
+
commandSpec({
|
|
263
|
+
command: ["timeline", "move"],
|
|
264
|
+
usage: "blitzreels timeline move --project-id ID --timeline-item-id ID --at 00:03 [--layer-index 2]",
|
|
265
|
+
flags: ["project-id", "timeline-item-id", "at", "layer-index"],
|
|
266
|
+
}),
|
|
267
|
+
commandSpec({
|
|
268
|
+
command: ["timeline", "delete"],
|
|
269
|
+
usage: "blitzreels timeline delete --project-id ID --timeline-item-id ID|--timeline-item-ids ID1,ID2 [--auto-pack true]",
|
|
270
|
+
flags: ["project-id", "timeline-item-id", "timeline-item-ids", "auto-pack"],
|
|
271
|
+
}),
|
|
272
|
+
commandSpec({
|
|
273
|
+
command: ["text", "add"],
|
|
274
|
+
usage: "blitzreels text add --project-id ID --text \"Hook\" [--name NAME] [--at 0] [--duration 4] [--layer-index 2] [--spec-json JSON] [--font-family Inter] [--font-size 64] [--font-weight 700] [--color '#fff'] [--background-color '#000'] [--padding-x 32] [--padding-y 16] [--border-radius 24] [--top '18%'] [--left '50%'] [--text-align center] [--text-shadow '0 6px 18px #000'] [--no-background]",
|
|
275
|
+
flags: [
|
|
276
|
+
"project-id",
|
|
277
|
+
"text",
|
|
278
|
+
"name",
|
|
279
|
+
"at",
|
|
280
|
+
"duration",
|
|
281
|
+
"layer-index",
|
|
282
|
+
...TEXT_STYLE_FLAGS,
|
|
283
|
+
],
|
|
284
|
+
}),
|
|
285
|
+
commandSpec({
|
|
286
|
+
command: ["text", "list"],
|
|
287
|
+
usage: "blitzreels text list --project-id ID [--json]",
|
|
288
|
+
flags: ["project-id"],
|
|
289
|
+
}),
|
|
290
|
+
commandSpec({
|
|
291
|
+
command: ["text", "update"],
|
|
292
|
+
usage: "blitzreels text update --project-id ID --content-item-id ID [--text \"New hook\"] [--name NAME] [--spec-json JSON] [--font-family Pacifico] [--font-size 82] [--font-weight 700] [--color '#17FFA6'] [--background-color '#051914'] [--padding-x 32] [--padding-y 16] [--border-radius 24] [--top '18%'] [--left '50%'] [--text-align center] [--text-shadow '0 6px 18px #000'] [--no-background]",
|
|
293
|
+
flags: [
|
|
294
|
+
"project-id",
|
|
295
|
+
"content-item-id",
|
|
296
|
+
"text",
|
|
297
|
+
"name",
|
|
298
|
+
...TEXT_STYLE_FLAGS,
|
|
299
|
+
],
|
|
300
|
+
}),
|
|
301
|
+
commandSpec({
|
|
302
|
+
command: ["text", "remove"],
|
|
303
|
+
usage: "blitzreels text remove --project-id ID --content-item-id ID",
|
|
304
|
+
flags: ["project-id", "content-item-id"],
|
|
305
|
+
}),
|
|
306
|
+
commandSpec({
|
|
307
|
+
command: ["audio", "add"],
|
|
308
|
+
usage: "blitzreels audio add --project-id ID --asset-id ID [--at 0] [--duration 30] [--volume 0.6] [--fade-in 0.5] [--fade-out 0.5] [--loop true]",
|
|
309
|
+
flags: [
|
|
310
|
+
"project-id",
|
|
311
|
+
"asset-id",
|
|
312
|
+
"at",
|
|
313
|
+
"duration",
|
|
314
|
+
"volume",
|
|
315
|
+
"fade-in",
|
|
316
|
+
"fade-out",
|
|
317
|
+
"loop",
|
|
318
|
+
],
|
|
319
|
+
}),
|
|
320
|
+
commandSpec({
|
|
321
|
+
command: ["silence", "plan"],
|
|
322
|
+
usage: "blitzreels silence plan --project-id ID --timeline-item-id ID [--padding-ms 120] [--silence-threshold-db -35] [--min-silence-duration 0.25] [--remove-blips-max-duration 0.12] [--use-caption-validation true] [--json]",
|
|
323
|
+
flags: [
|
|
324
|
+
"project-id",
|
|
325
|
+
"timeline-item-id",
|
|
326
|
+
"padding-ms",
|
|
327
|
+
"silence-threshold-db",
|
|
328
|
+
"min-silence-duration",
|
|
329
|
+
"remove-blips-max-duration",
|
|
330
|
+
"use-caption-validation",
|
|
331
|
+
],
|
|
332
|
+
}),
|
|
333
|
+
commandSpec({
|
|
334
|
+
command: ["silence", "apply"],
|
|
335
|
+
usage: "blitzreels silence apply --project-id ID --timeline-item-id ID --confirm-preview [--padding-ms 120] [--silence-threshold-db -35] [--min-silence-duration 0.25] [--remove-blips-max-duration 0.12] [--use-caption-validation true] [--delete-silent-clips true] [--manual-segment-overrides-json JSON]",
|
|
336
|
+
flags: [
|
|
337
|
+
"project-id",
|
|
338
|
+
"timeline-item-id",
|
|
339
|
+
"confirm-preview",
|
|
340
|
+
"padding-ms",
|
|
341
|
+
"silence-threshold-db",
|
|
342
|
+
"min-silence-duration",
|
|
343
|
+
"remove-blips-max-duration",
|
|
344
|
+
"use-caption-validation",
|
|
345
|
+
"delete-silent-clips",
|
|
346
|
+
"manual-segment-overrides-json",
|
|
347
|
+
],
|
|
348
|
+
}),
|
|
349
|
+
commandSpec({
|
|
350
|
+
command: ["mistakes", "plan"],
|
|
351
|
+
usage: "blitzreels mistakes plan --project-id ID --timeline-item-id ID [--json]",
|
|
352
|
+
flags: ["project-id", "timeline-item-id"],
|
|
353
|
+
}),
|
|
354
|
+
commandSpec({
|
|
355
|
+
command: ["mistakes", "apply"],
|
|
356
|
+
usage: "blitzreels mistakes apply --project-id ID --timeline-item-id ID --confirm-preview [--plan-json JSON] [--manual-verdicts-json JSON] [--delete-mistakes true]",
|
|
357
|
+
flags: [
|
|
358
|
+
"project-id",
|
|
359
|
+
"timeline-item-id",
|
|
360
|
+
"confirm-preview",
|
|
361
|
+
"plan-json",
|
|
362
|
+
"manual-verdicts-json",
|
|
363
|
+
"delete-mistakes",
|
|
364
|
+
],
|
|
365
|
+
}),
|
|
366
|
+
commandSpec({
|
|
367
|
+
command: ["captions", "words", "list"],
|
|
368
|
+
usage: "blitzreels captions words list --project-id ID [--timeline-item-id ID] [--match-text TEXT] [--limit 100] [--offset 0]",
|
|
369
|
+
flags: ["project-id", "timeline-item-id", "match-text", "limit", "offset"],
|
|
370
|
+
}),
|
|
371
|
+
commandSpec({
|
|
372
|
+
command: ["captions", "words", "text"],
|
|
373
|
+
usage: 'blitzreels captions words text --project-id ID --word-id ID --text "Fix"|--new-text "Fix"',
|
|
374
|
+
flags: ["project-id", "word-id", "text", "new-text"],
|
|
375
|
+
}),
|
|
376
|
+
commandSpec({
|
|
377
|
+
command: ["captions", "words", "batch-text"],
|
|
378
|
+
usage: 'blitzreels captions words batch-text --project-id ID --updates-json \'[{"word_id":"...","new_text":"..."}]\'',
|
|
379
|
+
flags: ["project-id", "updates-json"],
|
|
380
|
+
}),
|
|
381
|
+
commandSpec({
|
|
382
|
+
command: ["captions", "words", "style"],
|
|
383
|
+
usage: "blitzreels captions words style --project-id ID [--word-id ID|--word-ids IDs|--timeline-item-id ID|--match-text TEXT|--match-pattern numbers|caps|exclamations] [--style-json JSON|null] [--font-family Pacifico] [--font-weight 700] [--font-style italic] [--color '#17FFA6'] [--active-color '#fff'] [--background-color '#051914'] [--active-animation pop] [--text-transform uppercase] [--text-shadow '0 6px 18px #000'] [--glow-color '#17FFA6'] [--glow-blur-px 18] [--scale 1.45] [--offset-x 0] [--offset-y -8] [--rotation-deg -2] [--letter-spacing 1] [--opacity 1] [--clear-existing true]",
|
|
384
|
+
flags: [
|
|
385
|
+
"project-id",
|
|
386
|
+
...CAPTION_WORD_SELECTOR_FLAGS,
|
|
387
|
+
...CAPTION_WORD_STYLE_FLAGS,
|
|
388
|
+
],
|
|
389
|
+
}),
|
|
390
|
+
commandSpec({
|
|
391
|
+
command: ["captions", "words", "emphasis"],
|
|
392
|
+
usage: "blitzreels captions words emphasis --project-id ID [--word-id ID|--word-ids IDs|--timeline-item-id ID|--match-text TEXT|--match-pattern numbers|caps|exclamations] [--emphasis true]",
|
|
393
|
+
flags: ["project-id", ...CAPTION_WORD_SELECTOR_FLAGS, "emphasis"],
|
|
394
|
+
}),
|
|
395
|
+
commandSpec({
|
|
396
|
+
command: ["captions", "words", "delete"],
|
|
397
|
+
usage: "blitzreels captions words delete --project-id ID --word-id ID|--word-ids ID1,ID2",
|
|
398
|
+
flags: ["project-id", "word-id", "word-ids"],
|
|
399
|
+
}),
|
|
400
|
+
commandSpec({
|
|
401
|
+
command: ["captions", "words", "merge"],
|
|
402
|
+
usage: 'blitzreels captions words merge --project-id ID --word-ids ID1,ID2 [--text "Merged"]',
|
|
403
|
+
flags: ["project-id", "word-ids", "text"],
|
|
404
|
+
}),
|
|
405
|
+
commandSpec({
|
|
406
|
+
command: ["captions", "words", "split"],
|
|
407
|
+
usage: 'blitzreels captions words split --project-id ID --word-id ID --words "foo,bar"',
|
|
408
|
+
flags: ["project-id", "word-id", "words"],
|
|
409
|
+
}),
|
|
410
|
+
commandSpec({
|
|
411
|
+
command: ["captions", "themes", "list"],
|
|
412
|
+
usage: "blitzreels captions themes list [--json]",
|
|
413
|
+
}),
|
|
414
|
+
commandSpec({
|
|
415
|
+
command: ["captions", "theme", "set"],
|
|
416
|
+
usage: "blitzreels captions theme set --project-id ID --theme-id ID",
|
|
417
|
+
flags: ["project-id", "theme-id"],
|
|
418
|
+
}),
|
|
419
|
+
commandSpec({
|
|
420
|
+
command: ["captions", "theme", "set-default"],
|
|
421
|
+
usage: "blitzreels captions theme set-default --theme-id ID",
|
|
422
|
+
flags: ["theme-id"],
|
|
423
|
+
}),
|
|
424
|
+
commandSpec({
|
|
425
|
+
command: ["exports", "start"],
|
|
426
|
+
usage: "blitzreels exports start --project-id ID [--resolution 1080p] [--format mp4] [--include-captions true]",
|
|
427
|
+
flags: ["project-id", "resolution", "format", "include-captions"],
|
|
428
|
+
}),
|
|
429
|
+
commandSpec({
|
|
430
|
+
command: ["exports", "wait"],
|
|
431
|
+
usage: "blitzreels exports wait --export-id ID [--interval-ms 3000] [--timeout-ms 1200000] [--json]",
|
|
432
|
+
flags: ["export-id", "interval-ms", "timeout-ms"],
|
|
433
|
+
}),
|
|
434
|
+
commandSpec({
|
|
435
|
+
command: ["exports", "download"],
|
|
436
|
+
usage: "blitzreels exports download --export-id ID --output ./short.mp4",
|
|
437
|
+
flags: ["export-id", "output"],
|
|
438
|
+
}),
|
|
439
|
+
commandSpec({
|
|
440
|
+
command: ["api", "docs"],
|
|
441
|
+
usage: "blitzreels api docs",
|
|
442
|
+
}),
|
|
443
|
+
commandSpec({
|
|
444
|
+
command: ["api", "spec"],
|
|
445
|
+
usage: "blitzreels api spec",
|
|
446
|
+
}),
|
|
447
|
+
];
|
|
448
|
+
class CliUsageError extends Error {
|
|
449
|
+
code;
|
|
450
|
+
suggestions;
|
|
451
|
+
usage;
|
|
452
|
+
constructor({ code, message, suggestions = [], usage, }) {
|
|
453
|
+
super(message);
|
|
454
|
+
this.name = "CliUsageError";
|
|
455
|
+
this.code = code;
|
|
456
|
+
this.suggestions = suggestions;
|
|
457
|
+
this.usage = usage;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
12
460
|
async function main() {
|
|
13
461
|
const parsed = parseArgs({ argv: process.argv.slice(2) });
|
|
14
|
-
if (parsed.command.length === 0
|
|
15
|
-
getBooleanFlag({ flags: parsed.flags, name: "help" })) {
|
|
462
|
+
if (parsed.command.length === 0) {
|
|
16
463
|
printHelp();
|
|
17
464
|
return;
|
|
18
465
|
}
|
|
466
|
+
if (getBooleanFlag({ flags: parsed.flags, name: "help" })) {
|
|
467
|
+
printCommandHelpOrThrow({ command: parsed.command });
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
validateParsedArgs({ parsed });
|
|
19
471
|
const config = await loadConfig();
|
|
20
472
|
const apiKey = getStringFlag({ flags: parsed.flags, name: "api-key" }) ??
|
|
21
473
|
process.env.BLITZREELS_API_KEY ??
|
|
@@ -408,7 +860,55 @@ async function runCommand({ context }) {
|
|
|
408
860
|
flags: context.args.flags,
|
|
409
861
|
name: "allow-duplicate",
|
|
410
862
|
}),
|
|
863
|
+
positionPreset: parseMediaPositionPreset({
|
|
864
|
+
value: getStringFlag({
|
|
865
|
+
flags: context.args.flags,
|
|
866
|
+
name: "position-preset",
|
|
867
|
+
}),
|
|
868
|
+
}),
|
|
869
|
+
positionX: getNumberFlag({
|
|
870
|
+
flags: context.args.flags,
|
|
871
|
+
name: "position-x",
|
|
872
|
+
}),
|
|
873
|
+
positionY: getNumberFlag({
|
|
874
|
+
flags: context.args.flags,
|
|
875
|
+
name: "position-y",
|
|
876
|
+
}),
|
|
877
|
+
widthPx: getNumberFlag({
|
|
878
|
+
flags: context.args.flags,
|
|
879
|
+
name: "width-px",
|
|
880
|
+
}),
|
|
881
|
+
heightPx: getNumberFlag({
|
|
882
|
+
flags: context.args.flags,
|
|
883
|
+
name: "height-px",
|
|
884
|
+
}),
|
|
885
|
+
scale: getNumberFlag({ flags: context.args.flags, name: "scale" }),
|
|
886
|
+
opacity: getNumberFlag({ flags: context.args.flags, name: "opacity" }),
|
|
887
|
+
animationPreset: parseMediaAnimationPreset({
|
|
888
|
+
value: getStringFlag({
|
|
889
|
+
flags: context.args.flags,
|
|
890
|
+
name: "animation-preset",
|
|
891
|
+
}),
|
|
892
|
+
}),
|
|
411
893
|
});
|
|
894
|
+
const requestedLayer = getNumberFlag({
|
|
895
|
+
flags: context.args.flags,
|
|
896
|
+
name: "layer-index",
|
|
897
|
+
});
|
|
898
|
+
if (requestedLayer !== undefined) {
|
|
899
|
+
await Promise.all(result.inserted
|
|
900
|
+
.map((item) => item.timeline_item_id)
|
|
901
|
+
.filter((item) => typeof item === "string")
|
|
902
|
+
.map((timelineItemId) => context.client.timeline.move({
|
|
903
|
+
projectId: requireStringFlag({
|
|
904
|
+
flags: context.args.flags,
|
|
905
|
+
name: "project-id",
|
|
906
|
+
}),
|
|
907
|
+
timelineItemId,
|
|
908
|
+
newStartSeconds: result.inserted.find((item) => item.timeline_item_id === timelineItemId)?.start_seconds ?? 0,
|
|
909
|
+
newLayerIndex: requestedLayer,
|
|
910
|
+
})));
|
|
911
|
+
}
|
|
412
912
|
printResult({
|
|
413
913
|
json: context.json,
|
|
414
914
|
value: result,
|
|
@@ -600,21 +1100,33 @@ async function runCommand({ context }) {
|
|
|
600
1100
|
return;
|
|
601
1101
|
}
|
|
602
1102
|
if (group === "text" && action === "add") {
|
|
1103
|
+
const text = requireStringFlag({ flags: context.args.flags, name: "text" });
|
|
1104
|
+
const durationSeconds = getNumberFlag({ flags: context.args.flags, name: "duration" }) ?? 4;
|
|
1105
|
+
const spec = parseJsonObjectFlag({ flags: context.args.flags, name: "spec-json" }) ??
|
|
1106
|
+
(hasTextStyleFlags({ flags: context.args.flags })
|
|
1107
|
+
? buildTextOverlaySpec({
|
|
1108
|
+
text,
|
|
1109
|
+
name: getStringFlag({ flags: context.args.flags, name: "name" }),
|
|
1110
|
+
durationSeconds,
|
|
1111
|
+
flags: context.args.flags,
|
|
1112
|
+
})
|
|
1113
|
+
: undefined);
|
|
603
1114
|
const result = await context.client.text.add({
|
|
604
1115
|
projectId: requireStringFlag({
|
|
605
1116
|
flags: context.args.flags,
|
|
606
1117
|
name: "project-id",
|
|
607
1118
|
}),
|
|
608
|
-
text
|
|
1119
|
+
text,
|
|
609
1120
|
name: getStringFlag({ flags: context.args.flags, name: "name" }),
|
|
610
1121
|
startSeconds: parseTimecode({
|
|
611
1122
|
value: getStringFlag({ flags: context.args.flags, name: "at" }) ?? "0",
|
|
612
1123
|
}),
|
|
613
|
-
durationSeconds
|
|
1124
|
+
durationSeconds,
|
|
614
1125
|
layerIndex: getNumberFlag({
|
|
615
1126
|
flags: context.args.flags,
|
|
616
1127
|
name: "layer-index",
|
|
617
1128
|
}),
|
|
1129
|
+
spec,
|
|
618
1130
|
});
|
|
619
1131
|
printResult({
|
|
620
1132
|
json: context.json,
|
|
@@ -656,6 +1168,29 @@ async function runCommand({ context }) {
|
|
|
656
1168
|
return;
|
|
657
1169
|
}
|
|
658
1170
|
if (group === "text" && action === "update") {
|
|
1171
|
+
const explicitSpec = parseJsonObjectFlag({
|
|
1172
|
+
flags: context.args.flags,
|
|
1173
|
+
name: "spec-json",
|
|
1174
|
+
});
|
|
1175
|
+
const spec = explicitSpec ??
|
|
1176
|
+
(hasTextStyleFlags({ flags: context.args.flags })
|
|
1177
|
+
? await buildUpdatedTextSpec({
|
|
1178
|
+
context,
|
|
1179
|
+
projectId: requireStringFlag({
|
|
1180
|
+
flags: context.args.flags,
|
|
1181
|
+
name: "project-id",
|
|
1182
|
+
}),
|
|
1183
|
+
contentItemId: requireStringFlag({
|
|
1184
|
+
flags: context.args.flags,
|
|
1185
|
+
name: "content-item-id",
|
|
1186
|
+
}),
|
|
1187
|
+
nextText: getStringFlag({
|
|
1188
|
+
flags: context.args.flags,
|
|
1189
|
+
name: "text",
|
|
1190
|
+
}),
|
|
1191
|
+
flags: context.args.flags,
|
|
1192
|
+
})
|
|
1193
|
+
: undefined);
|
|
659
1194
|
const result = await context.client.text.update({
|
|
660
1195
|
projectId: requireStringFlag({
|
|
661
1196
|
flags: context.args.flags,
|
|
@@ -667,15 +1202,94 @@ async function runCommand({ context }) {
|
|
|
667
1202
|
}),
|
|
668
1203
|
text: getStringFlag({ flags: context.args.flags, name: "text" }),
|
|
669
1204
|
name: getStringFlag({ flags: context.args.flags, name: "name" }),
|
|
670
|
-
spec
|
|
1205
|
+
spec,
|
|
1206
|
+
});
|
|
1207
|
+
printResult({
|
|
1208
|
+
json: context.json,
|
|
1209
|
+
value: result,
|
|
1210
|
+
human: ["Text updated."],
|
|
1211
|
+
});
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
if (group === "timeline" && action === "transform") {
|
|
1215
|
+
const result = await context.client.timeline.transform({
|
|
1216
|
+
projectId: requireStringFlag({
|
|
1217
|
+
flags: context.args.flags,
|
|
1218
|
+
name: "project-id",
|
|
1219
|
+
}),
|
|
1220
|
+
timelineItemId: requireStringFlag({
|
|
1221
|
+
flags: context.args.flags,
|
|
1222
|
+
name: "timeline-item-id",
|
|
1223
|
+
}),
|
|
1224
|
+
positionX: getNumberFlag({
|
|
1225
|
+
flags: context.args.flags,
|
|
1226
|
+
name: "position-x",
|
|
1227
|
+
}),
|
|
1228
|
+
positionY: getNumberFlag({
|
|
1229
|
+
flags: context.args.flags,
|
|
1230
|
+
name: "position-y",
|
|
1231
|
+
}),
|
|
1232
|
+
widthPx: parseNullableNumberFlag({
|
|
1233
|
+
flags: context.args.flags,
|
|
1234
|
+
name: "width-px",
|
|
1235
|
+
}),
|
|
1236
|
+
heightPx: parseNullableNumberFlag({
|
|
1237
|
+
flags: context.args.flags,
|
|
1238
|
+
name: "height-px",
|
|
1239
|
+
}),
|
|
1240
|
+
keepAspectRatio: getOptionalBooleanFlag({
|
|
671
1241
|
flags: context.args.flags,
|
|
672
|
-
name: "
|
|
1242
|
+
name: "keep-aspect-ratio",
|
|
673
1243
|
}),
|
|
674
1244
|
});
|
|
675
1245
|
printResult({
|
|
676
1246
|
json: context.json,
|
|
677
1247
|
value: result,
|
|
678
|
-
human: [
|
|
1248
|
+
human: [JSON.stringify(result, null, 2)],
|
|
1249
|
+
});
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1252
|
+
if (group === "timeline" && action === "move") {
|
|
1253
|
+
const result = await context.client.timeline.move({
|
|
1254
|
+
projectId: requireStringFlag({
|
|
1255
|
+
flags: context.args.flags,
|
|
1256
|
+
name: "project-id",
|
|
1257
|
+
}),
|
|
1258
|
+
timelineItemId: requireStringFlag({
|
|
1259
|
+
flags: context.args.flags,
|
|
1260
|
+
name: "timeline-item-id",
|
|
1261
|
+
}),
|
|
1262
|
+
newStartSeconds: parseTimecode({
|
|
1263
|
+
value: requireStringFlag({ flags: context.args.flags, name: "at" }),
|
|
1264
|
+
}),
|
|
1265
|
+
newLayerIndex: getNumberFlag({
|
|
1266
|
+
flags: context.args.flags,
|
|
1267
|
+
name: "layer-index",
|
|
1268
|
+
}),
|
|
1269
|
+
});
|
|
1270
|
+
printResult({
|
|
1271
|
+
json: context.json,
|
|
1272
|
+
value: result,
|
|
1273
|
+
human: [JSON.stringify(result, null, 2)],
|
|
1274
|
+
});
|
|
1275
|
+
return;
|
|
1276
|
+
}
|
|
1277
|
+
if (group === "timeline" && action === "delete") {
|
|
1278
|
+
const result = await context.client.timeline.delete({
|
|
1279
|
+
projectId: requireStringFlag({
|
|
1280
|
+
flags: context.args.flags,
|
|
1281
|
+
name: "project-id",
|
|
1282
|
+
}),
|
|
1283
|
+
timelineItemIds: parseTimelineItemIds({ flags: context.args.flags }),
|
|
1284
|
+
autoPack: getOptionalBooleanFlag({
|
|
1285
|
+
flags: context.args.flags,
|
|
1286
|
+
name: "auto-pack",
|
|
1287
|
+
}),
|
|
1288
|
+
});
|
|
1289
|
+
printResult({
|
|
1290
|
+
json: context.json,
|
|
1291
|
+
value: result,
|
|
1292
|
+
human: [JSON.stringify(result, null, 2)],
|
|
679
1293
|
});
|
|
680
1294
|
return;
|
|
681
1295
|
}
|
|
@@ -850,6 +1464,154 @@ async function runCommand({ context }) {
|
|
|
850
1464
|
});
|
|
851
1465
|
return;
|
|
852
1466
|
}
|
|
1467
|
+
if (group === "captions" && action === "words" && subaction === "list") {
|
|
1468
|
+
const result = await context.client.captions.listWords({
|
|
1469
|
+
projectId: requireStringFlag({
|
|
1470
|
+
flags: context.args.flags,
|
|
1471
|
+
name: "project-id",
|
|
1472
|
+
}),
|
|
1473
|
+
timelineItemId: getStringFlag({
|
|
1474
|
+
flags: context.args.flags,
|
|
1475
|
+
name: "timeline-item-id",
|
|
1476
|
+
}),
|
|
1477
|
+
matchText: getStringFlag({
|
|
1478
|
+
flags: context.args.flags,
|
|
1479
|
+
name: "match-text",
|
|
1480
|
+
}),
|
|
1481
|
+
limit: getNumberFlag({ flags: context.args.flags, name: "limit" }),
|
|
1482
|
+
offset: getNumberFlag({ flags: context.args.flags, name: "offset" }),
|
|
1483
|
+
});
|
|
1484
|
+
printResult({
|
|
1485
|
+
json: context.json,
|
|
1486
|
+
value: result,
|
|
1487
|
+
human: result.words.map((word) => JSON.stringify(word)),
|
|
1488
|
+
});
|
|
1489
|
+
return;
|
|
1490
|
+
}
|
|
1491
|
+
if (group === "captions" && action === "words" && subaction === "text") {
|
|
1492
|
+
const result = await context.client.captions.updateWordText({
|
|
1493
|
+
projectId: requireStringFlag({
|
|
1494
|
+
flags: context.args.flags,
|
|
1495
|
+
name: "project-id",
|
|
1496
|
+
}),
|
|
1497
|
+
wordId: requireStringFlag({ flags: context.args.flags, name: "word-id" }),
|
|
1498
|
+
newText: getStringFlag({ flags: context.args.flags, name: "new-text" }) ??
|
|
1499
|
+
requireStringFlag({ flags: context.args.flags, name: "text" }),
|
|
1500
|
+
});
|
|
1501
|
+
printResult({
|
|
1502
|
+
json: context.json,
|
|
1503
|
+
value: result,
|
|
1504
|
+
human: [
|
|
1505
|
+
`Updated ${result.word_id}: ${result.old_text} -> ${result.new_text}`,
|
|
1506
|
+
],
|
|
1507
|
+
});
|
|
1508
|
+
return;
|
|
1509
|
+
}
|
|
1510
|
+
if (group === "captions" &&
|
|
1511
|
+
action === "words" &&
|
|
1512
|
+
subaction === "batch-text") {
|
|
1513
|
+
const result = await context.client.captions.batchUpdateWordText({
|
|
1514
|
+
projectId: requireStringFlag({
|
|
1515
|
+
flags: context.args.flags,
|
|
1516
|
+
name: "project-id",
|
|
1517
|
+
}),
|
|
1518
|
+
updates: parseWordTextUpdatesFlag({
|
|
1519
|
+
flags: context.args.flags,
|
|
1520
|
+
name: "updates-json",
|
|
1521
|
+
}),
|
|
1522
|
+
});
|
|
1523
|
+
printResult({
|
|
1524
|
+
json: context.json,
|
|
1525
|
+
value: result,
|
|
1526
|
+
human: [result.message],
|
|
1527
|
+
});
|
|
1528
|
+
return;
|
|
1529
|
+
}
|
|
1530
|
+
if (group === "captions" && action === "words" && subaction === "style") {
|
|
1531
|
+
const styleJson = parseNullableJsonObjectFlag({
|
|
1532
|
+
flags: context.args.flags,
|
|
1533
|
+
name: "style-json",
|
|
1534
|
+
});
|
|
1535
|
+
const style = styleJson === undefined
|
|
1536
|
+
? buildCaptionWordStyleFromFlags({ flags: context.args.flags })
|
|
1537
|
+
: styleJson;
|
|
1538
|
+
const result = await context.client.captions.setWordStyle({
|
|
1539
|
+
...buildCaptionWordSelector({ flags: context.args.flags }),
|
|
1540
|
+
style,
|
|
1541
|
+
clearExisting: getOptionalBooleanFlag({
|
|
1542
|
+
flags: context.args.flags,
|
|
1543
|
+
name: "clear-existing",
|
|
1544
|
+
}),
|
|
1545
|
+
});
|
|
1546
|
+
printResult({
|
|
1547
|
+
json: context.json,
|
|
1548
|
+
value: result,
|
|
1549
|
+
human: [`Updated ${result.updated_count} caption word(s).`],
|
|
1550
|
+
});
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1553
|
+
if (group === "captions" && action === "words" && subaction === "emphasis") {
|
|
1554
|
+
const result = await context.client.captions.setWordEmphasis({
|
|
1555
|
+
...buildCaptionWordSelector({ flags: context.args.flags }),
|
|
1556
|
+
emphasis: getOptionalBooleanFlag({
|
|
1557
|
+
flags: context.args.flags,
|
|
1558
|
+
name: "emphasis",
|
|
1559
|
+
}) ?? true,
|
|
1560
|
+
});
|
|
1561
|
+
printResult({
|
|
1562
|
+
json: context.json,
|
|
1563
|
+
value: result,
|
|
1564
|
+
human: [`Updated ${result.updated_count} caption word(s).`],
|
|
1565
|
+
});
|
|
1566
|
+
return;
|
|
1567
|
+
}
|
|
1568
|
+
if (group === "captions" && action === "words" && subaction === "delete") {
|
|
1569
|
+
const result = await context.client.captions.deleteWords({
|
|
1570
|
+
projectId: requireStringFlag({
|
|
1571
|
+
flags: context.args.flags,
|
|
1572
|
+
name: "project-id",
|
|
1573
|
+
}),
|
|
1574
|
+
wordIds: parseWordIds({ flags: context.args.flags }),
|
|
1575
|
+
});
|
|
1576
|
+
printResult({
|
|
1577
|
+
json: context.json,
|
|
1578
|
+
value: result,
|
|
1579
|
+
human: [result.message],
|
|
1580
|
+
});
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1583
|
+
if (group === "captions" && action === "words" && subaction === "merge") {
|
|
1584
|
+
const result = await context.client.captions.mergeWords({
|
|
1585
|
+
projectId: requireStringFlag({
|
|
1586
|
+
flags: context.args.flags,
|
|
1587
|
+
name: "project-id",
|
|
1588
|
+
}),
|
|
1589
|
+
wordIds: parseWordIds({ flags: context.args.flags }),
|
|
1590
|
+
text: getStringFlag({ flags: context.args.flags, name: "text" }),
|
|
1591
|
+
});
|
|
1592
|
+
printResult({
|
|
1593
|
+
json: context.json,
|
|
1594
|
+
value: result,
|
|
1595
|
+
human: [result.message],
|
|
1596
|
+
});
|
|
1597
|
+
return;
|
|
1598
|
+
}
|
|
1599
|
+
if (group === "captions" && action === "words" && subaction === "split") {
|
|
1600
|
+
const result = await context.client.captions.splitWord({
|
|
1601
|
+
projectId: requireStringFlag({
|
|
1602
|
+
flags: context.args.flags,
|
|
1603
|
+
name: "project-id",
|
|
1604
|
+
}),
|
|
1605
|
+
wordId: requireStringFlag({ flags: context.args.flags, name: "word-id" }),
|
|
1606
|
+
words: parseCsvRequiredFlag({ flags: context.args.flags, name: "words" }),
|
|
1607
|
+
});
|
|
1608
|
+
printResult({
|
|
1609
|
+
json: context.json,
|
|
1610
|
+
value: result,
|
|
1611
|
+
human: [result.message],
|
|
1612
|
+
});
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
853
1615
|
if (group === "captions" && action === "themes" && subaction === "list") {
|
|
854
1616
|
const result = await context.client.captions.listThemes();
|
|
855
1617
|
printResult({
|
|
@@ -955,7 +1717,7 @@ async function runCommand({ context }) {
|
|
|
955
1717
|
});
|
|
956
1718
|
return;
|
|
957
1719
|
}
|
|
958
|
-
throw
|
|
1720
|
+
throw buildUnknownCommandError({ command: context.args.command });
|
|
959
1721
|
}
|
|
960
1722
|
async function setApiKey({ context }) {
|
|
961
1723
|
const apiKey = getStringFlag({ flags: context.args.flags, name: "api-key" }) ??
|
|
@@ -1228,6 +1990,118 @@ function parseArgs({ argv }) {
|
|
|
1228
1990
|
}
|
|
1229
1991
|
return { command, flags };
|
|
1230
1992
|
}
|
|
1993
|
+
function validateParsedArgs({ parsed }) {
|
|
1994
|
+
const spec = findCommandSpec({ command: parsed.command });
|
|
1995
|
+
if (!spec) {
|
|
1996
|
+
throw buildUnknownCommandError({ command: parsed.command });
|
|
1997
|
+
}
|
|
1998
|
+
const allowedFlags = new Set([...GLOBAL_FLAGS, ...spec.flags]);
|
|
1999
|
+
for (const flag of Object.keys(parsed.flags)) {
|
|
2000
|
+
if (!allowedFlags.has(flag)) {
|
|
2001
|
+
throw buildUnknownFlagError({ spec, flag });
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
function findCommandSpec({ command, }) {
|
|
2006
|
+
return COMMAND_SPECS.find((spec) => commandsEqual(spec.command, command));
|
|
2007
|
+
}
|
|
2008
|
+
function commandsEqual(left, right) {
|
|
2009
|
+
return (left.length === right.length &&
|
|
2010
|
+
left.every((part, index) => part === right[index]));
|
|
2011
|
+
}
|
|
2012
|
+
function commandLabel({ command }) {
|
|
2013
|
+
return command.join(" ");
|
|
2014
|
+
}
|
|
2015
|
+
function printCommandHelpOrThrow({ command }) {
|
|
2016
|
+
const spec = findCommandSpec({ command });
|
|
2017
|
+
if (!spec) {
|
|
2018
|
+
throw buildUnknownCommandError({ command });
|
|
2019
|
+
}
|
|
2020
|
+
printCommandHelp({ spec });
|
|
2021
|
+
}
|
|
2022
|
+
function printCommandHelp({ spec }) {
|
|
2023
|
+
const flags = [...new Set([...spec.flags, ...GLOBAL_FLAGS])].sort();
|
|
2024
|
+
console.log(`Usage:
|
|
2025
|
+
${spec.usage}
|
|
2026
|
+
|
|
2027
|
+
Flags:
|
|
2028
|
+
${flags.map((flag) => ` --${flag}`).join("\n")}
|
|
2029
|
+
`);
|
|
2030
|
+
}
|
|
2031
|
+
function buildUnknownCommandError({ command, }) {
|
|
2032
|
+
const suggestions = suggestCommands({ command }).map((spec) => spec.usage);
|
|
2033
|
+
return new CliUsageError({
|
|
2034
|
+
code: "unknown_command",
|
|
2035
|
+
message: `Unknown command: ${commandLabel({ command })}`,
|
|
2036
|
+
suggestions,
|
|
2037
|
+
usage: suggestions[0],
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
2040
|
+
function buildUnknownFlagError({ spec, flag, }) {
|
|
2041
|
+
const flags = [...new Set([...spec.flags, ...GLOBAL_FLAGS])];
|
|
2042
|
+
const suggestions = suggestValues({ value: flag, candidates: flags }).map((candidate) => `--${candidate}`);
|
|
2043
|
+
return new CliUsageError({
|
|
2044
|
+
code: "unknown_flag",
|
|
2045
|
+
message: `Unknown flag --${flag} for \`${commandLabel({ command: spec.command })}\`.`,
|
|
2046
|
+
suggestions,
|
|
2047
|
+
usage: spec.usage,
|
|
2048
|
+
});
|
|
2049
|
+
}
|
|
2050
|
+
function suggestCommands({ command }) {
|
|
2051
|
+
const joined = commandLabel({ command });
|
|
2052
|
+
const prefixMatches = COMMAND_SPECS.filter((spec) => commandsEqual(spec.command.slice(0, command.length), command));
|
|
2053
|
+
if (prefixMatches.length > 0) {
|
|
2054
|
+
return prefixMatches.slice(0, 3);
|
|
2055
|
+
}
|
|
2056
|
+
return COMMAND_SPECS.map((spec) => ({
|
|
2057
|
+
spec,
|
|
2058
|
+
score: commandSimilarity({
|
|
2059
|
+
left: joined,
|
|
2060
|
+
right: commandLabel({ command: spec.command }),
|
|
2061
|
+
}),
|
|
2062
|
+
}))
|
|
2063
|
+
.filter((item) => item.score >= 0.45)
|
|
2064
|
+
.sort((left, right) => right.score - left.score)
|
|
2065
|
+
.slice(0, 3)
|
|
2066
|
+
.map((item) => item.spec);
|
|
2067
|
+
}
|
|
2068
|
+
function suggestValues({ value, candidates, }) {
|
|
2069
|
+
return candidates
|
|
2070
|
+
.map((candidate) => ({
|
|
2071
|
+
candidate,
|
|
2072
|
+
score: commandSimilarity({ left: value, right: candidate }),
|
|
2073
|
+
}))
|
|
2074
|
+
.filter((item) => item.score >= 0.45)
|
|
2075
|
+
.sort((left, right) => right.score - left.score)
|
|
2076
|
+
.slice(0, 3)
|
|
2077
|
+
.map((item) => item.candidate);
|
|
2078
|
+
}
|
|
2079
|
+
function commandSimilarity({ left, right, }) {
|
|
2080
|
+
const maxLength = Math.max(left.length, right.length);
|
|
2081
|
+
if (maxLength === 0) {
|
|
2082
|
+
return 1;
|
|
2083
|
+
}
|
|
2084
|
+
return 1 - levenshteinDistance({ left, right }) / maxLength;
|
|
2085
|
+
}
|
|
2086
|
+
function levenshteinDistance({ left, right, }) {
|
|
2087
|
+
const previous = Array.from({ length: right.length + 1 }, (_, index) => index);
|
|
2088
|
+
const current = Array.from({ length: right.length + 1 }, () => 0);
|
|
2089
|
+
for (let leftIndex = 1; leftIndex <= left.length; leftIndex++) {
|
|
2090
|
+
current[0] = leftIndex;
|
|
2091
|
+
for (let rightIndex = 1; rightIndex <= right.length; rightIndex++) {
|
|
2092
|
+
const substitutionCost = left[leftIndex - 1] === right[rightIndex - 1] ? 0 : 1;
|
|
2093
|
+
current[rightIndex] = Math.min((current[rightIndex - 1] ?? 0) + 1, (previous[rightIndex] ?? 0) + 1, (previous[rightIndex - 1] ?? 0) + substitutionCost);
|
|
2094
|
+
}
|
|
2095
|
+
for (let index = 0; index < previous.length; index++) {
|
|
2096
|
+
previous[index] = current[index] ?? 0;
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
return previous[right.length] ?? 0;
|
|
2100
|
+
}
|
|
2101
|
+
function usageForCurrentCommand() {
|
|
2102
|
+
const parsed = parseArgs({ argv: process.argv.slice(2) });
|
|
2103
|
+
return findCommandSpec({ command: parsed.command })?.usage;
|
|
2104
|
+
}
|
|
1231
2105
|
function getStringFlag({ flags, name, }) {
|
|
1232
2106
|
const value = flags[name];
|
|
1233
2107
|
return typeof value === "string" ? value : undefined;
|
|
@@ -1259,6 +2133,20 @@ function getNumberFlag({ flags, name, }) {
|
|
|
1259
2133
|
}
|
|
1260
2134
|
return parsed;
|
|
1261
2135
|
}
|
|
2136
|
+
function parseNullableNumberFlag({ flags, name, }) {
|
|
2137
|
+
const value = getStringFlag({ flags, name });
|
|
2138
|
+
if (value === undefined) {
|
|
2139
|
+
return undefined;
|
|
2140
|
+
}
|
|
2141
|
+
if (value === "null") {
|
|
2142
|
+
return null;
|
|
2143
|
+
}
|
|
2144
|
+
const parsed = Number(value);
|
|
2145
|
+
if (!Number.isFinite(parsed)) {
|
|
2146
|
+
throw new Error(`--${name} must be a number or null.`);
|
|
2147
|
+
}
|
|
2148
|
+
return parsed;
|
|
2149
|
+
}
|
|
1262
2150
|
function parseJsonObjectFlag({ flags, name, }) {
|
|
1263
2151
|
const value = getStringFlag({ flags, name });
|
|
1264
2152
|
if (value === undefined) {
|
|
@@ -1270,6 +2158,31 @@ function parseJsonObjectFlag({ flags, name, }) {
|
|
|
1270
2158
|
}
|
|
1271
2159
|
return parsed;
|
|
1272
2160
|
}
|
|
2161
|
+
function parseNullableJsonObjectFlag({ flags, name, }) {
|
|
2162
|
+
const value = getStringFlag({ flags, name });
|
|
2163
|
+
if (value === undefined) {
|
|
2164
|
+
return undefined;
|
|
2165
|
+
}
|
|
2166
|
+
if (value === "null") {
|
|
2167
|
+
return null;
|
|
2168
|
+
}
|
|
2169
|
+
const parsed = JSON.parse(value);
|
|
2170
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
2171
|
+
throw new Error(`--${name} must be a JSON object or null.`);
|
|
2172
|
+
}
|
|
2173
|
+
return parsed;
|
|
2174
|
+
}
|
|
2175
|
+
function parseJsonArrayFlag({ flags, name, }) {
|
|
2176
|
+
const value = getStringFlag({ flags, name });
|
|
2177
|
+
if (value === undefined) {
|
|
2178
|
+
return undefined;
|
|
2179
|
+
}
|
|
2180
|
+
const parsed = JSON.parse(value);
|
|
2181
|
+
if (!Array.isArray(parsed)) {
|
|
2182
|
+
throw new Error(`--${name} must be a JSON array.`);
|
|
2183
|
+
}
|
|
2184
|
+
return parsed;
|
|
2185
|
+
}
|
|
1273
2186
|
function parseCsvFlag({ flags, name, }) {
|
|
1274
2187
|
const value = getStringFlag({ flags, name });
|
|
1275
2188
|
if (value === undefined) {
|
|
@@ -1280,6 +2193,13 @@ function parseCsvFlag({ flags, name, }) {
|
|
|
1280
2193
|
.map((item) => item.trim())
|
|
1281
2194
|
.filter((item) => item.length > 0);
|
|
1282
2195
|
}
|
|
2196
|
+
function parseCsvRequiredFlag({ flags, name, }) {
|
|
2197
|
+
const parsed = parseCsvFlag({ flags, name });
|
|
2198
|
+
if (parsed === undefined || parsed.length === 0) {
|
|
2199
|
+
throw new Error(`Missing required --${name}.`);
|
|
2200
|
+
}
|
|
2201
|
+
return parsed;
|
|
2202
|
+
}
|
|
1283
2203
|
function parseNullableStringFlag({ flags, name, }) {
|
|
1284
2204
|
const value = getStringFlag({ flags, name });
|
|
1285
2205
|
if (value === undefined) {
|
|
@@ -1480,6 +2400,45 @@ function parseYoutubeQuality({ value, }) {
|
|
|
1480
2400
|
}
|
|
1481
2401
|
throw new Error("--quality must be 720p, 1080p, 1440p, or 2160p.");
|
|
1482
2402
|
}
|
|
2403
|
+
function parseMediaPositionPreset({ value, }) {
|
|
2404
|
+
if (value === undefined) {
|
|
2405
|
+
return undefined;
|
|
2406
|
+
}
|
|
2407
|
+
if (value === "center" ||
|
|
2408
|
+
value === "top-left" ||
|
|
2409
|
+
value === "top-right" ||
|
|
2410
|
+
value === "bottom-left" ||
|
|
2411
|
+
value === "bottom-right" ||
|
|
2412
|
+
value === "full-screen") {
|
|
2413
|
+
return value;
|
|
2414
|
+
}
|
|
2415
|
+
throw new Error("--position-preset must be center, top-left, top-right, bottom-left, bottom-right, or full-screen.");
|
|
2416
|
+
}
|
|
2417
|
+
function parseMediaAnimationPreset({ value, }) {
|
|
2418
|
+
if (value === undefined) {
|
|
2419
|
+
return undefined;
|
|
2420
|
+
}
|
|
2421
|
+
if (value === "none" ||
|
|
2422
|
+
value === "fadeIn" ||
|
|
2423
|
+
value === "fadeOut" ||
|
|
2424
|
+
value === "zoomIn" ||
|
|
2425
|
+
value === "slideIn" ||
|
|
2426
|
+
value === "popIn" ||
|
|
2427
|
+
value === "bounce" ||
|
|
2428
|
+
value === "spin") {
|
|
2429
|
+
return value;
|
|
2430
|
+
}
|
|
2431
|
+
throw new Error("--animation-preset must be none, fadeIn, fadeOut, zoomIn, slideIn, popIn, bounce, or spin.");
|
|
2432
|
+
}
|
|
2433
|
+
function parseCaptionMatchPattern({ value, }) {
|
|
2434
|
+
if (value === undefined) {
|
|
2435
|
+
return undefined;
|
|
2436
|
+
}
|
|
2437
|
+
if (value === "numbers" || value === "caps" || value === "exclamations") {
|
|
2438
|
+
return value;
|
|
2439
|
+
}
|
|
2440
|
+
throw new Error("--match-pattern must be numbers, caps, or exclamations.");
|
|
2441
|
+
}
|
|
1483
2442
|
function parseFolderIdFlag({ flags, name, }) {
|
|
1484
2443
|
const value = getStringFlag({ flags, name });
|
|
1485
2444
|
if (value === undefined) {
|
|
@@ -1508,6 +2467,45 @@ function parseAssetIds({ flags }) {
|
|
|
1508
2467
|
.map((item) => item.trim())
|
|
1509
2468
|
.filter((item) => item.length > 0);
|
|
1510
2469
|
}
|
|
2470
|
+
function parseTimelineItemIds({ flags }) {
|
|
2471
|
+
const csv = getStringFlag({ flags, name: "timeline-item-ids" }) ??
|
|
2472
|
+
getStringFlag({ flags, name: "timeline-item-id" });
|
|
2473
|
+
if (!csv) {
|
|
2474
|
+
throw new Error("Missing required --timeline-item-id or --timeline-item-ids.");
|
|
2475
|
+
}
|
|
2476
|
+
return csv
|
|
2477
|
+
.split(",")
|
|
2478
|
+
.map((item) => item.trim())
|
|
2479
|
+
.filter((item) => item.length > 0);
|
|
2480
|
+
}
|
|
2481
|
+
function parseWordIds({ flags }) {
|
|
2482
|
+
const csv = getStringFlag({ flags, name: "word-ids" }) ??
|
|
2483
|
+
getStringFlag({ flags, name: "word-id" });
|
|
2484
|
+
if (!csv) {
|
|
2485
|
+
throw new Error("Missing required --word-id or --word-ids.");
|
|
2486
|
+
}
|
|
2487
|
+
return csv
|
|
2488
|
+
.split(",")
|
|
2489
|
+
.map((item) => item.trim())
|
|
2490
|
+
.filter((item) => item.length > 0);
|
|
2491
|
+
}
|
|
2492
|
+
function parseWordTextUpdatesFlag({ flags, name, }) {
|
|
2493
|
+
const parsed = parseJsonArrayFlag({ flags, name });
|
|
2494
|
+
if (parsed === undefined) {
|
|
2495
|
+
throw new Error(`Missing required --${name}.`);
|
|
2496
|
+
}
|
|
2497
|
+
return parsed.map((item, index) => {
|
|
2498
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) {
|
|
2499
|
+
throw new Error(`--${name}[${index}] must be an object.`);
|
|
2500
|
+
}
|
|
2501
|
+
const record = item;
|
|
2502
|
+
if (typeof record.word_id !== "string" ||
|
|
2503
|
+
typeof record.new_text !== "string") {
|
|
2504
|
+
throw new Error(`--${name}[${index}] must include word_id and new_text.`);
|
|
2505
|
+
}
|
|
2506
|
+
return { word_id: record.word_id, new_text: record.new_text };
|
|
2507
|
+
});
|
|
2508
|
+
}
|
|
1511
2509
|
function inferContentType({ filePath }) {
|
|
1512
2510
|
const extension = extname(filePath).toLowerCase();
|
|
1513
2511
|
switch (extension) {
|
|
@@ -1618,6 +2616,271 @@ function buildWorkspaceDefaults({ flags }) {
|
|
|
1618
2616
|
}
|
|
1619
2617
|
return defaults;
|
|
1620
2618
|
}
|
|
2619
|
+
const TEXT_STYLE_FLAG_NAMES = [
|
|
2620
|
+
"font-family",
|
|
2621
|
+
"font-size",
|
|
2622
|
+
"font-weight",
|
|
2623
|
+
"color",
|
|
2624
|
+
"background-color",
|
|
2625
|
+
"padding-x",
|
|
2626
|
+
"padding-y",
|
|
2627
|
+
"border-radius",
|
|
2628
|
+
"top",
|
|
2629
|
+
"left",
|
|
2630
|
+
"text-align",
|
|
2631
|
+
"text-shadow",
|
|
2632
|
+
"no-background",
|
|
2633
|
+
];
|
|
2634
|
+
function hasTextStyleFlags({ flags }) {
|
|
2635
|
+
return TEXT_STYLE_FLAG_NAMES.some((name) => name in flags);
|
|
2636
|
+
}
|
|
2637
|
+
function buildTextOverlaySpec({ text, name, durationSeconds, flags, }) {
|
|
2638
|
+
const durationInFrames = Math.max(1, Math.round(durationSeconds * 30));
|
|
2639
|
+
const top = getStringFlag({ flags, name: "top" }) ?? "18%";
|
|
2640
|
+
const left = getStringFlag({ flags, name: "left" }) ?? "50%";
|
|
2641
|
+
const textStyle = buildTextStyle({ flags });
|
|
2642
|
+
return {
|
|
2643
|
+
id: `cli-${Date.now()}`,
|
|
2644
|
+
fps: 30,
|
|
2645
|
+
mode: "elements",
|
|
2646
|
+
name: name ?? text,
|
|
2647
|
+
fonts: [String(textStyle.fontFamily ?? "Inter")],
|
|
2648
|
+
width: 1080,
|
|
2649
|
+
height: 1920,
|
|
2650
|
+
defaults: {
|
|
2651
|
+
color: textStyle.color,
|
|
2652
|
+
fontSize: textStyle.fontSize,
|
|
2653
|
+
fontFamily: textStyle.fontFamily,
|
|
2654
|
+
},
|
|
2655
|
+
elements: [
|
|
2656
|
+
{
|
|
2657
|
+
id: `group-${Date.now()}`,
|
|
2658
|
+
type: "group",
|
|
2659
|
+
style: {
|
|
2660
|
+
top,
|
|
2661
|
+
left,
|
|
2662
|
+
display: "inline-flex",
|
|
2663
|
+
opacity: {
|
|
2664
|
+
keyframes: [
|
|
2665
|
+
{ frame: 0, value: 0 },
|
|
2666
|
+
{ frame: 10, value: 1 },
|
|
2667
|
+
{ frame: Math.max(10, durationInFrames - 10), value: 1 },
|
|
2668
|
+
{ frame: durationInFrames, value: 0 },
|
|
2669
|
+
],
|
|
2670
|
+
},
|
|
2671
|
+
position: "absolute",
|
|
2672
|
+
transform: "translate(-50%, -50%)",
|
|
2673
|
+
alignItems: "center",
|
|
2674
|
+
flexDirection: "column",
|
|
2675
|
+
},
|
|
2676
|
+
children: [
|
|
2677
|
+
{
|
|
2678
|
+
id: `text-${Date.now()}`,
|
|
2679
|
+
type: "text",
|
|
2680
|
+
style: textStyle,
|
|
2681
|
+
layout: "none",
|
|
2682
|
+
content: text,
|
|
2683
|
+
},
|
|
2684
|
+
],
|
|
2685
|
+
},
|
|
2686
|
+
],
|
|
2687
|
+
metadata: {
|
|
2688
|
+
kind: "overlay",
|
|
2689
|
+
createdBy: "blitzreels-cli",
|
|
2690
|
+
},
|
|
2691
|
+
durationInFrames,
|
|
2692
|
+
};
|
|
2693
|
+
}
|
|
2694
|
+
function buildTextStyle({ flags }) {
|
|
2695
|
+
const noBackground = getBooleanFlag({ flags, name: "no-background" });
|
|
2696
|
+
const backgroundColor = noBackground
|
|
2697
|
+
? "transparent"
|
|
2698
|
+
: (getStringFlag({ flags, name: "background-color" }) ??
|
|
2699
|
+
"rgba(17, 24, 39, 0.86)");
|
|
2700
|
+
const style = {
|
|
2701
|
+
color: getStringFlag({ flags, name: "color" }) ?? "#FFFFFF",
|
|
2702
|
+
padding: `${getNumberFlag({ flags, name: "padding-y" }) ?? 12}px ${getNumberFlag({ flags, name: "padding-x" }) ?? 24}px`,
|
|
2703
|
+
fontSize: getNumberFlag({ flags, name: "font-size" }) ?? 48,
|
|
2704
|
+
textAlign: parseTextAlign({
|
|
2705
|
+
value: getStringFlag({ flags, name: "text-align" }) ?? "center",
|
|
2706
|
+
}),
|
|
2707
|
+
fontFamily: getStringFlag({ flags, name: "font-family" }) ?? "Inter",
|
|
2708
|
+
fontWeight: getStringFlag({ flags, name: "font-weight" }) ?? "700",
|
|
2709
|
+
lineHeight: 1.12,
|
|
2710
|
+
textShadow: getStringFlag({ flags, name: "text-shadow" }) ??
|
|
2711
|
+
"0 8px 22px rgba(0, 0, 0, 0.52)",
|
|
2712
|
+
borderRadius: getNumberFlag({ flags, name: "border-radius" }) ?? 18,
|
|
2713
|
+
letterSpacing: 0,
|
|
2714
|
+
backgroundColor,
|
|
2715
|
+
bubbleJoinStyle: "reverse-radius",
|
|
2716
|
+
boxDecorationBreak: "clone",
|
|
2717
|
+
};
|
|
2718
|
+
return style;
|
|
2719
|
+
}
|
|
2720
|
+
async function buildUpdatedTextSpec({ context, projectId, contentItemId, nextText, flags, }) {
|
|
2721
|
+
const items = await context.client.text.list({ projectId });
|
|
2722
|
+
const item = items.data.find((candidate) => candidate.content_item_id === contentItemId);
|
|
2723
|
+
if (!item?.spec) {
|
|
2724
|
+
throw new Error(`Content item ${contentItemId} has no editable text spec.`);
|
|
2725
|
+
}
|
|
2726
|
+
return applyTextStyleToSpec({
|
|
2727
|
+
spec: item.spec,
|
|
2728
|
+
text: nextText,
|
|
2729
|
+
flags,
|
|
2730
|
+
});
|
|
2731
|
+
}
|
|
2732
|
+
function applyTextStyleToSpec({ spec, text, flags, }) {
|
|
2733
|
+
const cloned = JSON.parse(JSON.stringify(spec));
|
|
2734
|
+
const elements = Array.isArray(cloned.elements) ? cloned.elements : [];
|
|
2735
|
+
const firstGroup = elements.find((element) => Boolean(element) &&
|
|
2736
|
+
typeof element === "object" &&
|
|
2737
|
+
element.type === "group");
|
|
2738
|
+
const children = Array.isArray(firstGroup?.children)
|
|
2739
|
+
? firstGroup.children
|
|
2740
|
+
: [];
|
|
2741
|
+
const firstText = children.find((child) => Boolean(child) &&
|
|
2742
|
+
typeof child === "object" &&
|
|
2743
|
+
child.type === "text");
|
|
2744
|
+
if (!firstText) {
|
|
2745
|
+
throw new Error("Text overlay spec has no editable text element.");
|
|
2746
|
+
}
|
|
2747
|
+
firstText.style = {
|
|
2748
|
+
...(firstText.style ?? {}),
|
|
2749
|
+
...buildTextStyle({ flags }),
|
|
2750
|
+
};
|
|
2751
|
+
if (text !== undefined) {
|
|
2752
|
+
firstText.content = text;
|
|
2753
|
+
}
|
|
2754
|
+
if (firstGroup) {
|
|
2755
|
+
const style = (firstGroup.style ??
|
|
2756
|
+
{});
|
|
2757
|
+
firstGroup.style = {
|
|
2758
|
+
...style,
|
|
2759
|
+
top: getStringFlag({ flags, name: "top" }) ?? style.top,
|
|
2760
|
+
left: getStringFlag({ flags, name: "left" }) ?? style.left,
|
|
2761
|
+
};
|
|
2762
|
+
}
|
|
2763
|
+
return cloned;
|
|
2764
|
+
}
|
|
2765
|
+
function parseTextAlign({ value, }) {
|
|
2766
|
+
if (value === "left" ||
|
|
2767
|
+
value === "center" ||
|
|
2768
|
+
value === "right" ||
|
|
2769
|
+
value === "justify") {
|
|
2770
|
+
return value;
|
|
2771
|
+
}
|
|
2772
|
+
throw new Error("--text-align must be left, center, right, or justify.");
|
|
2773
|
+
}
|
|
2774
|
+
function buildCaptionWordSelector({ flags }) {
|
|
2775
|
+
const wordIds = parseCsvFlag({ flags, name: "word-ids" }) ??
|
|
2776
|
+
parseCsvFlag({ flags, name: "word-id" });
|
|
2777
|
+
return {
|
|
2778
|
+
projectId: requireStringFlag({ flags, name: "project-id" }),
|
|
2779
|
+
wordIds,
|
|
2780
|
+
matchText: getStringFlag({ flags, name: "match-text" }),
|
|
2781
|
+
matchPattern: parseCaptionMatchPattern({
|
|
2782
|
+
value: getStringFlag({ flags, name: "match-pattern" }),
|
|
2783
|
+
}),
|
|
2784
|
+
timelineItemId: getStringFlag({ flags, name: "timeline-item-id" }),
|
|
2785
|
+
};
|
|
2786
|
+
}
|
|
2787
|
+
function buildCaptionWordStyleFromFlags({ flags, }) {
|
|
2788
|
+
const style = {};
|
|
2789
|
+
setIfDefined({
|
|
2790
|
+
target: style,
|
|
2791
|
+
key: "fontFamily",
|
|
2792
|
+
value: getStringFlag({ flags, name: "font-family" }),
|
|
2793
|
+
});
|
|
2794
|
+
setIfDefined({
|
|
2795
|
+
target: style,
|
|
2796
|
+
key: "fontWeight",
|
|
2797
|
+
value: getStringFlag({ flags, name: "font-weight" }),
|
|
2798
|
+
});
|
|
2799
|
+
setIfDefined({
|
|
2800
|
+
target: style,
|
|
2801
|
+
key: "color",
|
|
2802
|
+
value: getStringFlag({ flags, name: "color" }),
|
|
2803
|
+
});
|
|
2804
|
+
setIfDefined({
|
|
2805
|
+
target: style,
|
|
2806
|
+
key: "activeColor",
|
|
2807
|
+
value: getStringFlag({ flags, name: "active-color" }),
|
|
2808
|
+
});
|
|
2809
|
+
setIfDefined({
|
|
2810
|
+
target: style,
|
|
2811
|
+
key: "backgroundColor",
|
|
2812
|
+
value: getStringFlag({ flags, name: "background-color" }),
|
|
2813
|
+
});
|
|
2814
|
+
setIfDefined({
|
|
2815
|
+
target: style,
|
|
2816
|
+
key: "fontStyle",
|
|
2817
|
+
value: getStringFlag({ flags, name: "font-style" }),
|
|
2818
|
+
});
|
|
2819
|
+
setIfDefined({
|
|
2820
|
+
target: style,
|
|
2821
|
+
key: "activeAnimation",
|
|
2822
|
+
value: getStringFlag({ flags, name: "active-animation" }),
|
|
2823
|
+
});
|
|
2824
|
+
setIfDefined({
|
|
2825
|
+
target: style,
|
|
2826
|
+
key: "textTransform",
|
|
2827
|
+
value: getStringFlag({ flags, name: "text-transform" }),
|
|
2828
|
+
});
|
|
2829
|
+
setIfDefined({
|
|
2830
|
+
target: style,
|
|
2831
|
+
key: "textShadow",
|
|
2832
|
+
value: getStringFlag({ flags, name: "text-shadow" }),
|
|
2833
|
+
});
|
|
2834
|
+
setIfDefined({
|
|
2835
|
+
target: style,
|
|
2836
|
+
key: "glowColor",
|
|
2837
|
+
value: getStringFlag({ flags, name: "glow-color" }),
|
|
2838
|
+
});
|
|
2839
|
+
setIfDefined({
|
|
2840
|
+
target: style,
|
|
2841
|
+
key: "scale",
|
|
2842
|
+
value: getNumberFlag({ flags, name: "scale" }),
|
|
2843
|
+
});
|
|
2844
|
+
setIfDefined({
|
|
2845
|
+
target: style,
|
|
2846
|
+
key: "offsetX",
|
|
2847
|
+
value: getNumberFlag({ flags, name: "offset-x" }),
|
|
2848
|
+
});
|
|
2849
|
+
setIfDefined({
|
|
2850
|
+
target: style,
|
|
2851
|
+
key: "offsetY",
|
|
2852
|
+
value: getNumberFlag({ flags, name: "offset-y" }),
|
|
2853
|
+
});
|
|
2854
|
+
setIfDefined({
|
|
2855
|
+
target: style,
|
|
2856
|
+
key: "rotationDeg",
|
|
2857
|
+
value: getNumberFlag({ flags, name: "rotation-deg" }),
|
|
2858
|
+
});
|
|
2859
|
+
setIfDefined({
|
|
2860
|
+
target: style,
|
|
2861
|
+
key: "letterSpacing",
|
|
2862
|
+
value: getNumberFlag({ flags, name: "letter-spacing" }),
|
|
2863
|
+
});
|
|
2864
|
+
setIfDefined({
|
|
2865
|
+
target: style,
|
|
2866
|
+
key: "opacity",
|
|
2867
|
+
value: getNumberFlag({ flags, name: "opacity" }),
|
|
2868
|
+
});
|
|
2869
|
+
setIfDefined({
|
|
2870
|
+
target: style,
|
|
2871
|
+
key: "glowBlurPx",
|
|
2872
|
+
value: getNumberFlag({ flags, name: "glow-blur-px" }),
|
|
2873
|
+
});
|
|
2874
|
+
if (Object.keys(style).length === 0) {
|
|
2875
|
+
throw new Error("Provide --style-json or at least one caption word style flag.");
|
|
2876
|
+
}
|
|
2877
|
+
return style;
|
|
2878
|
+
}
|
|
2879
|
+
function setIfDefined({ target, key, value, }) {
|
|
2880
|
+
if (value !== undefined) {
|
|
2881
|
+
target[key] = value;
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
1621
2884
|
function parseContextMode({ value, }) {
|
|
1622
2885
|
if (value === "summary" ||
|
|
1623
2886
|
value === "assets" ||
|
|
@@ -1644,52 +2907,7 @@ function printHelp() {
|
|
|
1644
2907
|
console.log(`blitzreels
|
|
1645
2908
|
|
|
1646
2909
|
Usage:
|
|
1647
|
-
|
|
1648
|
-
blitzreels auth set-key --api-key KEY [--base-url URL]
|
|
1649
|
-
blitzreels auth whoami [--json]
|
|
1650
|
-
blitzreels workspace settings get [--json]
|
|
1651
|
-
blitzreels workspace settings update [--name NAME] [--protected-words foo,bar]
|
|
1652
|
-
blitzreels projects list [--search QUERY] [--status active|archived|all]
|
|
1653
|
-
blitzreels projects create --name NAME [--aspect-ratio 9:16]
|
|
1654
|
-
blitzreels projects get --project-id ID [--json]
|
|
1655
|
-
blitzreels projects rename --project-id ID --name NAME
|
|
1656
|
-
blitzreels projects update --project-id ID [--name NAME] [--description TEXT]
|
|
1657
|
-
blitzreels projects delete --project-id ID --confirm-delete
|
|
1658
|
-
blitzreels media list [--asset-type video|audio|image|document] [--json]
|
|
1659
|
-
blitzreels media get --asset-id ID [--json]
|
|
1660
|
-
blitzreels media delete --asset-id ID --confirm-delete
|
|
1661
|
-
blitzreels media upload --file ./video.mp4 [--auto-transcribe true]
|
|
1662
|
-
blitzreels media import-youtube --url URL [--folder-id ID] [--quality 1080p]
|
|
1663
|
-
blitzreels media rename --asset-id ID --name NAME
|
|
1664
|
-
blitzreels media update --asset-id ID [--description TEXT] [--folder-id ID|root]
|
|
1665
|
-
blitzreels media move --asset-id ID --target-folder-id ID|root
|
|
1666
|
-
blitzreels media attach --project-id ID --asset-id ID [--at 0]
|
|
1667
|
-
blitzreels media folders list [--json]
|
|
1668
|
-
blitzreels media folders create --name NAME [--parent-folder-id ID]
|
|
1669
|
-
blitzreels media folders rename --folder-id ID --name NAME
|
|
1670
|
-
blitzreels media folders update --folder-id ID [--parent-folder-id ID|root]
|
|
1671
|
-
blitzreels media folders delete --folder-id ID --confirm-delete
|
|
1672
|
-
blitzreels project inspect --project-id ID [--mode full] [--json]
|
|
1673
|
-
blitzreels project timeline --project-id ID [--json]
|
|
1674
|
-
blitzreels project snapshot --project-id ID --at 00:03 [--json]
|
|
1675
|
-
blitzreels project snapshots --project-id ID --at 00:01,00:03 [--json]
|
|
1676
|
-
blitzreels text add --project-id ID --text "Hook" [--at 0] [--duration 4]
|
|
1677
|
-
blitzreels text list --project-id ID [--json]
|
|
1678
|
-
blitzreels text update --project-id ID --content-item-id ID [--text "New hook"]
|
|
1679
|
-
blitzreels text remove --project-id ID --content-item-id ID
|
|
1680
|
-
blitzreels audio add --project-id ID --asset-id ID [--at 0] [--volume 0.6]
|
|
1681
|
-
blitzreels silence plan --project-id ID --timeline-item-id ID [--json]
|
|
1682
|
-
blitzreels silence apply --project-id ID --timeline-item-id ID --confirm-preview
|
|
1683
|
-
blitzreels mistakes plan --project-id ID --timeline-item-id ID [--json]
|
|
1684
|
-
blitzreels mistakes apply --project-id ID --timeline-item-id ID --confirm-preview
|
|
1685
|
-
blitzreels captions themes list [--json]
|
|
1686
|
-
blitzreels captions theme set --project-id ID --theme-id ID
|
|
1687
|
-
blitzreels captions theme set-default --theme-id ID
|
|
1688
|
-
blitzreels exports start --project-id ID [--resolution 1080p] [--format mp4]
|
|
1689
|
-
blitzreels exports wait --export-id ID [--json]
|
|
1690
|
-
blitzreels exports download --export-id ID --output ./short.mp4
|
|
1691
|
-
blitzreels api docs
|
|
1692
|
-
blitzreels api spec
|
|
2910
|
+
${COMMAND_SPECS.map((spec) => ` ${spec.usage}`).join("\n")}
|
|
1693
2911
|
|
|
1694
2912
|
Global flags:
|
|
1695
2913
|
--api-key KEY
|
|
@@ -1698,14 +2916,69 @@ Global flags:
|
|
|
1698
2916
|
`);
|
|
1699
2917
|
}
|
|
1700
2918
|
main().catch((error) => {
|
|
2919
|
+
const json = isJsonOutputRequested();
|
|
1701
2920
|
if (error instanceof BlitzReelsError) {
|
|
1702
|
-
|
|
1703
|
-
|
|
2921
|
+
printCliError({
|
|
2922
|
+
json,
|
|
2923
|
+
code: "api_error",
|
|
2924
|
+
message: `BlitzReels API error ${error.status}: ${error.message}`,
|
|
2925
|
+
status: error.status,
|
|
2926
|
+
requestId: error.requestId ?? undefined,
|
|
2927
|
+
usage: usageForCurrentCommand(),
|
|
2928
|
+
});
|
|
1704
2929
|
process.exitCode = 1;
|
|
1705
2930
|
return;
|
|
1706
2931
|
}
|
|
1707
|
-
|
|
1708
|
-
|
|
2932
|
+
if (error instanceof CliUsageError) {
|
|
2933
|
+
printCliError({
|
|
2934
|
+
json,
|
|
2935
|
+
code: error.code,
|
|
2936
|
+
message: error.message,
|
|
2937
|
+
suggestions: error.suggestions,
|
|
2938
|
+
usage: error.usage,
|
|
2939
|
+
});
|
|
2940
|
+
process.exitCode = 1;
|
|
2941
|
+
return;
|
|
2942
|
+
}
|
|
2943
|
+
const usage = usageForCurrentCommand();
|
|
2944
|
+
printCliError({
|
|
2945
|
+
json,
|
|
2946
|
+
code: "cli_error",
|
|
2947
|
+
message: error instanceof Error ? error.message : String(error),
|
|
2948
|
+
usage,
|
|
2949
|
+
});
|
|
1709
2950
|
process.exitCode = 1;
|
|
1710
2951
|
});
|
|
2952
|
+
function isJsonOutputRequested() {
|
|
2953
|
+
return process.argv.slice(2).some((value) => value === "--json");
|
|
2954
|
+
}
|
|
2955
|
+
function printCliError({ json, code, message, suggestions = [], usage, status, requestId, }) {
|
|
2956
|
+
if (json) {
|
|
2957
|
+
console.error(JSON.stringify({
|
|
2958
|
+
error: {
|
|
2959
|
+
code,
|
|
2960
|
+
message,
|
|
2961
|
+
suggestions,
|
|
2962
|
+
usage,
|
|
2963
|
+
status,
|
|
2964
|
+
request_id: requestId,
|
|
2965
|
+
},
|
|
2966
|
+
}, null, 2));
|
|
2967
|
+
return;
|
|
2968
|
+
}
|
|
2969
|
+
console.error(message);
|
|
2970
|
+
if (suggestions.length > 0) {
|
|
2971
|
+
console.error("Did you mean?");
|
|
2972
|
+
for (const suggestion of suggestions) {
|
|
2973
|
+
console.error(` ${suggestion.startsWith("--") ? suggestion : suggestion}`);
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
if (usage) {
|
|
2977
|
+
console.error("Usage:");
|
|
2978
|
+
console.error(` ${usage}`);
|
|
2979
|
+
}
|
|
2980
|
+
if (requestId) {
|
|
2981
|
+
console.error(`Request ID: ${requestId}`);
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
1711
2984
|
//# sourceMappingURL=index.js.map
|