twentythree-skills 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,631 @@
1
+ ---
2
+ name: video
3
+ description: Manage video assets — upload, list, metadata updates, thumbnails, transcoding status, sections (chapters), and subtitles.
4
+ ---
5
+
6
+ # TwentyThree Video Commands
7
+
8
+ > Video is the primary asset type in TwentyThree. Every example uses `--json` for machine-readable output.
9
+ > CLI `video` maps to API `photo` — see Terminology Notes at the bottom of this file.
10
+
11
+ ## Prerequisites
12
+
13
+ Auth scope varies: **read** (list, get, transcoding-progress), **write** (upload, update, delete, replace, frame, all section writes, all subtitle writes).
14
+ Run `twentythree auth credentials` if not already configured.
15
+ Verify: `twentythree auth status --json`
16
+
17
+ > For any flag not listed here, run `twentythree video <cmd> --agent` to get the complete flag list, types, and defaults.
18
+
19
+ ## Commands
20
+
21
+ ### video upload
22
+
23
+ **Auth scope:** write **Side effects:** creates **Output:** key-value (id + admin_url)
24
+
25
+ > **Chunked upload is automatic.** `twentythree video upload <file>` handles chunking internally.
26
+ > `--chunk-size` (default 5 MB) and `--concurrency` (default 5) are tunables — never construct multipart requests directly.
27
+
28
+ After upload the CLI prints the new video ID and its admin URL. Capture `data.id` and `data.admin_url` from the `--json` response.
29
+
30
+ | Flag | Required | Default | Description |
31
+ |------|----------|---------|-------------|
32
+ | `--title` | no | — | Title for the uploaded video |
33
+ | `--description` | no | — | Description for the uploaded video |
34
+ | `--tags` | no | — | Space-separated tags for the uploaded video |
35
+ | `--category-id` | no | — | Category ID (or comma-separated IDs) to assign the video to |
36
+ | `--publish` | no | false | Publish the video immediately after upload |
37
+ | `--chunk-size` | no | 5242880 | Chunk size in bytes (default: 5 MB) |
38
+ | `--concurrency` | no | 5 | Number of chunks to upload in parallel |
39
+
40
+ ```bash
41
+ # Basic upload
42
+ twentythree video upload ./video.mp4 --title "Demo" --json
43
+
44
+ # Upload with category, tags, and publish immediately
45
+ twentythree video upload ./video.mp4 --title "Q2 Keynote" --category-id <cat-id> --tags "product q2" --publish --json
46
+ ```
47
+
48
+ ---
49
+
50
+ ### video list
51
+
52
+ **Auth scope:** read **Side effects:** none **Output:** table (ID, Title, Duration, Status, Published, Updated)
53
+
54
+ | Flag | Required | Default | Description |
55
+ |------|----------|---------|-------------|
56
+ | `--limit` | no | — | Maximum number of videos to return (default: all) |
57
+ | `--include-unpublished` | no | — | Include unpublished videos in results |
58
+
59
+ ```bash
60
+ # List all published videos
61
+ twentythree video list --json
62
+
63
+ # List up to 20 videos including unpublished
64
+ twentythree video list --limit 20 --include-unpublished --json
65
+ ```
66
+
67
+ ---
68
+
69
+ ### video get
70
+
71
+ **Auth scope:** read **Side effects:** none **Output:** key-value
72
+
73
+ No additional flags — pass the video ID as a positional argument.
74
+
75
+ ```bash
76
+ # Get details of a specific video
77
+ twentythree video get <id> --json
78
+
79
+ # Example with a real ID
80
+ twentythree video get 12345 --json
81
+ ```
82
+
83
+ ---
84
+
85
+ ### video update
86
+
87
+ **Auth scope:** write **Side effects:** updates **Output:** key-value
88
+
89
+ | Flag | Required | Default | Description |
90
+ |------|----------|---------|-------------|
91
+ | `--title` | no | — | New title for the video |
92
+ | `--description` | no | — | New description for the video |
93
+ | `--tags` | no | — | Space-separated tags (replaces existing tags) |
94
+ | `--category-id` | no | — | Category ID (or comma-separated IDs) to assign the video to |
95
+ | `--publish` | no | — | Publish or unpublish the video |
96
+ | `--promote` | no | — | Promote or demote the video |
97
+ | `--publish-date` | no | — | Scheduled publish date/time (ISO 8601) |
98
+ | `--360` | no | — | Mark as 360° video |
99
+
100
+ ```bash
101
+ # Update title and description
102
+ twentythree video update <id> --title "New Title" --description "Updated description" --json
103
+
104
+ # Assign to category, add tags, and schedule publish
105
+ twentythree video update <id> --category-id <cat-id> --tags "demo q2" --publish-date "2026-06-01T10:00:00Z" --json
106
+ ```
107
+
108
+ ---
109
+
110
+ ### video delete
111
+
112
+ **Auth scope:** write **Side effects:** destructive **Output:** key-value
113
+
114
+ > **Warning: This action is destructive and cannot be undone.** The video and all associated data (subtitles, sections, analytics) are permanently deleted from the workspace.
115
+
116
+ No additional flags — pass the video ID as a positional argument.
117
+
118
+ ```bash
119
+ # Delete a video (destructive — cannot be undone)
120
+ twentythree video delete <id> --json
121
+
122
+ # Example with a real ID
123
+ twentythree video delete 12345 --json
124
+ ```
125
+
126
+ ---
127
+
128
+ ### video replace
129
+
130
+ **Auth scope:** write **Side effects:** updates **Output:** key-value (id + admin_url)
131
+
132
+ Replaces the video file while preserving metadata (title, description, subtitles, etc.). After replace the CLI prints the video ID and its admin URL.
133
+
134
+ | Flag | Required | Default | Description |
135
+ |------|----------|---------|-------------|
136
+ | `--chunk-size` | no | 5242880 | Chunk size in bytes (default: 5 MB) |
137
+ | `--concurrency` | no | 5 | Number of chunks to upload in parallel |
138
+
139
+ > **Chunked upload is automatic.** Replacement uses the same chunked engine as upload.
140
+
141
+ After replace, the CLI prints the video ID and its admin URL. Capture `data.id` and `data.admin_url` from the `--json` response.
142
+
143
+ ```bash
144
+ # Replace a video file
145
+ twentythree video replace <id> ./new-video.mp4 --json
146
+
147
+ # Replace with custom chunk size for large files
148
+ twentythree video replace <id> ./new-video.mp4 --chunk-size 52428800 --concurrency 3 --json
149
+ ```
150
+
151
+ ---
152
+
153
+ ### video frame
154
+
155
+ **Auth scope:** write **Side effects:** updates **Output:** key-value
156
+
157
+ Extracts a frame from the video at a given time offset and sets it as the video thumbnail.
158
+
159
+ | Flag | Required | Default | Description |
160
+ |------|----------|---------|-------------|
161
+ | `--time` | no | — | Time offset in seconds to extract the frame from |
162
+
163
+ ```bash
164
+ # Extract a frame from the beginning (default time)
165
+ twentythree video frame <id> --json
166
+
167
+ # Extract a frame at 30 seconds and set as thumbnail
168
+ twentythree video frame <id> --time 30 --json
169
+ ```
170
+
171
+ ---
172
+
173
+ ### video transcoding-progress
174
+
175
+ **Auth scope:** read **Side effects:** none **Output:** key-value
176
+
177
+ Returns the transcoding status and progress percentage for a video. Poll this after upload to confirm processing is complete before publishing.
178
+
179
+ No additional flags — pass the video ID as a positional argument.
180
+
181
+ ```bash
182
+ # Check transcoding status
183
+ twentythree video transcoding-progress <id> --json
184
+
185
+ # Example with a real ID
186
+ twentythree video transcoding-progress 12345 --json
187
+ ```
188
+
189
+ ---
190
+
191
+ ## Subtopic: video section
192
+
193
+ Sections are chapter markers on a video. Start time is expressed in seconds from the beginning of the video. Use sections to help viewers navigate long-form content.
194
+
195
+ ### video section list
196
+
197
+ **Auth scope:** read **Side effects:** none **Output:** table (ID, Title, Start Time, Description)
198
+
199
+ No additional flags — pass the video ID as a positional argument.
200
+
201
+ ```bash
202
+ # List all sections for a video
203
+ twentythree video section list <id> --json
204
+
205
+ # Example with a real ID
206
+ twentythree video section list 12345 --json
207
+ ```
208
+
209
+ ---
210
+
211
+ ### video section create
212
+
213
+ **Auth scope:** write **Side effects:** creates **Output:** key-value
214
+
215
+ | Flag | Required | Default | Description |
216
+ |------|----------|---------|-------------|
217
+ | `--title` | yes | — | Section title |
218
+ | `--start-time` | yes | — | Start time in seconds |
219
+ | `--description` | no | — | Section description |
220
+
221
+ ```bash
222
+ # Create an intro section at the beginning
223
+ twentythree video section create <id> --title "Introduction" --start-time 0 --json
224
+
225
+ # Create a named chapter at 30 seconds with description
226
+ twentythree video section create <id> --title "Deep Dive" --start-time 30 --description "Technical walkthrough" --json
227
+ ```
228
+
229
+ ---
230
+
231
+ ### video section update
232
+
233
+ **Auth scope:** write **Side effects:** updates **Output:** key-value
234
+
235
+ | Flag | Required | Default | Description |
236
+ |------|----------|---------|-------------|
237
+ | `--section-id` | yes | — | Section ID to update |
238
+ | `--title` | no | — | New section title |
239
+ | `--start-time` | no | — | New start time in seconds |
240
+ | `--description` | no | — | New section description |
241
+
242
+ ```bash
243
+ # Update a section title
244
+ twentythree video section update <id> --section-id <section-id> --title "New Title" --json
245
+
246
+ # Update start time and description
247
+ twentythree video section update <id> --section-id <section-id> --start-time 45 --description "Updated description" --json
248
+ ```
249
+
250
+ ---
251
+
252
+ ### video section delete
253
+
254
+ **Auth scope:** write **Side effects:** destructive **Output:** key-value
255
+
256
+ | Flag | Required | Default | Description |
257
+ |------|----------|---------|-------------|
258
+ | `--section-id` | yes | — | Section ID to delete |
259
+
260
+ ```bash
261
+ # Delete a section from a video
262
+ twentythree video section delete <id> --section-id <section-id> --json
263
+
264
+ # Example with real IDs
265
+ twentythree video section delete 12345 --section-id 67 --json
266
+ ```
267
+
268
+ ---
269
+
270
+ ### video section generate
271
+
272
+ **Auth scope:** write **Side effects:** creates **Output:** key-value
273
+
274
+ Automatically generates chapter sections using AI. **Prerequisite:** the video must have a transcript (auto-transcription or manual subtitle upload). The AI reads the transcript and identifies natural chapter boundaries.
275
+
276
+ No additional flags — pass the video ID as a positional argument.
277
+
278
+ ```bash
279
+ # Generate AI sections from transcript (transcript must exist)
280
+ twentythree video section generate <id> --json
281
+
282
+ # Example with a real ID
283
+ twentythree video section generate 12345 --json
284
+ ```
285
+
286
+ ---
287
+
288
+ ### video section set-thumbnail
289
+
290
+ **Auth scope:** write **Side effects:** updates **Output:** key-value
291
+
292
+ Sets the thumbnail image for a video section by extracting a frame at the given time offset.
293
+
294
+ | Flag | Required | Default | Description |
295
+ |------|----------|---------|-------------|
296
+ | `--section-id` | yes | — | Section ID |
297
+ | `--time` | no | — | Time offset in seconds for the thumbnail frame |
298
+
299
+ ```bash
300
+ # Set thumbnail for a section (uses video frame at section start by default)
301
+ twentythree video section set-thumbnail <id> --section-id <section-id> --json
302
+
303
+ # Set thumbnail at a specific time offset
304
+ twentythree video section set-thumbnail <id> --section-id <section-id> --time 15 --json
305
+ ```
306
+
307
+ ---
308
+
309
+ ## Subtopic: video subtitle
310
+
311
+ Subtitle commands manage caption tracks on a video (SRT/WebVTT formats). Use `twentythree video subtitle locales --json` to list all supported locales, and `twentythree video subtitle types --json` to list available subtitle types. Use `--agent` on any subtitle command to inspect the full flag list.
312
+
313
+ ### video subtitle list
314
+
315
+ **Auth scope:** read **Side effects:** none **Output:** table (Locale, Language, Type, Status, Primary)
316
+
317
+ | Flag | Required | Default | Description |
318
+ |------|----------|---------|-------------|
319
+ | `--include-drafts` | no | — | Include draft (unpublished) subtitle tracks |
320
+
321
+ ```bash
322
+ # List published subtitle tracks for a video
323
+ twentythree video subtitle list <id> --json
324
+
325
+ # List all tracks including drafts
326
+ twentythree video subtitle list <id> --include-drafts --json
327
+ ```
328
+
329
+ ---
330
+
331
+ ### video subtitle create
332
+
333
+ **Auth scope:** write **Side effects:** creates **Output:** key-value
334
+
335
+ Creates an empty subtitle track. Use `video subtitle upload` to add content to the track.
336
+
337
+ | Flag | Required | Default | Description |
338
+ |------|----------|---------|-------------|
339
+ | `--locale` | yes | — | Locale for the subtitle track (e.g. `en_US`, `fr_FR`, `auto`) |
340
+ | `--type` | no | general | Subtitle type: `general`, `closedcaptions`, `audiodescriptions` |
341
+ | `--draft` | no | — | Create the subtitle track as a draft (hidden from viewers) |
342
+
343
+ ```bash
344
+ # Create an English subtitle track
345
+ twentythree video subtitle create <id> --locale en_US --json
346
+
347
+ # Create a French closed-captions track as a draft
348
+ twentythree video subtitle create <id> --locale fr_FR --type closedcaptions --draft --json
349
+ ```
350
+
351
+ ---
352
+
353
+ ### video subtitle upload
354
+
355
+ **Auth scope:** write **Side effects:** creates **Output:** key-value
356
+
357
+ Uploads an SRT or WebVTT subtitle file for a video. Creates the track and populates it with the uploaded file content.
358
+
359
+ | Flag | Required | Default | Description |
360
+ |------|----------|---------|-------------|
361
+ | `--locale` | yes | — | Locale for the subtitle track (e.g. `en_US`, `fr_FR`) |
362
+ | `--type` | no | general | Subtitle type: `general`, `closedcaptions`, `audiodescriptions` |
363
+ | `--draft` | no | — | Upload as a draft (hidden from viewers until published) |
364
+
365
+ ```bash
366
+ # Upload an SRT file for English subtitles
367
+ twentythree video subtitle upload <id> ./subtitles.srt --locale en_US --json
368
+
369
+ # Upload a WebVTT file as French closed captions (draft)
370
+ twentythree video subtitle upload <id> ./captions.vtt --locale fr_FR --type closedcaptions --draft --json
371
+ ```
372
+
373
+ ---
374
+
375
+ ### video subtitle update
376
+
377
+ **Auth scope:** write **Side effects:** updates **Output:** key-value
378
+
379
+ | Flag | Required | Default | Description |
380
+ |------|----------|---------|-------------|
381
+ | `--subtitle-id` | yes | — | Locale of the subtitle track to update (e.g. `en_US`) |
382
+ | `--type` | no | — | New subtitle type: `general`, `closedcaptions`, `audiodescriptions` |
383
+ | `--draft` | no | — | Set draft status: true = hidden, false = published |
384
+ | `--default` | no | — | Set this subtitle track as the default |
385
+
386
+ ```bash
387
+ # Publish a draft subtitle track (remove draft status)
388
+ twentythree video subtitle update <id> --subtitle-id en_US --no-draft --json
389
+
390
+ # Change subtitle type and set as default
391
+ twentythree video subtitle update <id> --subtitle-id en_US --type closedcaptions --default --json
392
+ ```
393
+
394
+ ---
395
+
396
+ ### video subtitle delete
397
+
398
+ **Auth scope:** write **Side effects:** destructive **Output:** key-value
399
+
400
+ | Flag | Required | Default | Description |
401
+ |------|----------|---------|-------------|
402
+ | `--subtitle-id` | yes | — | Locale of the subtitle track to delete (e.g. `en_US`) |
403
+ | `--type` | no | general | Subtitle type to delete: `general`, `closedcaptions`, `audiodescriptions` |
404
+
405
+ ```bash
406
+ # Delete an English subtitle track
407
+ twentythree video subtitle delete <id> --subtitle-id en_US --json
408
+
409
+ # Delete a specific subtitle type
410
+ twentythree video subtitle delete <id> --subtitle-id en_US --type closedcaptions --json
411
+ ```
412
+
413
+ ---
414
+
415
+ ### video subtitle duplicate
416
+
417
+ **Auth scope:** write **Side effects:** creates **Output:** key-value
418
+
419
+ Copies a subtitle track to a new locale. Useful for pre-populating a track before translation.
420
+
421
+ | Flag | Required | Default | Description |
422
+ |------|----------|---------|-------------|
423
+ | `--subtitle-id` | yes | — | Source locale of the subtitle track to duplicate (e.g. `en_US`) |
424
+ | `--target-locale` | yes | — | Target locale for the duplicated track (e.g. `fr_FR`) |
425
+ | `--source-type` | no | general | Source subtitle type |
426
+ | `--target-type` | no | general | Target subtitle type |
427
+ | `--draft` | no | — | Create the duplicated track as a draft |
428
+
429
+ ```bash
430
+ # Duplicate English subtitles to French
431
+ twentythree video subtitle duplicate <id> --subtitle-id en_US --target-locale fr_FR --json
432
+
433
+ # Duplicate to German and keep as draft for review
434
+ twentythree video subtitle duplicate <id> --subtitle-id en_US --target-locale de_DE --draft --json
435
+ ```
436
+
437
+ ---
438
+
439
+ ### video subtitle locales
440
+
441
+ **Auth scope:** read **Side effects:** none **Output:** table (Code, Name, Auto Transcribe, Auto Translate, Live)
442
+
443
+ Lists all subtitle locale codes supported by TwentyThree. Use the `Code` value as the `--locale` or `--subtitle-id` argument in other subtitle commands.
444
+
445
+ No additional flags.
446
+
447
+ ```bash
448
+ # List all available locales
449
+ twentythree video subtitle locales --json
450
+
451
+ # Pipe to filter for English locales
452
+ twentythree video subtitle locales --json
453
+ ```
454
+
455
+ ---
456
+
457
+ ### video subtitle types
458
+
459
+ **Auth scope:** read **Side effects:** none **Output:** table (Type, Label)
460
+
461
+ Lists all valid subtitle types accepted by the platform.
462
+
463
+ No additional flags.
464
+
465
+ ```bash
466
+ # List available subtitle types
467
+ twentythree video subtitle types --json
468
+
469
+ # Use to verify the type value before creating/updating
470
+ twentythree video subtitle types --json
471
+ ```
472
+
473
+ ---
474
+
475
+ ### video subtitle data
476
+
477
+ **Auth scope:** read **Side effects:** none **Output:** key-value
478
+
479
+ Retrieves the raw subtitle content for a track. Use `--format` to select the file format.
480
+
481
+ | Flag | Required | Default | Description |
482
+ |------|----------|---------|-------------|
483
+ | `--subtitle-id` | yes | — | Locale of the subtitle track to retrieve (e.g. `en_US`) |
484
+ | `--format` | no | websrt | Subtitle format: `websrt`, `webvtt`, `json`, `adobe`, `subviewer` |
485
+ | `--type` | no | general | Subtitle type: `general`, `closedcaptions`, `audiodescriptions` |
486
+
487
+ ```bash
488
+ # Get raw subtitle data in default SRT format
489
+ twentythree video subtitle data <id> --subtitle-id en_US --json
490
+
491
+ # Get subtitle data in WebVTT format
492
+ twentythree video subtitle data <id> --subtitle-id en_US --format webvtt --json
493
+ ```
494
+
495
+ ---
496
+
497
+ ### video subtitle set-primary
498
+
499
+ **Auth scope:** write **Side effects:** updates **Output:** key-value
500
+
501
+ Sets a subtitle track as the primary (default) language for the video.
502
+
503
+ | Flag | Required | Default | Description |
504
+ |------|----------|---------|-------------|
505
+ | `--subtitle-id` | yes | — | Locale of the subtitle track to set as primary (e.g. `en_US`) |
506
+
507
+ ```bash
508
+ # Set English as the primary subtitle language
509
+ twentythree video subtitle set-primary <id> --subtitle-id en_US --json
510
+
511
+ # Set French as primary
512
+ twentythree video subtitle set-primary <id> --subtitle-id fr_FR --json
513
+ ```
514
+
515
+ ---
516
+
517
+ ### video subtitle archive
518
+
519
+ **Auth scope:** write (both paths) **Side effects:** creates (without --progress) | none (with --progress) **Output:** key-value
520
+
521
+ Triggers or checks workspace-wide subtitle archive transcription. Without `--progress`, starts transcription. With `--progress`, reports current transcription status.
522
+
523
+ > Note: `--progress` only reads status and has read-only semantics, but both paths require write scope because the command maps to POST endpoints.
524
+
525
+ | Flag | Required | Default | Description |
526
+ |------|----------|---------|-------------|
527
+ | `--progress` | no | false | Check transcription progress instead of triggering transcription |
528
+
529
+ ```bash
530
+ # Trigger workspace subtitle archive transcription
531
+ twentythree video subtitle archive --json
532
+
533
+ # Check transcription progress
534
+ twentythree video subtitle archive --progress --json
535
+ ```
536
+
537
+ ---
538
+
539
+ ## Common Patterns
540
+
541
+ ### Upload, update metadata, and publish
542
+
543
+ ```bash
544
+ # 1. Upload video (chunked upload is automatic)
545
+ twentythree video upload ./demo.mp4 --title "Q2 Demo" --json
546
+ # => { "data": { "id": "<video-id>", "admin_url": "..." } }
547
+
548
+ # 2. Update tags and category
549
+ twentythree video update <video-id> --tags "demo q2" --category-id <cat-id> --json
550
+
551
+ # 3. Publish
552
+ twentythree video update <video-id> --publish --json
553
+ ```
554
+
555
+ ### Poll for transcoding completion before publishing
556
+
557
+ ```bash
558
+ # Check transcoding status (repeat until status is "complete")
559
+ twentythree video transcoding-progress <id> --json
560
+ # => { "data": { "status": "transcoding", "progress": 45 } }
561
+
562
+ # When progress reaches 100 / status is "complete", publish
563
+ twentythree video update <id> --publish --json
564
+ ```
565
+
566
+ ### Extract a thumbnail frame
567
+
568
+ ```bash
569
+ # Set thumbnail at 15 seconds into the video
570
+ twentythree video frame <id> --time 15 --json
571
+
572
+ # Alternatively, use video section set-thumbnail for a section preview
573
+ twentythree video section set-thumbnail <id> --section-id <section-id> --time 15 --json
574
+ ```
575
+
576
+ ### Create chapter markers (sections)
577
+
578
+ ```bash
579
+ # Create multiple sections for a structured video
580
+ twentythree video section create <id> --title "Introduction" --start-time 0 --json
581
+ twentythree video section create <id> --title "Demo" --start-time 30 --json
582
+ twentythree video section create <id> --title "Q&A" --start-time 180 --json
583
+
584
+ # List all sections to verify
585
+ twentythree video section list <id> --json
586
+ ```
587
+
588
+ ### Generate AI chapters from transcript
589
+
590
+ ```bash
591
+ # Prerequisite: video must have a transcript (subtitle track created or uploaded)
592
+ # First, check if subtitles/transcript exist
593
+ twentythree video subtitle list <id> --json
594
+
595
+ # Generate chapters using AI
596
+ twentythree video section generate <id> --json
597
+ # => Creates sections based on transcript content
598
+ ```
599
+
600
+ ### Upload and publish subtitle tracks
601
+
602
+ ```bash
603
+ # Upload English SRT subtitles
604
+ twentythree video subtitle upload <id> ./en-subtitles.srt --locale en_US --json
605
+
606
+ # Publish the track (if created as draft)
607
+ twentythree video subtitle update <id> --subtitle-id en_US --no-draft --json
608
+
609
+ # Set as primary language
610
+ twentythree video subtitle set-primary <id> --subtitle-id en_US --json
611
+
612
+ # Duplicate to French for translation
613
+ twentythree video subtitle duplicate <id> --subtitle-id en_US --target-locale fr_FR --draft --json
614
+ ```
615
+
616
+ ---
617
+
618
+ ## Terminology Notes
619
+
620
+ CLI `video` = API `photo`. The `api_endpoint` field in `--agent` output uses the API name:
621
+
622
+ - `twentythree video upload` -> `POST /photo/redeem-upload-token`
623
+ - `twentythree video list` -> `GET /photo/list`
624
+ - `twentythree video update` -> `POST /photo/update`
625
+ - `twentythree video delete` -> `POST /photo/delete`
626
+ - `twentythree video replace` -> `POST /photo/replace`
627
+ - `twentythree video frame` -> `POST /photo/frame`
628
+ - `twentythree video transcoding-progress` -> `GET /photo/get-transcoding-progress`
629
+
630
+ When reading the raw OpenAPI spec or debugging API responses, `photo` refers to a video asset.
631
+ When commenting on a video via the `comment` topic, pass `--object-type photo`.