veodl 1.12.1 → 2.0.1
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/AGENTS.md +12 -12
- package/CHANGELOG.md +404 -373
- package/LICENSE +21 -21
- package/README.md +1040 -910
- package/bin/veo.js +47 -2
- package/docs/AGENT_GUIDE.md +135 -122
- package/native/android-arm64/veo +0 -0
- package/native/darwin-arm64/veo +0 -0
- package/native/darwin-x64/veo +0 -0
- package/native/linux-arm64/veo +0 -0
- package/native/linux-x64/veo +0 -0
- package/native/win32-arm64/veo.exe +0 -0
- package/native/win32-x64/veo.exe +0 -0
- package/package.json +53 -57
- package/src/alias.js +0 -258
- package/src/backend-update.js +0 -191
- package/src/backend.js +0 -572
- package/src/changes.js +0 -278
- package/src/cli.js +0 -785
- package/src/compatibility.js +0 -39
- package/src/config-clipboard.js +0 -67
- package/src/config-diagnostics.js +0 -155
- package/src/config-editor.js +0 -404
- package/src/config-errors.js +0 -64
- package/src/config-reset.js +0 -39
- package/src/config-template.js +0 -227
- package/src/config.js +0 -307
- package/src/disk-space.js +0 -68
- package/src/doctor.js +0 -306
- package/src/download-cache.js +0 -31
- package/src/downloader.js +0 -704
- package/src/execution.js +0 -68
- package/src/experimental-fragments.js +0 -29
- package/src/flush.js +0 -66
- package/src/history.js +0 -173
- package/src/inline-region.js +0 -72
- package/src/inspect-media.js +0 -179
- package/src/interactive.js +0 -120
- package/src/jobs.js +0 -218
- package/src/legacy-config-comments.js +0 -106
- package/src/media-assets.js +0 -272
- package/src/naming.js +0 -54
- package/src/open-file.js +0 -15
- package/src/option-suggestions.js +0 -43
- package/src/output.js +0 -81
- package/src/path-links.js +0 -53
- package/src/paths.js +0 -26
- package/src/playlist.js +0 -31
- package/src/progress.js +0 -341
- package/src/run-archive.js +0 -148
- package/src/runs.js +0 -346
- package/src/source-discovery.js +0 -305
- package/src/state.js +0 -27
- package/src/stats.js +0 -63
- package/src/terminal-size.js +0 -8
- package/src/terminal-title.js +0 -19
- package/src/tool-setup.js +0 -289
- package/src/uninstall.js +0 -222
- package/src/updater.js +0 -229
- package/src/utils.js +0 -208
- package/src/version.js +0 -38
package/README.md
CHANGED
|
@@ -1,910 +1,1040 @@
|
|
|
1
|
-
# veo
|
|
2
|
-
|
|
3
|
-
A small, clean video-downloading CLI powered by [yt-dlp](https://github.com/yt-dlp/yt-dlp). No banners, just progress and the saved file path.
|
|
4
|
-
|
|
5
|
-
Automating with an agent? Start with the [agent guide](docs/AGENT_GUIDE.md) for JSON output, run inspection and audio verification.
|
|
6
|
-
|
|
7
|
-
**Only download content you own or are authorized or legally permitted to download.** Respect copyright, website terms, and access restrictions. veo does not bypass DRM, private-content access controls, or paywalls.
|
|
8
|
-
|
|
9
|
-
## Install and run
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
npm
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
--
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
--
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
--
|
|
77
|
-
--
|
|
78
|
-
|
|
79
|
-
--
|
|
80
|
-
--
|
|
81
|
-
--
|
|
82
|
-
--
|
|
83
|
-
--
|
|
84
|
-
--
|
|
85
|
-
--
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
--
|
|
90
|
-
--
|
|
91
|
-
--
|
|
92
|
-
--
|
|
93
|
-
--
|
|
94
|
-
--
|
|
95
|
-
--
|
|
96
|
-
--
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
veo --
|
|
149
|
-
|
|
150
|
-
veo
|
|
151
|
-
veo --
|
|
152
|
-
veo
|
|
153
|
-
veo
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
- `
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
`--
|
|
306
|
-
|
|
307
|
-
the
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
Use `
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
a
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
{
|
|
480
|
-
|
|
481
|
-
"
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
- `--
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
veo
|
|
573
|
-
veo
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
veo
|
|
592
|
-
veo
|
|
593
|
-
|
|
594
|
-
veo
|
|
595
|
-
|
|
596
|
-
veo
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
`
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
veo
|
|
704
|
-
veo
|
|
705
|
-
veo
|
|
706
|
-
veo
|
|
707
|
-
veo
|
|
708
|
-
veo
|
|
709
|
-
veo
|
|
710
|
-
veo
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
`
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
veo
|
|
732
|
-
veo
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
`
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
`veo
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
the
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
veo
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
1
|
+
# veo
|
|
2
|
+
|
|
3
|
+
A small, clean video-downloading CLI powered by [yt-dlp](https://github.com/yt-dlp/yt-dlp). No banners, just progress and the saved file path.
|
|
4
|
+
|
|
5
|
+
Automating with an agent? Start with the [agent guide](docs/AGENT_GUIDE.md) for JSON output, run inspection and audio verification.
|
|
6
|
+
|
|
7
|
+
**Only download content you own or are authorized or legally permitted to download.** Respect copyright, website terms, and access restrictions. veo does not bypass DRM, private-content access controls, or paywalls.
|
|
8
|
+
|
|
9
|
+
## Install and run
|
|
10
|
+
|
|
11
|
+
veo is a single native executable (written in Rust) for Windows, macOS, Linux and
|
|
12
|
+
Android/Termux. Internet access is needed for installation and first-use backend setup.
|
|
13
|
+
|
|
14
|
+
The npm package is `veodl`; the installed commands are `veo` and `veodl`. npm installs the
|
|
15
|
+
prebuilt binary for your platform from a matching `veodl-<platform>-<arch>` package; no
|
|
16
|
+
install scripts run. Node.js is only needed for npm itself, not to run downloads.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx veodl "https://example.com/video.mp4"
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Or install globally:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install -g veodl
|
|
26
|
+
veo "https://example.com/video.mp4"
|
|
27
|
+
# or: veodl "https://example.com/video.mp4"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The first download automatically prepares missing yt-dlp, FFmpeg and FFprobe.
|
|
31
|
+
On Android/Termux this includes installing the native packages and yt-dlp's
|
|
32
|
+
JavaScript support with `pkg install -y`. On desktop systems, missing media tools
|
|
33
|
+
are downloaded into veo's own cache. Run `veo doctor fix` to prepare everything
|
|
34
|
+
before downloading. Plain `veo doctor`, help and version do not install tools.
|
|
35
|
+
|
|
36
|
+
Without npm, download the binary for your platform from the GitHub releases page, or
|
|
37
|
+
build it with Rust 1.85+:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
cargo install --git https://github.com/Mailo037/veodl
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
From this checkout:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
cargo build --release # target/release/veo
|
|
47
|
+
cargo test # unit and offline end-to-end tests
|
|
48
|
+
cargo test --test smoke -- --ignored # real downloads with yt-dlp and FFmpeg
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Use only trusted URLs, and quote URLs to protect query strings from your shell.
|
|
52
|
+
|
|
53
|
+
If something does not work, run `veo doctor` first: it inspects the whole local setup and prints one line per check.
|
|
54
|
+
|
|
55
|
+
Run `veo` without arguments in an interactive terminal for a guided download: choose a
|
|
56
|
+
profile, enter a link, select video or audio, choose available resolution and output
|
|
57
|
+
directory, and start. The wizard checks the link and asks about playlist mode only when
|
|
58
|
+
it finds a collection; configured playlist and entry selection values are preselected.
|
|
59
|
+
Playlist mode also lists entries for selection. The wizard enables
|
|
60
|
+
resume and offers skipping previously downloaded files. With redirected input, use the
|
|
61
|
+
regular command arguments; veo never starts a prompt in a script.
|
|
62
|
+
|
|
63
|
+
## Usage
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
Usage:
|
|
67
|
+
veo <url> [<url>...] [options]
|
|
68
|
+
|
|
69
|
+
Download:
|
|
70
|
+
-q, --quality <quality> Video quality (best, 2160p, 1440p, 1080p, 720p, 480p, 360p)
|
|
71
|
+
Numeric qualities are an upper bound: -q 720p never
|
|
72
|
+
downloads 2160p.
|
|
73
|
+
--closest-quality Pick the nearest available resolution, above or below
|
|
74
|
+
-o, --output <path> Output directory (default: current directory)
|
|
75
|
+
-r, --rename <name> Filename without extension; * inserts the original title
|
|
76
|
+
--audio Download audio only (default: mp3)
|
|
77
|
+
--format <format> Video: mp4, mkv, webm, mov; audio: mp3, m4a, aac, opus, flac, wav
|
|
78
|
+
Video uses lossless remux; incompatible codecs fail.
|
|
79
|
+
--compatible Ensure MP4 H.264/AAC; converts only when needed (may lose quality)
|
|
80
|
+
--recode Allow video conversion (requires --format; may lose quality)
|
|
81
|
+
--open Open the saved file with your default app
|
|
82
|
+
--resume Keep partial data and continue an interrupted download
|
|
83
|
+
--skip-existing Skip matching downloads still present on disk
|
|
84
|
+
--section <range> Download only a time range, e.g. "*10:00-12:00"
|
|
85
|
+
--sponsorblock-remove <categories>
|
|
86
|
+
Remove sponsor segments, e.g. "sponsor,selfpromo"
|
|
87
|
+
|
|
88
|
+
Subtitles and metadata:
|
|
89
|
+
--subs Download subtitles (default languages: en)
|
|
90
|
+
--auto-subs Include automatically generated subtitles
|
|
91
|
+
--sub-langs <langs> Subtitle languages, e.g. "de,en" (manual unless --auto-subs)
|
|
92
|
+
--sub-format <format> Preferred subtitle format, e.g. srt/vtt/best
|
|
93
|
+
--list-subs Show manual and automatic subtitle languages, then exit
|
|
94
|
+
--embed-subs Embed subtitles into the video file
|
|
95
|
+
--embed-metadata Embed title, date and other metadata
|
|
96
|
+
--embed-thumbnail Embed the thumbnail
|
|
97
|
+
|
|
98
|
+
Playlists and batches:
|
|
99
|
+
--playlist Download every entry of a playlist or channel URL
|
|
100
|
+
--playlist-items <list> Select playlist entries, e.g. 1,3-5 (implies --playlist)
|
|
101
|
+
--playlist-concurrency <n> Simultaneous playlist downloads (1-4; default: 2)
|
|
102
|
+
--concurrent-downloads <n> Parallel URLs/batch entries (1-4; default: 2)
|
|
103
|
+
--batch-file <file> Read URLs from a file (one per line; # comments)
|
|
104
|
+
--retry-failed <id|file> Retry failed/unfinished items by run ID or job file
|
|
105
|
+
|
|
106
|
+
Naming and privacy:
|
|
107
|
+
--filename-template <s> Filename without extension, e.g. {index} - {title}
|
|
108
|
+
--folder-template <s> Relative folders, e.g. {channel}/{year}
|
|
109
|
+
--neutral-filename Use a random video name; omit title and naming templates
|
|
110
|
+
--incognito Save media without run IDs, history, stats or retry data
|
|
111
|
+
|
|
112
|
+
Inspect before downloading:
|
|
113
|
+
--list-qualities Show available video resolutions and exit
|
|
114
|
+
--list-qualitys Alias for --list-qualities
|
|
115
|
+
--list-formats Show the available formats and exit
|
|
116
|
+
--list-sources Find video sources loaded by a web page and exit
|
|
117
|
+
--auto-list-sources Search after no video is found (default: on)
|
|
118
|
+
--source <n> Select source number from that page (also for scripts)
|
|
119
|
+
--deep-scan Check every media candidate found during source search
|
|
120
|
+
--timeout <duration> Source search deadline, e.g. 30, 30s or 2m (5s-10m)
|
|
121
|
+
--dry-run Show what would be downloaded and exit
|
|
122
|
+
|
|
123
|
+
Network and performance:
|
|
124
|
+
-N, --concurrent-fragments <n>
|
|
125
|
+
Parallel fragments (1-64; default: 8); 17-64 are experimental
|
|
126
|
+
--experimental-fragments Explicitly accept experimental values above 16
|
|
127
|
+
Otherwise requires terminal confirmation before download
|
|
128
|
+
--adaptive-concurrency Reduce connections and retry temporary failures (default: on)
|
|
129
|
+
--check-space Estimate cache/output space before downloading (default: on)
|
|
130
|
+
--cookies <file> Netscape cookie file, for content you may access
|
|
131
|
+
--cookies-from-browser <browser[:profile]>
|
|
132
|
+
Read cookies from an installed browser
|
|
133
|
+
|
|
134
|
+
Output and scripting:
|
|
135
|
+
--json Print one JSON object per URL instead of prose
|
|
136
|
+
--verify Probe saved media files with FFprobe (default: off)
|
|
137
|
+
--timings Show phase timings (default: on; --no-timings disables)
|
|
138
|
+
--no-color Disable terminal colors (also respects NO_COLOR)
|
|
139
|
+
--profile <name> Apply a named config profile
|
|
140
|
+
--no-<boolean-option> Disable a stored boolean default, e.g. --no-open
|
|
141
|
+
-v, --version Show installed version (also: veo version)
|
|
142
|
+
-h, --help Show help; veo help all lists every option and command
|
|
143
|
+
|
|
144
|
+
Commands:
|
|
145
|
+
veo doctor Diagnose the local setup
|
|
146
|
+
veo update|up [--check] Update veo itself with npm (up is a short alias)
|
|
147
|
+
veo history Show the last 5 downloads (--json for scripting)
|
|
148
|
+
veo history --failed --limit 20
|
|
149
|
+
Filter and extend download history
|
|
150
|
+
veo retry --last Retry the newest failed or unfinished job
|
|
151
|
+
veo runs [id] List active runs; add --json for metadata and progress
|
|
152
|
+
veo stop [id] Stop one run, or every active run
|
|
153
|
+
veo stats Show persistent download statistics
|
|
154
|
+
veo changes [<version>] List release notes; --since <version> for newer changes
|
|
155
|
+
veo subs <url> List available manual and automatic subtitles
|
|
156
|
+
veo inspect <file> Read media metadata; --check-audio measures audio signal
|
|
157
|
+
veo inspect run <id> Inspect saved files from a finished run by its id
|
|
158
|
+
veo backend update Install a newer yt-dlp release (see veo backend --help)
|
|
159
|
+
veo flush Stop veo runs and clear temporary downloads and jobs
|
|
160
|
+
veo config edit|path|profiles|guide|check|show|reset
|
|
161
|
+
Manage defaults and named profiles
|
|
162
|
+
veo config edit [--external|--terminal]
|
|
163
|
+
Choose the configuration editor
|
|
164
|
+
veo profile [list|reset|name]
|
|
165
|
+
Show, list or change the default profile
|
|
166
|
+
veo alias list|add|remove Manage extra command names (wrappers calling veo)
|
|
167
|
+
veo uninstall [-p <name>] Remove one alias, or everything with --yes
|
|
168
|
+
veo version Show the installed version
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
veo "https://youtube.com/watch?v=VIDEO_ID" -q 1080p
|
|
173
|
+
veo "https://x.com/USER/status/STATUS_ID" -q best
|
|
174
|
+
veo "https://example.com/video.mp4" --audio
|
|
175
|
+
veo "https://example.com/video.mp4" --audio --format flac
|
|
176
|
+
veo "https://example.com/video.mp4" --format webm --recode -o ./videos
|
|
177
|
+
veo "https://example.com/video.mp4" -r "My Video" --format mp4 --open
|
|
178
|
+
veo "https://example.com/video.mp4" --audio -r "My Music"
|
|
179
|
+
veo <url1> <url2> <url3> --embed-metadata --subs
|
|
180
|
+
veo "https://youtube.com/playlist?list=LIST_ID" --playlist -q 720p
|
|
181
|
+
veo "https://example.com/video.mp4" --resume
|
|
182
|
+
npx veodl "https://example.com/video.mp4" --output ./downloads
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Several URLs and playlists
|
|
186
|
+
|
|
187
|
+
Playlist downloads use two concurrent entries by default; use `--playlist-concurrency 1` for sequential downloads. Each entry uses up to eight concurrent DASH/HLS fragments by default (`-N 1` disables fragment parallelism). Fragment counts between 1 and 16 need no confirmation. Values from 17 to 64 are experimental and prompt for `y/N` confirmation in terminals, or require `--experimental-fragments` (or `"experimentalFragments": true` in configuration/profiles) in non-interactive environments and JSON mode. Values above 64 are rejected. More connections help only when the source and connection have spare capacity, and excessive connections may trigger server limits. Video format changes preserve the encoded streams unless `--recode` is explicitly enabled; audio extraction and precise section cuts retain their existing conversion behavior.
|
|
188
|
+
|
|
189
|
+
- Pass any number of URLs; up to two run concurrently by default. Use
|
|
190
|
+
`--concurrent-downloads 1` for sequential processing. A failure is reported
|
|
191
|
+
with its URL and does not stop the remaining URLs; the exit status is `1` if anything
|
|
192
|
+
failed.
|
|
193
|
+
- Playlists, channels and other collections are refused by default with a hint. Add
|
|
194
|
+
`--playlist` to download every entry. Each entry keeps its own title; `--rename` applies
|
|
195
|
+
a name prefix per entry (`My Name - 001`), or substitutes each title with `movie_*`.
|
|
196
|
+
- Use `--playlist-items 1,3-5` to select entries by their original, one-based index.
|
|
197
|
+
Playlist entries run with bounded parallelism: a failed entry does not discard successful
|
|
198
|
+
files or stop the remaining entries. Before downloading, veo displays the selected count
|
|
199
|
+
and a size estimate when the source supplies sizes. Unknown sizes are labeled explicitly;
|
|
200
|
+
metadata estimates do not predict conversion size.
|
|
201
|
+
- `--batch-file links.txt` accepts a UTF-8 URL list, optionally alongside URLs on the command
|
|
202
|
+
line. A final summary counts saved, skipped and failed videos. Successful files are opened
|
|
203
|
+
with `--open` even if another URL or playlist entry fails.
|
|
204
|
+
- Failed or cancelled jobs print a ready-to-use `veo --retry-failed <runId>` command. Saved job file paths are also accepted.
|
|
205
|
+
- Use `veo retry --last` to retry the newest failed or unfinished job without copying its path. Active runs are ignored; use `veo runs` to inspect them.
|
|
206
|
+
Jobs are stored under the per-user veo cache's `jobs` directory. Retries retain resolved
|
|
207
|
+
output directories and settings, even from a different working directory, and explicit
|
|
208
|
+
flags can override them. Completed playlist jobs retry only failed indices; interrupted
|
|
209
|
+
playlists revisit their selection and skip completed entries through resume history.
|
|
210
|
+
Playlist indices refer to the playlist's current order, so changes to that order can
|
|
211
|
+
change what an index selects. Cookie paths and browser-session settings are not saved in
|
|
212
|
+
retry jobs; pass those flags again if needed. Job files contain URLs, settings and local
|
|
213
|
+
file paths and can be deleted when no longer needed.
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
veo --batch-file links.txt --profile archive
|
|
217
|
+
veo "https://example.com/playlist" --playlist-items 1,3-5 --resume
|
|
218
|
+
veo "https://example.com/playlist" --playlist --skip-existing
|
|
219
|
+
veo --retry-failed "C:\path\to\job.json"
|
|
220
|
+
veo --retry-failed abc123
|
|
221
|
+
veo retry --last
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Quality
|
|
225
|
+
|
|
226
|
+
- Numeric qualities are an **upper bound**: `-q 720p` downloads the best resolution at or
|
|
227
|
+
below 720p, so a metered connection can never accidentally receive a 2160p file. If a
|
|
228
|
+
source offers nothing at or below the request, veo stops before downloading and lists
|
|
229
|
+
the resolutions that do exist.
|
|
230
|
+
- `--closest-quality` restores the former "nearest available resolution" rule, which may
|
|
231
|
+
pick a resolution *above* the request. It needs a numeric `--quality`.
|
|
232
|
+
- Sources that report no resolution metadata fall back to the best available stream.
|
|
233
|
+
Collections resolve and enforce the quality limit separately for each entry.
|
|
234
|
+
- Other positive numeric resolutions, such as `-q 540p`, are also accepted. The interactive
|
|
235
|
+
wizard offers the resolutions reported by the source; without resolution metadata it
|
|
236
|
+
offers `best` rather than inventing available streams.
|
|
237
|
+
- `--quality` does not apply to audio.
|
|
238
|
+
- MP4-compatible codecs are preferred at the selected resolution; merged video prefers MP4
|
|
239
|
+
with MKV fallback. A single-file source may retain its original container. Use
|
|
240
|
+
`--format mp4` to require MP4 through lossless remuxing. Incompatible codecs cause an error.
|
|
241
|
+
- `--format` on video remuxes without re-encoding. Add `--recode` to explicitly allow conversion, which may be slow or lossy. Audio formats require `--audio`.
|
|
242
|
+
|
|
243
|
+
### Playback compatibility
|
|
244
|
+
|
|
245
|
+
H.264/AAC sources are preferred at the selected quality, including explicit MP4 output.
|
|
246
|
+
Original codecs are retained by default; a playback note identifies media needing extra
|
|
247
|
+
player codecs. MP4 is a container, not a promise of a particular codec.
|
|
248
|
+
|
|
249
|
+
Use `veo URL --compatible` to ensure MP4 with H.264 8-bit 4:2:0 and AAC.
|
|
250
|
+
Already compatible streams are copied; only incompatible streams are encoded (H.264 CRF 18,
|
|
251
|
+
AAC 192 kbit/s), which takes time and may lose quality. HDR requiring video conversion
|
|
252
|
+
is refused rather than silently losing correct colors. Embedded subtitles/thumbnails are
|
|
253
|
+
not supported in this mode; separate subtitle files remain supported.
|
|
254
|
+
New configs include a `kompatibel` profile; existing configs receive a commented profile
|
|
255
|
+
example through `veo config edit`. Enable it with `veo URL --profile kompatibel`.
|
|
256
|
+
|
|
257
|
+
### Download controls and diagnostics
|
|
258
|
+
|
|
259
|
+
- URL lists and batch files use `--concurrent-downloads 2` by default (range 1–4).
|
|
260
|
+
Each playlist independently uses `--playlist-concurrency 2` (range 1–4).
|
|
261
|
+
The worker limits multiply when several playlists run at once, while media
|
|
262
|
+
connections share a host-local budget (normally `concurrentFragments`, or the
|
|
263
|
+
larger of that and `httpConnections` for eligible native HTTP transfers).
|
|
264
|
+
JSON emits one complete
|
|
265
|
+
object per URL in completion order; the `url` field identifies each result.
|
|
266
|
+
- Adaptive concurrency is on by default. After the backend's own retries are exhausted,
|
|
267
|
+
HTTP 429/5xx and temporary connection failures trigger at most two further attempts,
|
|
268
|
+
after 2 and 4 seconds. Capacity is reduced for that host, then recovers one step
|
|
269
|
+
after four successful operations. Workers wait for capacity and remain available
|
|
270
|
+
for later items. Active backend transfers retain their connection count until
|
|
271
|
+
the next attempt; format and quality stay fixed.
|
|
272
|
+
Partials are continued on retry. Use `--no-adaptive-concurrency` to disable this.
|
|
273
|
+
- `--native-http` is on by default for anonymous, direct HTTP(S) video files that
|
|
274
|
+
require no subtitle, metadata or section processing. Rust reuses HTTP connections
|
|
275
|
+
and writes byte ranges into disjoint offsets of one file, avoiding an assembly
|
|
276
|
+
copy. `--http-connections 4` controls native connections (1–16); the shared host
|
|
277
|
+
budget may reduce the effective count. Files smaller than 8 MiB use one range.
|
|
278
|
+
A strong ETag and valid byte-range responses are required for ranged resume;
|
|
279
|
+
changed ETags discard partial data. Servers without range support or a strong
|
|
280
|
+
validator use a full stream. Unsupported responses fall back to yt-dlp.
|
|
281
|
+
Cookies, custom authentication headers, multiple formats and transformations
|
|
282
|
+
continue through yt-dlp. Use `--no-native-http` to force that path.
|
|
283
|
+
- Single-video extraction results are reused through a private temporary info
|
|
284
|
+
file, removed when yt-dlp exits. Expired media information is refreshed. Flat
|
|
285
|
+
playlists use direct entry page URLs when available, preserving entry indices
|
|
286
|
+
for naming, selection and retry. Raw extraction results are never archived.
|
|
287
|
+
- `--staging-dir output` stages under `<output>/.veo-staging`, so the final save can
|
|
288
|
+
use a hard link on supported filesystems instead of copying across drives.
|
|
289
|
+
`--staging-dir D:/veo-cache` chooses a specific staging directory. The default
|
|
290
|
+
remains local-cache staging, which can work better for slow network/cloud drives.
|
|
291
|
+
Explicit roots are registered for expiration cleanup and `veo flush`; flush
|
|
292
|
+
removes only veo partial directories and keeps saved media. Incognito creates
|
|
293
|
+
an unregistered private child directory and removes it after the attempt.
|
|
294
|
+
- `--section "*10:00-12:00" --fast-cut` skips forced keyframes for a faster cut
|
|
295
|
+
aligned to nearby existing keyframes. Start/end positions can be less precise.
|
|
296
|
+
Omit `--fast-cut` to keep precise cuts. This setting changes download identity,
|
|
297
|
+
so a previous precise-cut result cannot be reused as a fast-cut result.
|
|
298
|
+
- `--verify` reuses the compatibility probe only when saving preserves the exact
|
|
299
|
+
file identity, size and modification time. Converted files, copies and retained
|
|
300
|
+
transfer retries receive a fresh probe.
|
|
301
|
+
- `--check-space` checks cache and destination free space before media transfer. Known
|
|
302
|
+
sizes include conservative room for merge output and a destination copy, plus space
|
|
303
|
+
reserved by concurrent downloads in the same process. Unknown sizes are reported as
|
|
304
|
+
unknown; conversion sizes and other processes' disk usage cannot be predicted exactly.
|
|
305
|
+
Use `--no-check-space` to disable this conservative check.
|
|
306
|
+
- `--timings` shows phase times at the end of the run. Single downloads show
|
|
307
|
+
timing without a summary; multiple downloads show timing below the summary.
|
|
308
|
+
The phases cover setup, metadata, download/backend, processing, saving and retry waits.
|
|
309
|
+
Download/backend includes the backend's own startup and extraction overhead;
|
|
310
|
+
these are summed per-download times, not a diagnosis of network speed.
|
|
311
|
+
JSON results include `timings` in milliseconds, or `entryTimings` for playlists.
|
|
312
|
+
Use `--no-timings` to hide/omit them.
|
|
313
|
+
- Terminal details are gray, titles bold, saves green and errors red. The same styling
|
|
314
|
+
applies to stats, history, runs/stop, doctor, flush, updates, config prose, help and
|
|
315
|
+
interactive prompts. For example, `veo stats --no-color` disables it for one command. Redirected output
|
|
316
|
+
and JSON have no color escapes. `--no-color`, `"color": false`, `NO_COLOR`,
|
|
317
|
+
and `TERM=dumb` disable colors.
|
|
318
|
+
Terminal reports shorten long URLs, paths and detail values to the current window
|
|
319
|
+
width. Titles can use up to three lines before an ellipsis is added. This also
|
|
320
|
+
applies with `--no-color`; JSON and redirected output retain complete values.
|
|
321
|
+
Downloads stay in the normal terminal flow. Only the current progress block is
|
|
322
|
+
updated in place; narrow windows put the statistics below the progress bar.
|
|
323
|
+
Existing logs remain in scrollback and are not replayed or rewritten on resize.
|
|
324
|
+
This can be set independently per profile, for example
|
|
325
|
+
`"profiles": { "default": { "color": true }, "plain": { "color": false } }`.
|
|
326
|
+
Use `veo stats --profile plain` or `veo URL --profile plain`; `--color` or
|
|
327
|
+
`--no-color` overrides the profile for one invocation (except `NO_COLOR`).
|
|
328
|
+
External npm and editor output keeps its own formatting.
|
|
329
|
+
|
|
330
|
+
### Filename templates and folders
|
|
331
|
+
|
|
332
|
+
`--filename-template` controls the name without extension; `--folder-template`
|
|
333
|
+
creates relative subfolders under `--output`. Both support `{title}`, `{id}`,
|
|
334
|
+
`{channel}`, `{year}`, `{playlist}` and `{index}` (three-digit playlist index).
|
|
335
|
+
Missing metadata uses readable fallbacks. `{year}` is the upload year when available.
|
|
336
|
+
Subtitles follow the media name. Existing files are never overwritten. Templates cannot
|
|
337
|
+
escape the output folder, and symlink/junction subfolders are refused. Use forward slashes
|
|
338
|
+
for folders. `--rename` and `--filename-template` are mutually exclusive.
|
|
339
|
+
|
|
340
|
+
```powershell
|
|
341
|
+
veo "VIDEO-URL" --folder-template "{channel}/{year}" --filename-template "{title} - {id}"
|
|
342
|
+
veo "PLAYLIST-URL" --playlist --folder-template "{playlist}" --filename-template "{index} - {title}"
|
|
343
|
+
veo config check
|
|
344
|
+
veo config check --profile fast
|
|
345
|
+
veo config show --profile fast
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Config checks validate every effective profile (or the selected one), including unknown
|
|
349
|
+
settings, ranges and conflicting options. Show prints merged built-in, global and profile
|
|
350
|
+
settings as JSON, with credential paths/browser profiles redacted. Neither command contacts
|
|
351
|
+
video sites. All new options are also documented in `veo config guide`.
|
|
352
|
+
|
|
353
|
+
### Files, names and resume
|
|
354
|
+
|
|
355
|
+
- Original titles are preserved by default. Use `-r "My Video"` or `--rename "My Video"`
|
|
356
|
+
for video or audio. Supply the name **without an extension**; the actual media extension
|
|
357
|
+
is appended automatically. Use `-o` for the directory. Invalid filename characters are
|
|
358
|
+
sanitized and overly long names shortened. Existing files are never intentionally
|
|
359
|
+
overwritten: duplicates get ` (1)`, ` (2)`, etc.
|
|
360
|
+
- Use `-r "movie_*"` or `"rename": "movie_*"` in your config/profile to insert the
|
|
361
|
+
original title: `My Film` becomes `movie_My Film.mp4`. Every `*` is substituted.
|
|
362
|
+
Quote the pattern in your shell. Patterns also work with URL batches and playlists.
|
|
363
|
+
- Subtitles and thumbnails are saved beside the media file under the same base name
|
|
364
|
+
(`My Video.mp4` → `My Video.en.vtt`).
|
|
365
|
+
- Downloads and media processing first finish in the local per-user veo cache, under
|
|
366
|
+
`downloads` (`%LOCALAPPDATA%\veo\downloads` on Windows). The destination is only written
|
|
367
|
+
after the media is ready. Saving uses a hard link when supported or an exclusive copy
|
|
368
|
+
across drives/cloud mounts; copied file sizes are checked. Existing files are never
|
|
369
|
+
overwritten. The local original is removed only after files and history are saved.
|
|
370
|
+
Local disk space is therefore needed for the complete download and processing files.
|
|
371
|
+
- If saving fails or is cancelled after media processing completes, the local original and
|
|
372
|
+
sidecars are kept for **15 minutes**, even without `--resume`. Repeat the same command or
|
|
373
|
+
use the printed `--retry-failed` command to retry the transfer. Individual completed
|
|
374
|
+
downloads can be recovered without contacting their source again. The same source,
|
|
375
|
+
media settings and destination identify a cached transfer; changing those starts a new
|
|
376
|
+
download. Expired copies are removed on the next veo invocation, not by a background
|
|
377
|
+
timer while veo is closed. Active transfers are never expired. Another failed transfer
|
|
378
|
+
starts a fresh 15-minute retention period.
|
|
379
|
+
- `--resume` also keeps unfinished downloads in local `.veo-part-<request-hash>` folders
|
|
380
|
+
until resumed; unfinished data has no automatic expiry. Without `--resume`, unfinished
|
|
381
|
+
downloads are discarded on failure or cancellation. The hash separates source URLs,
|
|
382
|
+
playlist entries, destinations, quality, media type, format, sections and subtitle/metadata
|
|
383
|
+
options. A manifest records backend-confirmed
|
|
384
|
+
completion and saved files, so an unprocessed file is not mistaken for a finished video.
|
|
385
|
+
Each playlist entry has its own state. Completed entries survive later failures and are
|
|
386
|
+
skipped when resuming the same selection. Partial downloads are never resumed without
|
|
387
|
+
`--resume`. Legacy partial folders in the output directory are left untouched; the new
|
|
388
|
+
local cache does not automatically migrate them.
|
|
389
|
+
- A lock prevents two resume processes from using the same partial folder. Normal failures
|
|
390
|
+
and Ctrl+C release it. After a force kill, remove the named `.lock` file only after making
|
|
391
|
+
sure no veo process still uses that folder.
|
|
392
|
+
- Successful downloads record their source, output settings and saved paths in
|
|
393
|
+
`.veo-history` inside the output directory. `--skip-existing` uses these records and checks
|
|
394
|
+
that the files still exist. A different quality/format or deleted output is downloaded
|
|
395
|
+
again. Files downloaded before this history existed are not recognized automatically.
|
|
396
|
+
Deleting history removes duplicate detection, not downloaded media. Records whose files
|
|
397
|
+
no longer exist are removed on the next download into that folder, and `.veo-history`
|
|
398
|
+
itself is removed with its last record; `veo doctor` reports stale records.
|
|
399
|
+
|
|
400
|
+
### Metadata and subtitles
|
|
401
|
+
|
|
402
|
+
- `veo subs <URL>` lists manual and automatically generated subtitles separately, including
|
|
403
|
+
their languages and source formats. `--json` returns one object without subtitle URLs.
|
|
404
|
+
- `--subs` writes manual subtitle files. `--auto-subs` adds generated subtitles, or selects
|
|
405
|
+
only generated subtitles when used alone. `--sub-langs de,en` selects languages;
|
|
406
|
+
`--sub-format srt/vtt/best` prefers available source formats in that order. A format
|
|
407
|
+
preference does not convert subtitles. `--embed-subs` embeds selected subtitles into
|
|
408
|
+
the video container.
|
|
409
|
+
- `--embed-metadata` and `--embed-thumbnail` use FFmpeg to write metadata and cover art.
|
|
410
|
+
- `--sponsorblock-remove sponsor,selfpromo` cuts sponsor segments (YouTube) and requires
|
|
411
|
+
FFmpeg; the cut re-encodes the affected parts.
|
|
412
|
+
- `--section "*10:00-12:00"` downloads only a time range.
|
|
413
|
+
- `-N 8` downloads several fragments in parallel, which is noticeably faster on HLS/DASH
|
|
414
|
+
sources and heavier on the network.
|
|
415
|
+
|
|
416
|
+
### Optional post-download verification
|
|
417
|
+
|
|
418
|
+
Use `veo <URL> --verify` or set `"verify": true` in a config profile to check
|
|
419
|
+
saved media with FFprobe before recording a successful download. It checks that
|
|
420
|
+
the container can be probed and contains a video track (or an audio track for
|
|
421
|
+
`--audio`). Verification is off by default; `--no-verify` overrides a profile.
|
|
422
|
+
This quick check does not decode the whole file or prove that the audio is
|
|
423
|
+
audible. Use `veo inspect <file> --check-audio` for a full audio signal check.
|
|
424
|
+
If verification fails, veo reports failure and keeps the saved file for review.
|
|
425
|
+
|
|
426
|
+
### Access and credentials
|
|
427
|
+
|
|
428
|
+
veo downloads publicly accessible content. It does not bypass access controls, and it does
|
|
429
|
+
not expose options that defeat them. If you need your own session for content you are
|
|
430
|
+
authorized to view:
|
|
431
|
+
|
|
432
|
+
- `--cookies ./cookies.txt` passes a Netscape-format cookie file. The file is validated
|
|
433
|
+
before any network work, and on Unix a file readable by other users produces a warning.
|
|
434
|
+
- `--cookies-from-browser firefox:Work` reads cookies from an installed browser: `brave`,
|
|
435
|
+
`chrome`, `chromium`, `edge`, `firefox`, `opera`, `safari`, `vivaldi`, `whale`, optionally
|
|
436
|
+
with `+gnomekeyring`/`+kwallet`/`+basic` and a profile or container.
|
|
437
|
+
|
|
438
|
+
Credentials are used for that single invocation only and are never stored by veo. When a
|
|
439
|
+
download fails because a login is required, the error message points at these flags.
|
|
440
|
+
|
|
441
|
+
### Inspection and scripting
|
|
442
|
+
|
|
443
|
+
- `veo <page-url> --list-sources` opens the page in a temporary headless Chrome,
|
|
444
|
+
Edge or Chromium profile, repeatedly checks for visible Play controls (including
|
|
445
|
+
controls added later or inside frames), and watches media requests after interaction.
|
|
446
|
+
Use `--json` for numbered source
|
|
447
|
+
metadata. Each result includes its title, host, HLS/DASH/direct type, known
|
|
448
|
+
resolutions, estimated MiB size and Mbit/s bitrate when the source provides them. Signed media
|
|
449
|
+
URLs are not printed. Set `VEO_BROWSER_PATH` if the browser is not found.
|
|
450
|
+
- Add `--deep-scan` to verify every media candidate observed during the source
|
|
451
|
+
search. The normal search verifies at most 30 candidates. `--timeout 30s`
|
|
452
|
+
sets a deadline for browser observation and candidate verification; plain
|
|
453
|
+
numbers mean seconds, and `m` means minutes (5 seconds to 10 minutes).
|
|
454
|
+
Defaults are 45 seconds, or 2 minutes with `--deep-scan`. If the deadline
|
|
455
|
+
is reached, verified sources found so far are shown with a timeout notice.
|
|
456
|
+
A deep scan covers observed requests; it cannot discover sources that the
|
|
457
|
+
page never loads. The timeout does not stop a subsequent download.
|
|
458
|
+
- For an unsupported single page URL, veo searches for media automatically and
|
|
459
|
+
uses the only verified source when there is one. If several sources are found,
|
|
460
|
+
the terminal asks which one to use; scripts receive a numbered source list and
|
|
461
|
+
a nonzero exit. `veo <page-url> --source 2 --dry-run --json` previews a chosen
|
|
462
|
+
source, and `veo <page-url> --source 2 --json` downloads it. Scripts never
|
|
463
|
+
receive an interactive prompt.
|
|
464
|
+
Retry jobs retain the page URL and selected number and discover a fresh media
|
|
465
|
+
URL, because player links may expire. Browser discovery uses a temporary
|
|
466
|
+
profile without copying browser cookies, and cannot unlock DRM content.
|
|
467
|
+
Misspelled flags and commands show a nearby valid spelling, for example
|
|
468
|
+
`--deepscan` suggests `--deep-scan`.
|
|
469
|
+
- `veo <url> --list-qualities` lists available video resolutions, highest first,
|
|
470
|
+
without downloading media. `--list-qualitys` is an alias. Add `--json` for
|
|
471
|
+
a `qualities` array (e.g. `["1080p", "720p"]`); use `--quality 720p` to select
|
|
472
|
+
an upper bound. Unknown resolutions are reported without guessing. Audio-only,
|
|
473
|
+
storyboard and DRM formats are excluded. Supports `--source <number>` for embedded players.
|
|
474
|
+
- `--list-formats` prints the backend's own format table for one URL and exits.
|
|
475
|
+
- `--dry-run` prints the title, the resolved quality and the destination path that would be
|
|
476
|
+
used — without creating the output directory or downloading anything.
|
|
477
|
+
- `--json` prints one JSON object per line on stdout:
|
|
478
|
+
`{"url":…,"status":"saved","title":…,"files":[…]}` or
|
|
479
|
+
`{"url":…,"status":"failed","error":…}`. Progress and status still go to stderr. Without
|
|
480
|
+
`--json`, every saved file is printed as `Saved: <path>` on stdout.
|
|
481
|
+
Duplicate detection can return `status: "skipped"`; cancellation returns `"cancelled"`.
|
|
482
|
+
Playlist results also include `saved`, `skipped` and `failures` (with original indices).
|
|
483
|
+
A failed or cancelled playlist can still report files saved before the failure.
|
|
484
|
+
- `veo runs [id] --json` reports active run metadata and per-item progress. Finished attempts
|
|
485
|
+
remain available through `veo history --json`.
|
|
486
|
+
- `veo inspect <file> --json` reports local container and stream metadata. Add
|
|
487
|
+
`--check-audio` to decode all audio tracks and measure whether any peak exceeds
|
|
488
|
+
-60 dBFS. A track can exist without a detectable signal. The check reads the full
|
|
489
|
+
media file and uses only local FFmpeg/FFprobe tools.
|
|
490
|
+
- Download results and history retain a `runId`. `veo inspect run <id> --json` reads
|
|
491
|
+
a finished run and checks every saved file before probing it. Renamed media is
|
|
492
|
+
found by file identity, size and a sampled SHA-256 fingerprint within the original output tree;
|
|
493
|
+
add `--search <directory>` after moving it elsewhere. Ambiguous or missing files
|
|
494
|
+
are reported without probing another file. Old runs lack this persistent record.
|
|
495
|
+
Finished run records live in the current device's veo cache. On Windows, macOS,
|
|
496
|
+
Linux and Termux, `inspect` uses bundled media tools where supported and otherwise
|
|
497
|
+
uses local `ffmpeg` and `ffprobe` (or `VEO_FFMPEG_PATH`); it does not install them.
|
|
498
|
+
Copying only the media to another device does not copy its run ID record.
|
|
499
|
+
|
|
500
|
+
### Config file
|
|
501
|
+
|
|
502
|
+
Defaults can be stored in a config file, so a long list of flags is not needed for every
|
|
503
|
+
call. `veo doctor` prints the exact path; `VEO_CONFIG` overrides it.
|
|
504
|
+
The file accepts JSON with `//` line comments and `/* ... */` block comments. Strings
|
|
505
|
+
(including URLs and Windows paths) keep their normal JSON escaping rules. Trailing commas
|
|
506
|
+
are not allowed.
|
|
507
|
+
|
|
508
|
+
- Windows: `%APPDATA%\veo\config.json`
|
|
509
|
+
- macOS: `~/Library/Application Support/veo/config.json`
|
|
510
|
+
- Linux: `$XDG_CONFIG_HOME/veo/config.json` (or `~/.config/veo/config.json`)
|
|
511
|
+
|
|
512
|
+
```json
|
|
513
|
+
{
|
|
514
|
+
"output": "D:\\Videos",
|
|
515
|
+
"quality": "1080p",
|
|
516
|
+
"embedMetadata": true,
|
|
517
|
+
"subLangs": "de,en",
|
|
518
|
+
"concurrentFragments": 4
|
|
519
|
+
}
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
Supported keys: `output`, `quality`, `format`, `rename`, `audio`, `open`, `resume`, `incognito`, `neutralFilename`,
|
|
523
|
+
`closestQuality`, `cookies`, `cookiesFromBrowser`, `playlist`, `concurrentFragments`,
|
|
524
|
+
`experimentalFragments`, `playlistConcurrency`, `recode`, `compatible`, `concurrentDownloads`, `adaptiveConcurrency`,
|
|
525
|
+
`filenameTemplate`, `folderTemplate`, `checkSpace`, `timings`, `color`,
|
|
526
|
+
`nativeHttp`, `httpConnections`, `stagingDir`, `fastCut`,
|
|
527
|
+
`subs`, `autoSubs`, `subLangs`, `subFormat`, `embedSubs`, `embedMetadata`, `embedThumbnail`, `sponsorblockRemove`, `verify`,
|
|
528
|
+
`section`, `json`. An explicit command-line flag always wins over a stored default. An
|
|
529
|
+
unknown key produces a warning; invalid JSON or a wrong value type is an error, because
|
|
530
|
+
silently ignoring a typo would be worse.
|
|
531
|
+
|
|
532
|
+
Source discovery defaults are `deepScan` (boolean), `timeout` (string such as
|
|
533
|
+
`"30s"` or `"2m"`), `listSources` (boolean) and `autoListSources` (boolean).
|
|
534
|
+
`listSources: true` makes a single URL list sources and exit; use
|
|
535
|
+
`--no-list-sources` to download for one invocation. `autoListSources` defaults
|
|
536
|
+
to `true` and searches when ordinary extraction finds no downloadable video.
|
|
537
|
+
Set it to `false` or pass `--no-auto-list-sources` to disable that fallback.
|
|
538
|
+
A single verified source is selected automatically; multiple sources require
|
|
539
|
+
a choice. `deepScan` and
|
|
540
|
+
`timeout` apply to either kind of source search.
|
|
541
|
+
|
|
542
|
+
Additional defaults are `skipExisting` and `playlistItems`. Boolean defaults can be disabled
|
|
543
|
+
with `--no-open`, `--no-audio`, `--no-resume`, `--no-embed-metadata`, etc. `--no-subs` also
|
|
544
|
+
disables stored subtitle languages and subtitle embedding for that invocation.
|
|
545
|
+
|
|
546
|
+
### Incognito downloads
|
|
547
|
+
|
|
548
|
+
Use `veo <url> --incognito` or set `"incognito": true` in a named profile. The
|
|
549
|
+
downloaded media is saved normally. veo does not assign a run ID or write a
|
|
550
|
+
retry job, run archive, download history, output `.veo-history` record, or
|
|
551
|
+
statistics for that attempt. It uses a private temporary staging directory and
|
|
552
|
+
removes it after success, failure, or cancellation. It also disables yt-dlp's
|
|
553
|
+
filesystem cache. `--no-incognito` overrides
|
|
554
|
+
a profile for one request. Incognito cannot be combined with `--resume`,
|
|
555
|
+
`--skip-existing`, or `--retry-failed`; there is no veo retry for an incognito
|
|
556
|
+
attempt. A force-killed process may leave temporary files that the OS can
|
|
557
|
+
clean later. The destination file, shell history, network service, and source
|
|
558
|
+
website can still reveal the download.
|
|
559
|
+
|
|
560
|
+
Example profile: `"profiles": { "private": { "incognito": true } }`.
|
|
561
|
+
Add `"neutralFilename": true` to that profile, or pass `--neutral-filename`,
|
|
562
|
+
to save files as names such as `video-a1b2c3d4e5f6.mp4`. This is optional:
|
|
563
|
+
incognito keeps the normal title by default. Neutral naming overrides `--rename`,
|
|
564
|
+
`--filename-template`, and `--folder-template` for that request. The selected
|
|
565
|
+
output directory, media contents, and embedded metadata are unaffected.
|
|
566
|
+
|
|
567
|
+
### Named profiles
|
|
568
|
+
|
|
569
|
+
If no profile is selected, `profiles.default` is applied automatically. `veo profile music`
|
|
570
|
+
selects another named profile for future commands and stores it as `activeProfile` in the
|
|
571
|
+
config; `veo profile` shows the current choice, and `veo profile list` marks it in
|
|
572
|
+
the list. `veo profile reset` removes the stored choice and returns to `default`.
|
|
573
|
+
You can also use `veo profile default` to select it explicitly.
|
|
574
|
+
The names `list` and `reset` are reserved for these commands and cannot be used as profile names.
|
|
575
|
+
`--profile NAME` overrides this choice for one command. Named profiles use global defaults
|
|
576
|
+
rather than inheriting `default`. The wizard preselects the active profile.
|
|
577
|
+
New configurations include an empty `default` profile and the example profiles. Existing configurations are
|
|
578
|
+
left unchanged when opened. An empty profile does not change download behavior.
|
|
579
|
+
|
|
580
|
+
```json
|
|
581
|
+
{
|
|
582
|
+
"output": "D:\\Videos",
|
|
583
|
+
"profiles": {
|
|
584
|
+
"default": { "quality": "1080p", "resume": true },
|
|
585
|
+
"music": { "audio": true, "format": "mp3", "output": "D:\\Music" },
|
|
586
|
+
"archive": { "quality": "1080p", "embedMetadata": true, "subLangs": "de,en" }
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
`veo <url> --profile music` merges global defaults, then the selected profile, then explicit
|
|
592
|
+
CLI flags. `veo config profiles` lists profile names; `veo config path` prints the file path.
|
|
593
|
+
The download status shows `Profile: NAME` (or `global (no profile)` when none is configured).
|
|
594
|
+
`veo config edit` creates a small, valid configuration for new or empty files. Opening an
|
|
595
|
+
existing configuration does not add or update comments. The current option guide is kept in
|
|
596
|
+
the program; `veo config guide` prints it without changing the file. In the built-in editor,
|
|
597
|
+
F3 offers **A** to add or update the guide at the top and **R** to remove a previously
|
|
598
|
+
generated guide. Ctrl+S saves that choice. This can also clean up the long duplicate block
|
|
599
|
+
inserted by older versions. Personal settings and notes below a generated block are preserved.
|
|
600
|
+
In an interactive terminal, it opens the built-in editor
|
|
601
|
+
unless `VISUAL` or `EDITOR` is configured (an executable path, without shell arguments).
|
|
602
|
+
The editor provides syntax colors, line numbers and live validation. Syntax errors mark
|
|
603
|
+
the affected line; unknown properties and invalid values are highlighted directly, with
|
|
604
|
+
spelling suggestions, expected types and allowed values in the status area. Validation uses
|
|
605
|
+
the same rules as the CLI, including profile overrides and audio/video formats.
|
|
606
|
+
Press F2 on a property or value to open suggestions, use Up/Down to choose, Enter to apply
|
|
607
|
+
or Esc to cancel. Suggestions require valid JSON syntax; free-text values and custom numeric
|
|
608
|
+
resolutions such as `900p` remain supported. Ctrl+S validates and saves;
|
|
609
|
+
Ctrl+Z undoes edits, Ctrl+Y redoes them, and Ctrl+A selects the whole file.
|
|
610
|
+
Esc or Ctrl+Q exits, asking before discarding changes. Use arrows, Home/End and PageUp/PageDown
|
|
611
|
+
to navigate. Invalid configurations cannot be saved. `--no-color` disables syntax colors.
|
|
612
|
+
In terminals supporting SGR mouse reporting, left-click positions the cursor and dragging
|
|
613
|
+
selects text, including across lines. Holding the pointer at the top or bottom while dragging
|
|
614
|
+
scrolls the file and extends the selection. Backspace/Delete removes the selection; typing replaces
|
|
615
|
+
it. The mouse wheel scrolls without changing the editing position; Ctrl+Up/Down also scrolls.
|
|
616
|
+
Ctrl+C copies selected text to the system clipboard, and Ctrl+V pastes clipboard text at the
|
|
617
|
+
cursor or replaces the selection. Ctrl+Q or Esc exits the editor. The editor disables mouse
|
|
618
|
+
reporting again when it exits. Keyboard editing remains available in terminals without mouse
|
|
619
|
+
support.
|
|
620
|
+
Clipboard access uses the system clipboard on Windows, `pbcopy`/`pbpaste` on macOS, and
|
|
621
|
+
`wl-clipboard` (Wayland), `xclip` or `xsel` (X11) on Linux. Linux requires one of those tools
|
|
622
|
+
and access to a graphical session. The editor reports when no clipboard is available; terminal
|
|
623
|
+
paste shortcuts can still insert text directly when supported by the terminal.
|
|
624
|
+
On Termux, editor clipboard shortcuts use `termux-clipboard-set`/`termux-clipboard-get`
|
|
625
|
+
when the Termux:API app and `termux-api` package are installed.
|
|
626
|
+
|
|
627
|
+
Use `veo config edit --external` to use `VISUAL`, then `EDITOR`, then Notepad on Windows
|
|
628
|
+
or `vi` elsewhere. `veo config edit --terminal` explicitly selects the built-in editor.
|
|
629
|
+
Set `VEO_CONFIG_EDITOR=external` to disable the built-in editor by default (`auto` restores
|
|
630
|
+
automatic selection, `terminal` forces it). For a persistent Windows preference:
|
|
631
|
+
|
|
632
|
+
```powershell
|
|
633
|
+
[Environment]::SetEnvironmentVariable('VEO_CONFIG_EDITOR', 'external', 'User')
|
|
634
|
+
$env:VEO_CONFIG_EDITOR = 'external'
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
Non-interactive sessions use the external editor unless `--terminal` is explicitly selected,
|
|
638
|
+
in which case an interactive-terminal error is reported. The wizard also offers configured profiles.
|
|
639
|
+
Generated guides and app messages are in English. Existing comments, profile names and
|
|
640
|
+
settings are preserved when opening the editor.
|
|
641
|
+
|
|
642
|
+
### Terminal output
|
|
643
|
+
|
|
644
|
+
- During a download, the terminal/tab title shows `veo | 50% | My Video` (original title or
|
|
645
|
+
your `-r` name), plus setup/processing status. It ends with `Done`, `Failed`, or
|
|
646
|
+
`Cancelled`; the shell may replace it at the next prompt. This uses the native console
|
|
647
|
+
title on Windows (including PowerShell/Windows Terminal) and OSC title sequences on
|
|
648
|
+
compatible Linux/macOS terminals. Titles are not changed when stderr is redirected or
|
|
649
|
+
`TERM=dumb`. Terminal settings that enforce a fixed tab title can override this feature.
|
|
650
|
+
- Progress shows percentage, speed, downloaded/total size and ETA on stderr; unknown values
|
|
651
|
+
appear as `?`. Separate audio/video streams each have their own progress. Non-interactive
|
|
652
|
+
output is throttled.
|
|
653
|
+
- Progress labels include the current item (`[3/12]`), source title, video/audio/media stream,
|
|
654
|
+
postprocessing (merging, conversion, subtitles or metadata) and saving. Stream percentages
|
|
655
|
+
describe that stream, not the entire multi-step job. Sources without codec metadata use
|
|
656
|
+
the neutral `Media` label.
|
|
657
|
+
- `--open` launches the completed file in your default app, including renamed files and
|
|
658
|
+
audio. With several URLs, the primary file of each URL is opened. Uses `explorer.exe` on
|
|
659
|
+
Windows, `open` on macOS, and `xdg-open` on Linux (requires a graphical desktop,
|
|
660
|
+
xdg-utils and a file association). The CLI does not wait for the player to close. If the
|
|
661
|
+
opener cannot be launched, a warning is printed and the successful download still exits
|
|
662
|
+
with `0`; later errors inside the detached opener/player are not monitored.
|
|
663
|
+
- After each successful command, veo checks the npm registry at most once per day for a
|
|
664
|
+
newer version and prints a one-line notice on stderr (`Update available: veo X
|
|
665
|
+
(you have Y). Run: veo up`). Help, version and the update commands themselves
|
|
666
|
+
stay quiet. Disable it with `VEO_NO_UPDATE_CHECK=1`;
|
|
667
|
+
`VEO_REGISTRY`/`npm_config_registry` are respected.
|
|
668
|
+
- Exit status is `0` on success, `1` on errors, and `130` on cancellation. With several
|
|
669
|
+
URLs, `1` means at least one URL failed.
|
|
670
|
+
|
|
671
|
+
## Commands
|
|
672
|
+
|
|
673
|
+
```bash
|
|
674
|
+
veo version # installed version (also: veo --version or veo -v)
|
|
675
|
+
veo # interactive download wizard (terminal only)
|
|
676
|
+
veo config edit # create/open config; F3 offers the optional guide
|
|
677
|
+
veo config guide # print the current option guide
|
|
678
|
+
veo config reset # confirm with y; back up config and restore the current template
|
|
679
|
+
veo config profiles # list available profiles
|
|
680
|
+
veo profile # show the currently selected profile
|
|
681
|
+
veo profile list # list all profiles and mark the active one
|
|
682
|
+
veo profile music # use music as the default for future commands
|
|
683
|
+
veo profile reset # return to default (or global settings if absent)
|
|
684
|
+
veo config path # show the config file location
|
|
685
|
+
veo doctor # diagnose the local setup; exit 1 if a check fails
|
|
686
|
+
veo doctor fix # restore missing or damaged managed tools
|
|
687
|
+
veo doctor --offline # skip the network checks
|
|
688
|
+
veo stats # persistent download totals; --json for scripting
|
|
689
|
+
veo history # the last 5 downloads; --json for scripting
|
|
690
|
+
veo history --failed --limit 20 # recent failed/cancelled attempts
|
|
691
|
+
veo changes # released versions, newest first; the installed one is marked
|
|
692
|
+
veo changes 1.10.1 # notes of one release (also: --version 1.10.1)
|
|
693
|
+
veo changes --since 1.10.1 # everything newer than a version
|
|
694
|
+
veo changes --latest --json # newest release as JSON
|
|
695
|
+
veo retry --last # retry the newest failed or unfinished job
|
|
696
|
+
veo runs # active runs with their id; veo runs <id> for details
|
|
697
|
+
veo runs --json # machine-readable active run metadata
|
|
698
|
+
veo inspect FILE --check-audio --json # track metadata and audio signal
|
|
699
|
+
veo subs URL --json # available manual and automatic subtitles
|
|
700
|
+
veo inspect run ID --check-audio --json # finished run and saved media
|
|
701
|
+
veo stop [id] # stop one run, or every active run
|
|
702
|
+
veo flush # stop runs, clear temporary downloads and retry jobs
|
|
703
|
+
veo flush --stats # the same, and reset the statistics
|
|
704
|
+
veo update # install the latest veo with npm
|
|
705
|
+
veo update --check # only check for a newer veo
|
|
706
|
+
veo up # short alias for veo update (also: veo up --check)
|
|
707
|
+
veo upgrade # alias for veo update
|
|
708
|
+
veo check update # alias for veo update --check
|
|
709
|
+
veo backend update # install the newest yt-dlp release
|
|
710
|
+
veo backend reset # back to the release pinned in this veo version
|
|
711
|
+
veo alias list # shipped (veo, veodl) plus custom wrappers
|
|
712
|
+
veo alias add veo-dl # create veo-dl as a wrapper that calls veo
|
|
713
|
+
veo alias remove veo-dl # delete a custom wrapper
|
|
714
|
+
veo uninstall -p veodl # delete one alias (veo itself stays installed)
|
|
715
|
+
veo uninstall # plan the full removal (aliases, package, cache, config)
|
|
716
|
+
veo uninstall --yes # remove everything
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
`veo update` runs `npm install -g veodl@latest` and then removes yt-dlp backend
|
|
720
|
+
caches from older pinned releases, keeping an explicitly installed backend release. It
|
|
721
|
+
never uses a shell on Linux/macOS, passes fixed arguments only, and prints the manual npm
|
|
722
|
+
command on any failure. The registry can be overridden with `VEO_REGISTRY` (or npm's
|
|
723
|
+
`npm_config_registry`) for mirrors and proxies.
|
|
724
|
+
|
|
725
|
+
### `veo alias` and `veo uninstall`
|
|
726
|
+
|
|
727
|
+
The npm package is `veodl`; a global install ships the commands `veo`
|
|
728
|
+
and `veodl`. `veo alias` manages extra command names without reinstalling:
|
|
729
|
+
|
|
730
|
+
```bash
|
|
731
|
+
veo alias list
|
|
732
|
+
veo alias add veo-dl
|
|
733
|
+
veo alias remove veo-dl
|
|
734
|
+
veo uninstall -p veodl
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
`add` creates a small wrapper next to the `veo` command found on `PATH` that
|
|
738
|
+
forwards to `veo`, so it survives `veo update`. Names use 2-31 lowercase
|
|
739
|
+
letters, digits or hyphens. `remove` (also `veo alias rm`) deletes the wrapper
|
|
740
|
+
files; `veo` itself can never be removed this way. Removing a shipped name such
|
|
741
|
+
as `veodl` only deletes that shortcut — the next `veo update` recreates it.
|
|
742
|
+
|
|
743
|
+
`veo uninstall -p <name>` is a shortcut for `veo alias remove <name>`. Bare
|
|
744
|
+
`veo uninstall` removes everything: without flags it only prints the plan
|
|
745
|
+
(package `veodl` with commands veo, veodl, plus custom wrappers, cache
|
|
746
|
+
and config paths); `veo uninstall --yes` deletes all of it — custom wrappers,
|
|
747
|
+
the package with `npm uninstall -g veodl`, veo's cache directory (downloads,
|
|
748
|
+
jobs, backend tools, history, statistics) and the config file. Use
|
|
749
|
+
`--keep-aliases`, `--keep-cache` or `--keep-config` to preserve one part.
|
|
750
|
+
The plan shows the active config path, including a `VEO_CONFIG` override.
|
|
751
|
+
Add `--json` for scripting.
|
|
752
|
+
|
|
753
|
+
### `veo flush`
|
|
754
|
+
|
|
755
|
+
Run `veo flush` to stop active veo runs started with this version, then remove
|
|
756
|
+
temporary local downloads, including the 15-minute retained files and unfinished
|
|
757
|
+
resume data, and cached retry job JSON files. Those jobs can no longer be retried.
|
|
758
|
+
Saved media, output history, config/profiles, the `veo history` list, finished-run
|
|
759
|
+
records and backend binaries are kept.
|
|
760
|
+
Cleanup waits for cancellation; if a run cannot stop, it fails without deleting
|
|
761
|
+
download or job files. Locked folders from older or interrupted processes are
|
|
762
|
+
skipped and reported. Only veo's own per-user cache is cleaned. Statistics are
|
|
763
|
+
preserved unless `--stats` is given: `veo flush --stats` resets them too.
|
|
764
|
+
To end runs without removing their downloads and jobs, use `veo stop [id]` instead.
|
|
765
|
+
|
|
766
|
+
### `veo stats`
|
|
767
|
+
|
|
768
|
+
Shows saved videos/audio, failed attempts, skips, cancellations and total time spent
|
|
769
|
+
on download requests (including preparation, processing and saving). Parallel run
|
|
770
|
+
times are added together. Playlist entries count individually; retries are new
|
|
771
|
+
attempts. Active requests are recorded when they finish. Tracking starts with this
|
|
772
|
+
version; previous downloads are not imported. `veo stats --json` returns the totals
|
|
773
|
+
as JSON. Statistics contain counters and timestamps, not URLs or filenames.
|
|
774
|
+
|
|
775
|
+
### `veo history`
|
|
776
|
+
|
|
777
|
+
Shows the **last 5 download attempts** by default, newest first, with title, status, media type,
|
|
778
|
+
date, duration, URL and the saved files. Saved, skipped, failed and cancelled items are
|
|
779
|
+
recorded, including the reason a failure was reported; playlist entries and retried
|
|
780
|
+
attempts count individually. Active downloads appear once they finish. Long file lists
|
|
781
|
+
are summarized in the text view.
|
|
782
|
+
|
|
783
|
+
Use `veo history --limit N` to show 1-1000 attempts, or `veo history --failed` to
|
|
784
|
+
show only failed and cancelled attempts; the flags can be combined. Failed attempts
|
|
785
|
+
include their exact retry-job command when one was recorded. New attempts also show
|
|
786
|
+
their persistent run ID for `veo inspect run <id>`. `veo history --json`
|
|
787
|
+
prints `{"count":N,"entries":[…]}` for scripting. Each entry has
|
|
788
|
+
`at`, `url`, `title`, `status`, `media` (`video`/`audio`), `quality`, `format`, the
|
|
789
|
+
complete `files` list, `error`, `elapsedMs` and an optional `job` path. Titles and paths are stored without
|
|
790
|
+
terminal control characters.
|
|
791
|
+
|
|
792
|
+
History is one small JSON file per attempt in the per-user veo cache's `history`
|
|
793
|
+
directory, so parallel runs cannot overwrite each other and each record stays small. The
|
|
794
|
+
directory keeps one file per attempt and contains URLs, titles and local file paths;
|
|
795
|
+
delete it to remove those records. `veo flush` keeps the list (only `veo flush --stats`
|
|
796
|
+
resets statistics, not history).
|
|
797
|
+
|
|
798
|
+
### `veo changes`
|
|
799
|
+
|
|
800
|
+
Lists every **released version**, newest first, and marks the installed one. `veo changelog`
|
|
801
|
+
is an alias. The notes are parsed from the `CHANGELOG.md` that ships inside the package, so
|
|
802
|
+
they always belong to the installed code and the command needs no network access.
|
|
803
|
+
|
|
804
|
+
```bash
|
|
805
|
+
veo changes # all versions with their Added/Changed/Fixed counts
|
|
806
|
+
veo changes 1.10.1 # the notes of one release
|
|
807
|
+
veo changes --version 1.10.1 # the same, spelled out
|
|
808
|
+
veo changes 1.10 # newest release starting with 1.10
|
|
809
|
+
veo changes --latest # only the newest release
|
|
810
|
+
veo changes --since 1.10.0 # everything newer than 1.10.0, up to the newest release
|
|
811
|
+
veo changes --range 1.9.0..1.11.0 # a closed range, newest first
|
|
812
|
+
veo changes --json # machine-readable
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
An unknown version fails with the known versions listed. Long entries wrap to the terminal
|
|
816
|
+
width, and `--json` returns the complete text. Because the list already names the released
|
|
817
|
+
versions, `veo changes` prints no automatic update hint.
|
|
818
|
+
|
|
819
|
+
`veo changes --json` prints `{"current":…,"count":N,"versions":[…]}`, where each entry has
|
|
820
|
+
`version`, `date` (currently `null`, since the changelog headings carry no date), `installed`,
|
|
821
|
+
`counts` and `summary`. One version adds `"version"`, `"installed"` and `"sections"`; a range
|
|
822
|
+
adds `"from"` and `"to"` and keeps the per-release `sections`. Sections are
|
|
823
|
+
`{"type":"Added","items":[{"text":"…","items":[…]}]}`, and nested items are preserved.
|
|
824
|
+
|
|
825
|
+
### `veo runs` and `veo stop`
|
|
826
|
+
|
|
827
|
+
Every run registers itself while it works, under a **6-character id**, and removes that
|
|
828
|
+
record when it ends:
|
|
829
|
+
|
|
830
|
+
```bash
|
|
831
|
+
veo runs # active runs: id, PID, state, start time, progress, output directory
|
|
832
|
+
veo runs k3f9qa # one run in detail: URLs, settings, job file, per-item state
|
|
833
|
+
veo stop k3f9qa # ask that run to stop and wait until it exits
|
|
834
|
+
veo stop # stop every active run
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
`veo runs` lists the runs of this user, including those started in another terminal, and a
|
|
838
|
+
run disappears from the list as soon as it finishes. Progress such as
|
|
839
|
+
`1/3 done, 1 running` is read from the run's job file, which is created before the first
|
|
840
|
+
download starts, so a run that is still preparing the backend shows `starting`. `veo stop
|
|
841
|
+
<id>` writes a stop request that the run itself polls, so it needs no signals or PIDs and
|
|
842
|
+
works the same on every platform. A stopped run exits like Ctrl+C (`130`) and keeps its
|
|
843
|
+
partial data and retry job, so the printed `veo --retry-failed` command still works —
|
|
844
|
+
unlike `veo flush`, which also removes that data. If a run does not stop within 15 seconds,
|
|
845
|
+
`veo stop` reports it and exits with `1`.
|
|
846
|
+
|
|
847
|
+
A run that crashed without cleaning up leaves its record behind: `veo runs` marks it
|
|
848
|
+
`stale` and `veo stop` removes it, with or without its id. Records contain the id, process
|
|
849
|
+
id, start time, URLs, output directory and job path — never cookie files, browser sessions
|
|
850
|
+
or other credentials. Unknown or damaged record files are ignored instead of breaking veo,
|
|
851
|
+
because a single stray file in the cache must never stop later runs.
|
|
852
|
+
|
|
853
|
+
### `veo doctor`
|
|
854
|
+
|
|
855
|
+
Prints one line per check: `ok`, `warn` or `fail`. It inspects the JavaScript runtime used by
|
|
856
|
+
yt-dlp, the platform, the
|
|
857
|
+
output directory, the backend cache, yt-dlp (including the SHA-256 of the cached binary and
|
|
858
|
+
the version it reports), FFmpeg/FFprobe, a system FFmpeg fallback, the config file, leftover
|
|
859
|
+
partial downloads, stale duplicate-detection records, the npm registry and the yt-dlp release host. It downloads no backend and
|
|
860
|
+
only creates its own probe files plus the backend cache directory. Exit status is `1` when
|
|
861
|
+
at least one check fails.
|
|
862
|
+
|
|
863
|
+
Run `veo doctor fix` to restore missing or damaged managed tools and check again.
|
|
864
|
+
It stages bundled FFmpeg/FFprobe and downloads verified yt-dlp when needed. Missing
|
|
865
|
+
desktop media tools are downloaded into veo's cache from the pinned media releases and
|
|
866
|
+
verified before use. On Termux it installs missing native tools with the package manager.
|
|
867
|
+
With `--offline`, it only uses local binaries; missing tools are reported for an online retry.
|
|
868
|
+
Use `-o PATH` to create and check an output directory. Config errors and invalid overrides
|
|
869
|
+
are reported for manual correction; PATH and config values are never rewritten.
|
|
870
|
+
A missing system FFmpeg is not a warning when the selected media tools work.
|
|
871
|
+
|
|
872
|
+
## Supported sites and backend
|
|
873
|
+
|
|
874
|
+
YouTube, X/Twitter, TikTok, Vimeo, Reddit, Instagram, and [many other yt-dlp sites](https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md) are supported **when publicly accessible and technically available**. Support changes with websites, regions, rate limits, and backend versions; it is not a guarantee that every URL will work.
|
|
875
|
+
|
|
876
|
+
Official standalone yt-dlp is acquired on first download and cached outside the package directory; help, version and plain doctor never download the backend. The release is pinned and SHA-256 verified against hashes shipped with this package. The npm package runs no installation scripts; its only dependencies are the optional per-platform packages that carry the veo binary.
|
|
877
|
+
|
|
878
|
+
When no trusted local FFmpeg/FFprobe pair is available, veo downloads both tools directly from the upstream [ffmpeg-static binary releases](https://github.com/eugeneware/ffmpeg-static/releases/tag/b6.1.1). Release URLs, compressed and executable SHA-256 hashes, and byte counts are pinned in the package. The complete pair and its license and README must pass verification before either executable is started. Later uses verify the cached pair again; legacy or damaged cached binaries are not accepted merely because they are executable. Most targets use FFmpeg 6.1.1; Windows ia32 uses the last available pair, FFmpeg 6.0. Old `FFMPEG_BINARIES_URL`, `FFMPEG_BINARY_RELEASE` and `FFMPEG_BIN` variables do not change these downloads. Use `VEO_FFMPEG_PATH` to choose a trusted installed pair explicitly.
|
|
879
|
+
|
|
880
|
+
The downloaded binaries retain their separate upstream licenses. `FFmpeg.LICENSE` and `FFmpeg.README` are saved next to the cached tools, including upstream source and build information. veo itself is MIT licensed. No Python installation is needed on supported standalone platforms.
|
|
881
|
+
|
|
882
|
+
An installed Node.js, Deno or Bun (found on PATH, in that order) is passed to yt-dlp as its JavaScript runtime for YouTube; `VEO_JS_RUNTIME=deno:/path/to/deno` selects one explicitly. Without one, yt-dlp uses its own default. Local yt-dlp configuration and plugins are disabled for predictable execution. Arguments are passed without a shell.
|
|
883
|
+
|
|
884
|
+
Windows ARM64 uses an FFmpeg/FFprobe pair found on `PATH`, including the usual
|
|
885
|
+
WinGet, Chocolatey and `C:\ffmpeg\bin` locations, or automatically downloads x64
|
|
886
|
+
media tools for Windows 11's x64 emulation.
|
|
887
|
+
|
|
888
|
+
### Android / Termux
|
|
889
|
+
|
|
890
|
+
With npm installed in Termux (`pkg install nodejs`), npm fetches the native
|
|
891
|
+
Android binary:
|
|
892
|
+
|
|
893
|
+
```sh
|
|
894
|
+
npm install -g veodl
|
|
895
|
+
veo "URL"
|
|
896
|
+
```
|
|
897
|
+
|
|
898
|
+
On Android, veo automatically finds `yt-dlp`, `ffmpeg` and `ffprobe` on PATH
|
|
899
|
+
(also checking `$PREFIX/bin`). If tools or the `yt-dlp-ejs` Python module are
|
|
900
|
+
missing, it runs `pkg install -y python-yt-dlp yt-dlp-ejs ffmpeg` automatically,
|
|
901
|
+
then checks the installed programs before continuing the download. Python is
|
|
902
|
+
installed as a dependency. Termux with the pacman package manager uses
|
|
903
|
+
`--noconfirm` instead. This needs a working Termux repository and internet access.
|
|
904
|
+
No root access is needed. Later runs reuse the installed tools.
|
|
905
|
+
|
|
906
|
+
The npm installation does not pull in desktop FFmpeg packages.
|
|
907
|
+
The system yt-dlp is maintained by Termux and is
|
|
908
|
+
not pinned or hash-verified by veo. Explicit `VEO_YT_DLP_PATH` and
|
|
909
|
+
`VEO_FFMPEG_PATH` overrides still take precedence.
|
|
910
|
+
|
|
911
|
+
`veo doctor fix` also performs this automatic setup; `veo doctor fix --offline`
|
|
912
|
+
never invokes a package manager. Update Termux packages with `pkg upgrade`;
|
|
913
|
+
`veo backend update` prints this platform's update instructions.
|
|
914
|
+
|
|
915
|
+
To save files in Android's shared Downloads folder, run `termux-setup-storage`,
|
|
916
|
+
grant the storage permission, then use `veo "URL" -o ~/storage/downloads`.
|
|
917
|
+
Keep veo and its tools in Termux's private storage.
|
|
918
|
+
|
|
919
|
+
For existing published veo 1.6.1 installations (before this automatic setup), run:
|
|
920
|
+
|
|
921
|
+
```sh
|
|
922
|
+
pkg install python-yt-dlp yt-dlp-ejs ffmpeg
|
|
923
|
+
export VEO_YT_DLP_PATH="$(command -v yt-dlp)"
|
|
924
|
+
export VEO_FFMPEG_PATH="$PREFIX/bin"
|
|
925
|
+
veo doctor
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
These exports apply to the current shell; add them to your shell startup file
|
|
929
|
+
if you need them on subsequent launches of 1.6.1.
|
|
930
|
+
|
|
931
|
+
### Advanced overrides
|
|
932
|
+
|
|
933
|
+
- `VEO_YT_DLP_PATH`: absolute path to a trusted, current yt-dlp executable. It always takes
|
|
934
|
+
precedence over the managed backend, including one installed by `veo backend update`.
|
|
935
|
+
- `VEO_FFMPEG_PATH`: directory containing both `ffmpeg` and `ffprobe` executables (with
|
|
936
|
+
`.exe` on Windows).
|
|
937
|
+
- `VEO_CONFIG`: path to the config file.
|
|
938
|
+
- `VEO_JS_RUNTIME`: `name:path` of the JavaScript runtime passed to yt-dlp, for example
|
|
939
|
+
`deno:/usr/local/bin/deno` (`node`, `deno`, `bun` or `quickjs`).
|
|
940
|
+
- `VEO_BINARY`: path to a veo executable the npm launcher should start instead of the
|
|
941
|
+
installed platform package (for testing a local build).
|
|
942
|
+
|
|
943
|
+
Automatic setup covers Windows x64/ia32/ARM64, macOS x64/ARM64, Linux x64/ARM64,
|
|
944
|
+
and Android through Termux. Windows ARM64 media tools require x64 emulation.
|
|
945
|
+
`--open` uses `termux-open` in Termux; another Android app must be available to view the file.
|
|
946
|
+
Other systems should supply trusted native binaries. Internet
|
|
947
|
+
access, executable private storage and working OS libraries are prerequisites;
|
|
948
|
+
network blocks or unavailable repositories can still prevent setup. Android's
|
|
949
|
+
shared-storage permission must be granted by the user. Maintainers should update
|
|
950
|
+
the pinned yt-dlp release and hashes as websites change,
|
|
951
|
+
or users can install a newer release themselves.
|
|
952
|
+
|
|
953
|
+
### Installing a newer backend
|
|
954
|
+
|
|
955
|
+
```bash
|
|
956
|
+
veo backend update --check # is a newer yt-dlp release available?
|
|
957
|
+
veo backend update # install it
|
|
958
|
+
veo backend reset # forget it, use the pinned release again
|
|
959
|
+
```
|
|
960
|
+
|
|
961
|
+
The pinned backend is hash-verified against values compiled into this veo version. That
|
|
962
|
+
guarantee cannot cover a release that did not exist when this version was built, so
|
|
963
|
+
`veo backend update` verifies the download against the `SHA2-256SUMS` file published with
|
|
964
|
+
that release over HTTPS: the trust anchor becomes HTTPS and GitHub instead of the npm
|
|
965
|
+
package. It is opt-in, it says so on stderr when it runs, and `veo backend reset` (plus the
|
|
966
|
+
next `veo update`) returns to the pinned release. An installed release is used only while it
|
|
967
|
+
is newer than the pinned one and its bytes still match the recorded hash; anything else
|
|
968
|
+
silently falls back to the pinned release.
|
|
969
|
+
|
|
970
|
+
## Develop and publish
|
|
971
|
+
|
|
972
|
+
veo is a Rust crate (Rust 1.85+). The npm package `veodl` contains only a small launcher
|
|
973
|
+
(`bin/veo.js`); the binaries ship in `veodl-<platform>-<arch>` packages generated from
|
|
974
|
+
`Cargo.toml` by `scripts/npm-packages.mjs`.
|
|
975
|
+
|
|
976
|
+
```bash
|
|
977
|
+
cargo build --release # target/release/veo
|
|
978
|
+
cargo test # unit tests and offline CLI tests, no network
|
|
979
|
+
cargo test --test smoke -- --ignored # real downloads: local HTTP server, real yt-dlp, real FFmpeg
|
|
980
|
+
cargo clippy --all-targets -- -D warnings
|
|
981
|
+
node scripts/npm-packages.mjs # sync npm package versions after a version bump
|
|
982
|
+
npm pack && node scripts/check-package.js
|
|
983
|
+
```
|
|
984
|
+
|
|
985
|
+
The offline tests (`tests/cli.rs`) run the real binary against `tests/fake-backend`, a
|
|
986
|
+
small stand-in for yt-dlp, ffmpeg and ffprobe, in isolated cache and config directories.
|
|
987
|
+
They cover downloads, duplicate names, skip-existing, playlists and entry selection,
|
|
988
|
+
audio, subtitles, naming templates, dry runs and listings, incognito mode, retries by run
|
|
989
|
+
ID, transient-failure back-off, profiles and release notes.
|
|
990
|
+
|
|
991
|
+
The smoke test prepares the pinned tools with `veo doctor fix`, generates a two-second
|
|
992
|
+
synthetic video with FFmpeg, serves it on loopback and runs real yt-dlp downloads. It checks
|
|
993
|
+
default output, the quality cap, duplicate names, audio extraction, conversion, remuxing,
|
|
994
|
+
dry-run, format listing, JSON output, audio inspection, batch failures, profiles with URL
|
|
995
|
+
lists, retry by run ID from another directory, playlist selection, and that a finished
|
|
996
|
+
download whose destination was unavailable is transferred later without contacting the
|
|
997
|
+
source again. It downloads no third-party video.
|
|
998
|
+
|
|
999
|
+
Continuous integration runs formatting, Clippy, the unit and offline tests, and the smoke
|
|
1000
|
+
test on Windows, macOS and Linux, and verifies the npm package. Pushing a tag `vX.Y.Z`
|
|
1001
|
+
(matching `Cargo.toml`) builds the binaries for Windows x64/ARM64, macOS x64/ARM64,
|
|
1002
|
+
static Linux x64/ARM64 (musl) and Android ARM64 and uploads the eight npm tarballs
|
|
1003
|
+
as an Actions artifact. The `rust-port` branch also triggers this build.
|
|
1004
|
+
|
|
1005
|
+
GitHub builds all seven native targets and bundles them into the single veodl npm
|
|
1006
|
+
package. Branch pushes and manual workflow runs build and upload the npm-package
|
|
1007
|
+
artifact without publishing. Pushing a matching version tag (for example,
|
|
1008
|
+
v2.0.1) additionally publishes the verified tarball using npm trusted publishing
|
|
1009
|
+
with OIDC. Configure Mailo037/veodl and release.yml as the npm trusted publisher,
|
|
1010
|
+
with direct npm publishing allowed; no npm token or GitHub environment is needed.
|
|
1011
|
+
The publish job alone has id-token: write permission and uses Node 24 and npm 11.
|
|
1012
|
+
|
|
1013
|
+
After committing and pushing the intended release changes, create and push the tag:
|
|
1014
|
+
|
|
1015
|
+
```sh
|
|
1016
|
+
git tag -a v2.0.1 -m "Release v2.0.1"
|
|
1017
|
+
git push origin v2.0.1
|
|
1018
|
+
```
|
|
1019
|
+
|
|
1020
|
+
Wait for the complete workflow, including the publish job, and check npm's latest
|
|
1021
|
+
tag before announcing the release. An already published version cannot be reused.
|
|
1022
|
+
For a local fallback, download the npm-package artifact and publish its verified
|
|
1023
|
+
tarball with npm publish; users always install with npm install -g veodl.
|
|
1024
|
+
|
|
1025
|
+
Modules mirror the commands and stay small (larger ones are directories of focused
|
|
1026
|
+
submodules): argument parsing and dispatch (`src/cli/`), configuration (`src/config*.rs`,
|
|
1027
|
+
`src/config_editor/`), backend setup and updates (`src/backend/`, `src/tool_setup.rs`,
|
|
1028
|
+
`src/backend_update.rs`), downloads (`src/downloader/`, `src/download_cache.rs`,
|
|
1029
|
+
`src/jobs/`, `src/playlist.rs`), records (`src/runs/`, `src/history.rs`, `src/stats.rs`,
|
|
1030
|
+
`src/run_archive.rs`, `src/flush.rs`), diagnostics (`src/doctor.rs`,
|
|
1031
|
+
`src/inspect_media.rs`), source discovery over the Chrome DevTools Protocol
|
|
1032
|
+
(`src/source_discovery/`), terminal output (`src/output.rs`, `src/progress/`,
|
|
1033
|
+
`src/terminal.rs`) and helpers.
|
|
1034
|
+
|
|
1035
|
+
## License
|
|
1036
|
+
|
|
1037
|
+
MIT for this CLI. yt-dlp and FFmpeg/FFprobe retain their respective upstream licenses.
|
|
1038
|
+
# Clickable paths
|
|
1039
|
+
|
|
1040
|
+
In supported terminals (Windows Terminal, iTerm2, WezTerm, Kitty, VS Code and recent VTE terminals), the `Saved:` path, `veo config path` and the config editor's header link to the containing folder. Use the terminal's link gesture, usually Ctrl+click or Cmd+click. The terminal and operating system decide whether file links open the file manager; unsupported terminals and redirected output show plain paths. Missing paths are not linked. JSON output remains plain.
|