veodl 1.12.0 → 2.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.
Files changed (58) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +183 -100
  3. package/bin/veo.js +47 -2
  4. package/docs/AGENT_GUIDE.md +1 -0
  5. package/native/android-arm64/veo +0 -0
  6. package/native/darwin-arm64/veo +0 -0
  7. package/native/darwin-x64/veo +0 -0
  8. package/native/linux-arm64/veo +0 -0
  9. package/native/linux-x64/veo +0 -0
  10. package/native/win32-arm64/veo.exe +0 -0
  11. package/native/win32-x64/veo.exe +0 -0
  12. package/package.json +53 -61
  13. package/src/alias.js +0 -258
  14. package/src/backend-update.js +0 -191
  15. package/src/backend.js +0 -548
  16. package/src/changes.js +0 -278
  17. package/src/cli.js +0 -781
  18. package/src/compatibility.js +0 -39
  19. package/src/config-clipboard.js +0 -67
  20. package/src/config-diagnostics.js +0 -155
  21. package/src/config-editor.js +0 -404
  22. package/src/config-errors.js +0 -64
  23. package/src/config-reset.js +0 -39
  24. package/src/config-template.js +0 -227
  25. package/src/config.js +0 -307
  26. package/src/disk-space.js +0 -68
  27. package/src/doctor.js +0 -302
  28. package/src/download-cache.js +0 -31
  29. package/src/downloader.js +0 -669
  30. package/src/execution.js +0 -68
  31. package/src/experimental-fragments.js +0 -29
  32. package/src/flush.js +0 -66
  33. package/src/history.js +0 -173
  34. package/src/inline-region.js +0 -72
  35. package/src/inspect-media.js +0 -179
  36. package/src/interactive.js +0 -120
  37. package/src/jobs.js +0 -218
  38. package/src/legacy-config-comments.js +0 -106
  39. package/src/naming.js +0 -54
  40. package/src/open-file.js +0 -15
  41. package/src/option-suggestions.js +0 -43
  42. package/src/output.js +0 -81
  43. package/src/path-links.js +0 -53
  44. package/src/paths.js +0 -26
  45. package/src/playlist.js +0 -31
  46. package/src/progress.js +0 -341
  47. package/src/run-archive.js +0 -148
  48. package/src/runs.js +0 -346
  49. package/src/source-discovery.js +0 -303
  50. package/src/state.js +0 -27
  51. package/src/stats.js +0 -63
  52. package/src/terminal-size.js +0 -8
  53. package/src/terminal-title.js +0 -19
  54. package/src/tool-setup.js +0 -151
  55. package/src/uninstall.js +0 -222
  56. package/src/updater.js +0 -229
  57. package/src/utils.js +0 -208
  58. package/src/version.js +0 -38
package/CHANGELOG.md CHANGED
@@ -2,6 +2,33 @@
2
2
 
3
3
  All notable changes to veo. This project follows [Semantic Versioning](https://semver.org/).
4
4
 
5
+ ## 2.0.0
6
+
7
+ ### Changed
8
+
9
+ - **Native Rust binary**: veo is rewritten in Rust and ships as a single native executable per platform. Node.js is no longer required to run veo; `npm install -g veodl` keeps working and installs the matching prebuilt binary from the single veodl package. Commands, flags, JSON output, config files, profiles, run records, history, statistics and retry jobs stay compatible, including resumable staging directories of 1.x.
10
+ - Startup is about ten times faster, and SHA-256 checks of yt-dlp, FFmpeg and FFprobe run in parallel with hardware acceleration, so every run still verifies the managed tools before use.
11
+ - A single-URL download reuses the metadata read while checking the page, so the backend starts once instead of twice per URL. Dry runs, quality and subtitle listings benefit the same way.
12
+ - First-use FFmpeg/FFprobe setup downloads both tools in parallel and publishes them by rename instead of copying them again.
13
+ - yt-dlp receives an installed Node.js, Deno or Bun as JavaScript runtime for YouTube challenges; `VEO_JS_RUNTIME=name:path` selects one explicitly. `veo doctor` reports the runtime instead of the Node.js version.
14
+ - Cancelling a download stops yt-dlp together with the FFmpeg processes it started.
15
+
16
+ ### Removed
17
+
18
+ - Unused compatibility code for configuration comments of the former German template.
19
+
20
+ ## 1.12.1
21
+
22
+ ### Fixed
23
+
24
+ - Remove the optional FFmpeg npm dependency tree and its installation scripts.
25
+ - Download desktop FFmpeg and FFprobe from fixed upstream releases and verify compressed and executable SHA-256 hashes before either program runs. Preserve upstream license and build information alongside the tools.
26
+ - Verify managed media caches on reuse and reject legacy, corrupt or symlinked binaries. Preserve trusted system tools and explicit overrides.
27
+ - Prevent rejected managed-cache binaries from being accepted again through PATH or a symlink alias; continue searching for external system tools.
28
+ - Keep Smolish cookie environment variables out of media-tool probe processes.
29
+ - Retry completed local transfers without contacting the original source, including selected-source retries, while retaining cache expiry and path validation.
30
+ - Allow up to 30 seconds for Chromium's debugging connection on cold starts, while retaining the source scan's overall deadline and cancellation.
31
+
5
32
  ## 1.12.0
6
33
 
7
34
  ### Added
package/README.md CHANGED
@@ -8,9 +8,12 @@ Automating with an agent? Start with the [agent guide](docs/AGENT_GUIDE.md) for
8
8
 
9
9
  ## Install and run
10
10
 
11
- Requires **Node.js 22+** and npm. Internet access is needed for installation and first-use backend setup.
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.
12
13
 
13
- The npm package is `veodl`; the installed commands are `veo` and `veodl`.
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.
14
17
 
15
18
  ```bash
16
19
  npx veodl "https://example.com/video.mp4"
@@ -30,16 +33,22 @@ JavaScript support with `pkg install -y`. On desktop systems, missing media tool
30
33
  are downloaded into veo's own cache. Run `veo doctor fix` to prepare everything
31
34
  before downloading. Plain `veo doctor`, help and version do not install tools.
32
35
 
33
- From this checkout, without publishing:
36
+ Without npm, download the binary for your platform from the GitHub releases page, or
37
+ build it with Rust 1.85+:
34
38
 
35
39
  ```bash
36
- npm install
37
- node bin/veo.js --help
38
- npm link
39
- veo "https://example.com/video.mp4"
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
40
49
  ```
41
50
 
42
- `package.json` maps `"veo": "./bin/veo.js"`; npm creates the executable/shim automatically. No custom command prefix is needed. Use only trusted URLs, and quote URLs to protect query strings from your shell.
51
+ Use only trusted URLs, and quote URLs to protect query strings from your shell.
43
52
 
44
53
  If something does not work, run `veo doctor` first: it inspects the whole local setup and prints one line per check.
45
54
 
@@ -54,50 +63,109 @@ regular command arguments; veo never starts a prompt in a script.
54
63
  ## Usage
55
64
 
56
65
  ```text
57
- veo <url> [<url>...] [options]
58
-
59
- Options:
60
- -q, --quality <quality> best, 2160p, 1440p, 1080p, 720p, 480p, 360p
61
- -o, --output <path> Output directory (default: current working directory)
62
- -r, --rename <name> Filename without extension; * inserts the original title
63
- --closest-quality Nearest available resolution instead of an upper bound
64
- --open Open the saved file with your default app
65
- --audio Audio only (MP3 by default)
66
- --format <format> Video: mp4, mkv, webm, mov
67
- Audio: mp3, m4a, aac, opus, flac, wav
68
- --recode Explicit video conversion (requires --format)
69
- --playlist-concurrency <n> Parallel playlist entries, 1-4 (default: 2)
70
- --playlist Download every entry of a playlist or channel URL
71
- -N, --concurrent-fragments <n> Parallel fragments, 1-64 (default: 8; 17-64 experimental)
72
- --experimental-fragments Explicitly accept experimental values above 16
73
- --subs Download subtitles (default languages: en)
74
- --auto-subs Include automatically generated subtitles
75
- --sub-langs <langs> Subtitle languages, e.g. "de,en" (manual unless --auto-subs)
76
- --sub-format <format> Prefer subtitle formats, e.g. srt/vtt/best
77
- --list-subs Show manual and automatic subtitle availability
78
- --embed-subs Embed subtitles into the video file
79
- --embed-metadata Embed title, date and other metadata
80
- --embed-thumbnail Embed the thumbnail
81
- --sponsorblock-remove <categories> e.g. "sponsor,selfpromo"
82
- --section <range> Only a time range, e.g. "*10:00-12:00"
83
- --cookies <file> Netscape cookie file, for content you may access
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
84
131
  --cookies-from-browser <browser[:profile]>
85
- --resume Keep partial data and continue an interrupted download
86
- --incognito Save media without run ID, history, stats or retry data
87
- --neutral-filename Optional random filename instead of title and templates
88
- --list-qualities Show available video resolutions and exit
89
- --list-formats Show available formats and exit
90
- --dry-run Show what would be downloaded and exit
91
- --verify Probe saved media files with FFprobe (default: off)
92
- --json One JSON object per URL instead of prose
93
- --profile <name> Use a named profile from the config file
94
- --batch-file <file> Read one URL per line (blank lines and # comments ignored)
95
- --retry-failed <id|file> Retry failed/unfinished downloads by run ID or job file
96
- --playlist-items <list> Select entries, e.g. 1,3-5 (implies --playlist)
97
- --skip-existing Skip matching downloads that are still on disk
98
- --no-<boolean-option> Disable a default, e.g. --no-open or --no-audio
99
- -v, --version Show installed version (also: veo version)
100
- -h, --help Show help
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
101
169
  ```
102
170
 
103
171
  ```bash
@@ -224,7 +292,7 @@ example through `veo config edit`. Enable it with `veo URL --profile kompatibel`
224
292
  `"profiles": { "default": { "color": true }, "plain": { "color": false } }`.
225
293
  Use `veo stats --profile plain` or `veo URL --profile plain`; `--color` or
226
294
  `--no-color` overrides the profile for one invocation (except `NO_COLOR`).
227
- External npm/editor output and Node runtime warnings keep their own formatting.
295
+ External npm and editor output keeps its own formatting.
228
296
 
229
297
  ### Filename templates and folders
230
298
 
@@ -750,7 +818,8 @@ because a single stray file in the cache must never stop later runs.
750
818
 
751
819
  ### `veo doctor`
752
820
 
753
- Prints one line per check: `ok`, `warn` or `fail`. It inspects Node.js, the platform, the
821
+ Prints one line per check: `ok`, `warn` or `fail`. It inspects the JavaScript runtime used by
822
+ yt-dlp, the platform, the
754
823
  output directory, the backend cache, yt-dlp (including the SHA-256 of the cached binary and
755
824
  the version it reports), FFmpeg/FFprobe, a system FFmpeg fallback, the config file, leftover
756
825
  partial downloads, stale duplicate-detection records, the npm registry and the yt-dlp release host. It downloads no backend and
@@ -759,8 +828,8 @@ at least one check fails.
759
828
 
760
829
  Run `veo doctor fix` to restore missing or damaged managed tools and check again.
761
830
  It stages bundled FFmpeg/FFprobe and downloads verified yt-dlp when needed. Missing
762
- desktop media tools are installed in veo's cache using npm and the pinned media
763
- packages. On Termux it installs missing native tools with the package manager.
831
+ desktop media tools are downloaded into veo's cache from the pinned media releases and
832
+ verified before use. On Termux it installs missing native tools with the package manager.
764
833
  With `--offline`, it only uses local binaries; missing tools are reported for an online retry.
765
834
  Use `-o PATH` to create and check an output directory. Config errors and invalid overrides
766
835
  are reported for manual correction; PATH and config values are never rewritten.
@@ -770,18 +839,22 @@ A missing system FFmpeg is not a warning when the selected media tools work.
770
839
 
771
840
  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.
772
841
 
773
- 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. FFmpeg and FFprobe are normally supplied by the optional `ffmpeg-static` and `ffprobe-static` dependencies during npm installation. If these are absent and no local pair is available, veo installs `ffmpeg-static@5.3.0` and a platform-specific `@ffprobe-installer` package in a temporary cache project, checks that both programs run, and saves them in its backend cache. Media packages use npm/upstream HTTPS distribution, not the yt-dlp pinned-hash guarantee. These binaries have their own licenses; see their upstream packages. No Python installation is needed on supported standalone platforms.
842
+ 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.
843
+
844
+ 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.
774
845
 
775
- The existing Node executable is explicitly enabled as yt-dlp's JavaScript runtime for YouTube. Local yt-dlp configuration and plugins are disabled for predictable execution. Arguments are passed without a shell.
846
+ 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.
776
847
 
777
- `ffmpeg-static` and `ffprobe-static` publish no Windows ARM64 binaries. veo no longer refuses
778
- that platform: it uses an FFmpeg/FFprobe pair found on `PATH`, including the usual
848
+ 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.
849
+
850
+ Windows ARM64 uses an FFmpeg/FFprobe pair found on `PATH`, including the usual
779
851
  WinGet, Chocolatey and `C:\ffmpeg\bin` locations, or automatically downloads x64
780
852
  media tools for Windows 11's x64 emulation.
781
853
 
782
854
  ### Android / Termux
783
855
 
784
- With Node.js 22+ and npm already installed in Termux:
856
+ With npm installed in Termux (`pkg install nodejs`), npm fetches the native
857
+ Android binary:
785
858
 
786
859
  ```sh
787
860
  npm install -g veodl
@@ -796,8 +869,7 @@ installed as a dependency. Termux with the pacman package manager uses
796
869
  `--noconfirm` instead. This needs a working Termux repository and internet access.
797
870
  No root access is needed. Later runs reuse the installed tools.
798
871
 
799
- Static FFmpeg dependencies are optional; `--omit=optional` can be added to the
800
- npm install command to skip attempting those desktop packages entirely.
872
+ The npm installation does not pull in desktop FFmpeg packages.
801
873
  The system yt-dlp is maintained by Termux and is
802
874
  not pinned or hash-verified by veo. Explicit `VEO_YT_DLP_PATH` and
803
875
  `VEO_FFMPEG_PATH` overrides still take precedence.
@@ -829,11 +901,15 @@ if you need them on subsequent launches of 1.6.1.
829
901
  - `VEO_FFMPEG_PATH`: directory containing both `ffmpeg` and `ffprobe` executables (with
830
902
  `.exe` on Windows).
831
903
  - `VEO_CONFIG`: path to the config file.
904
+ - `VEO_JS_RUNTIME`: `name:path` of the JavaScript runtime passed to yt-dlp, for example
905
+ `deno:/usr/local/bin/deno` (`node`, `deno`, `bun` or `quickjs`).
906
+ - `VEO_BINARY`: path to a veo executable the npm launcher should start instead of the
907
+ installed platform package (for testing a local build).
832
908
 
833
909
  Automatic setup covers Windows x64/ia32/ARM64, macOS x64/ARM64, Linux x64/ARM64,
834
910
  and Android through Termux. Windows ARM64 media tools require x64 emulation.
835
911
  `--open` uses `termux-open` in Termux; another Android app must be available to view the file.
836
- Other systems should supply trusted native binaries. Node.js 22+, npm, internet
912
+ Other systems should supply trusted native binaries. Internet
837
913
  access, executable private storage and working OS libraries are prerequisites;
838
914
  network blocks or unavailable repositories can still prevent setup. Android's
839
915
  shared-storage permission must be granted by the user. Maintainers should update
@@ -859,46 +935,53 @@ silently falls back to the pinned release.
859
935
 
860
936
  ## Develop and publish
861
937
 
938
+ veo is a Rust crate (Rust 1.85+). The npm package `veodl` contains only a small launcher
939
+ (`bin/veo.js`); the binaries ship in `veodl-<platform>-<arch>` packages generated from
940
+ `Cargo.toml` by `scripts/npm-packages.mjs`.
941
+
862
942
  ```bash
863
- npm install
864
- npm test # unit tests, no network
865
- npm run test:smoke # real downloads: local HTTP server, real yt-dlp, real FFmpeg
866
- npm run test:open # real download plus a controlled desktop-opener replacement
867
- npm pack
868
- npm run check:package # inspect the packed tarball
869
- npm link
870
- veo --version
871
- # Then, authenticated as the account that owns the name:
872
- npm publish
943
+ cargo build --release # target/release/veo
944
+ cargo test # unit tests and offline CLI tests, no network
945
+ cargo test --test smoke -- --ignored # real downloads: local HTTP server, real yt-dlp, real FFmpeg
946
+ cargo clippy --all-targets -- -D warnings
947
+ node scripts/npm-packages.mjs # sync npm package versions after a version bump
948
+ npm pack && node scripts/check-package.js
873
949
  ```
874
950
 
875
- The smoke test generates a two-second synthetic video with FFmpeg, serves it on loopback,
876
- and runs real yt-dlp downloads. It checks default output, the quality cap, duplicate names,
877
- audio extraction, conversion, dry-run, format listing, JSON output, metadata embedding,
878
- resume, batch behaviour, playlist selection and nonzero failures, and verifies that a
879
- finished download whose destination was unavailable is retried from the local cache
880
- without contacting the source again. It also confirms that real runs leave `veo history`
881
- entries, that finished runs clean up their record, and that `veo runs`/`veo stop` report
882
- nothing left behind. It needs network access once for yt-dlp acquisition; it downloads no
883
- third-party video. Unit tests require no network.
884
-
885
- The published tarball only includes `bin/`, `src/`, package metadata, README and LICENSE.
886
- The lockfile is kept for reproducible development. There is no build step. npm makes the
887
- shebang-bearing bin executable on installation (on Unix, `chmod +x bin/veo.js` also enables
888
- direct checkout execution).
889
-
890
- Continuous integration runs the unit tests on Windows, macOS and Linux for Node 22 and 24,
891
- runs the end-to-end smoke test on Node 22, and verifies the packed tarball.
892
-
893
- Modules separate argument parsing (`src/cli.js`), configuration (`src/config.js`,
894
- `src/config-errors.js`, `src/config-template.js`), backend setup (`src/backend.js`),
895
- backend updates (`src/backend-update.js`), download orchestration (`src/downloader.js`,
896
- `src/download-cache.js`), retry jobs (`src/jobs.js`), playlists (`src/playlist.js`),
897
- statistics, download history, the run registry and cleanup (`src/stats.js`,
898
- `src/history.js`, `src/runs.js`, `src/flush.js`), diagnostics (`src/doctor.js`),
899
- progress (`src/progress.js`), and helpers (`src/utils.js`, `src/paths.js`,
900
- `src/state.js`, `src/version.js`) so new options and providers can be added without
901
- replacing the CLI.
951
+ The offline tests (`tests/cli.rs`) run the real binary against `tests/fake-backend`, a
952
+ small stand-in for yt-dlp, ffmpeg and ffprobe, in isolated cache and config directories.
953
+ They cover downloads, duplicate names, skip-existing, playlists and entry selection,
954
+ audio, subtitles, naming templates, dry runs and listings, incognito mode, retries by run
955
+ ID, transient-failure back-off, profiles and release notes.
956
+
957
+ The smoke test prepares the pinned tools with `veo doctor fix`, generates a two-second
958
+ synthetic video with FFmpeg, serves it on loopback and runs real yt-dlp downloads. It checks
959
+ default output, the quality cap, duplicate names, audio extraction, conversion, remuxing,
960
+ dry-run, format listing, JSON output, audio inspection, batch failures, profiles with URL
961
+ lists, retry by run ID from another directory, playlist selection, and that a finished
962
+ download whose destination was unavailable is transferred later without contacting the
963
+ source again. It downloads no third-party video.
964
+
965
+ Continuous integration runs formatting, Clippy, the unit and offline tests, and the smoke
966
+ test on Windows, macOS and Linux, and verifies the npm package. Pushing a tag `vX.Y.Z`
967
+ (matching `Cargo.toml`) builds the binaries for Windows x64/ARM64, macOS x64/ARM64,
968
+ static Linux x64/ARM64 (musl) and Android ARM64 and uploads the eight npm tarballs
969
+ as an Actions artifact. The `rust-port` branch also triggers this build.
970
+
971
+ GitHub builds all seven native targets and bundles them into the single veodl npm
972
+ package. No platform packages or npm credentials are needed on GitHub. Download
973
+ its npm-2.0.0 artifact and publish locally with npm run release. Users only need
974
+ npm install -g veodl; the launcher automatically selects the bundled binary.
975
+
976
+ Modules mirror the commands and stay small (larger ones are directories of focused
977
+ submodules): argument parsing and dispatch (`src/cli/`), configuration (`src/config*.rs`,
978
+ `src/config_editor/`), backend setup and updates (`src/backend/`, `src/tool_setup.rs`,
979
+ `src/backend_update.rs`), downloads (`src/downloader/`, `src/download_cache.rs`,
980
+ `src/jobs/`, `src/playlist.rs`), records (`src/runs/`, `src/history.rs`, `src/stats.rs`,
981
+ `src/run_archive.rs`, `src/flush.rs`), diagnostics (`src/doctor.rs`,
982
+ `src/inspect_media.rs`), source discovery over the Chrome DevTools Protocol
983
+ (`src/source_discovery/`), terminal output (`src/output.rs`, `src/progress/`,
984
+ `src/terminal.rs`) and helpers.
902
985
 
903
986
  ## License
904
987
 
package/bin/veo.js CHANGED
@@ -1,4 +1,49 @@
1
1
  #!/usr/bin/env node
2
- import { main } from '../src/cli.js';
2
+ // Starts the native veo binary that npm installed from the matching platform
3
+ // package (veodl-<platform>-<arch>). Exit codes and signals pass through.
4
+ import { spawn } from 'node:child_process';
5
+ import { existsSync } from 'node:fs';
6
+ import { fileURLToPath } from 'node:url';
7
+ import path from 'node:path';
3
8
 
4
- process.exitCode = await main();
9
+ const root = fileURLToPath(new URL('../', import.meta.url));
10
+ const target = `${process.platform}-${process.arch}`;
11
+ const executable = process.platform === 'win32' ? 'veo.exe' : 'veo';
12
+
13
+ function binaryPath() {
14
+ if (process.env.VEO_BINARY) return process.env.VEO_BINARY;
15
+ // Windows on ARM can run the x64 build through emulation.
16
+ const candidates = [target, ...(target === 'win32-arm64' ? ['win32-x64'] : [])];
17
+ for (const candidate of candidates) {
18
+ const file = path.join(root, 'native', candidate, executable);
19
+ if (existsSync(file)) return file;
20
+ }
21
+ return null;
22
+ }
23
+
24
+ const binary = binaryPath();
25
+ if (!binary) {
26
+ process.stderr.write(`veo: no prebuilt binary for ${target} is installed.\n`
27
+ + 'Reinstall with npm install -g veodl\n'
28
+ + 'Or build from source: cargo install --git https://github.com/Mailo037/veodl\n');
29
+ process.exit(1);
30
+ }
31
+
32
+ const child = spawn(binary, process.argv.slice(2), { stdio: 'inherit', windowsHide: false });
33
+ // The terminal already delivers Ctrl+C to veo itself; keep this launcher alive
34
+ // until veo has cleaned up, and forward termination requests sent only to it.
35
+ for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) {
36
+ process.on(signal, () => { if (signal !== 'SIGINT') child.kill(signal); });
37
+ }
38
+ child.on('error', error => {
39
+ process.stderr.write(`veo: could not start ${binary}: ${error.message}\n`);
40
+ process.exit(1);
41
+ });
42
+ child.on('close', (code, signal) => {
43
+ if (signal) {
44
+ process.removeAllListeners(signal);
45
+ process.kill(process.pid, signal);
46
+ return;
47
+ }
48
+ process.exit(code ?? 1);
49
+ });
@@ -116,6 +116,7 @@ The run record is stored in veo's per-user cache on the device that ran the down
116
116
  - Example profile: `"experimental": { "concurrentFragments": 32, "experimentalFragments": true }`. Run with `veo <URL> --profile experimental`; use `--no-experimental-fragments` to revoke a stored opt-in.
117
117
 
118
118
  - Run `veo doctor --offline` to check the local setup without network repair. `veo doctor fix` may install missing tools.
119
+ - Desktop media downloads use fixed release URLs and shipped SHA-256 hashes; both FFmpeg and FFprobe are verified before execution and on cache reuse. A rejected legacy cache requires `veo doctor fix`. Trusted PATH tools and `VEO_FFMPEG_PATH` remain explicit alternatives. The npm package runs no install scripts; it includes the native veo binaries and selects your platform automatically.
119
120
  - Use `--resume` for interrupted downloads and `--skip-existing` when repeated saves should be avoided.
120
121
  - `veo flush` removes temporary downloads and retry jobs; do not run it as routine maintenance in an agent workflow.
121
122
  - Do not call bare `veo` in an interactive terminal from automation: it opens a wizard. Use explicit URLs and flags.
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,61 +1,53 @@
1
- {
2
- "name": "veodl",
3
- "version": "1.12.0",
4
- "description": "A clean, simple video downloader powered by yt-dlp.",
5
- "type": "module",
6
- "bin": {
7
- "veo": "bin/veo.js",
8
- "veodl": "bin/veo.js"
9
- },
10
- "files": [
11
- "bin/",
12
- "src/",
13
- "docs/",
14
- "AGENTS.md",
15
- "README.md",
16
- "CHANGELOG.md",
17
- "LICENSE"
18
- ],
19
- "engines": {
20
- "node": ">=22"
21
- },
22
- "scripts": {
23
- "test": "node --test",
24
- "test:smoke": "node scripts/smoke.js",
25
- "test:open": "node scripts/smoke-open.js",
26
- "check:package": "node scripts/check-package.js",
27
- "prepublishOnly": "npm test",
28
- "test:workflows": "node scripts/smoke-workflows.js"
29
- },
30
- "keywords": [
31
- "cli",
32
- "video",
33
- "downloader",
34
- "yt-dlp",
35
- "audio",
36
- "youtube",
37
- "playlist",
38
- "subtitles"
39
- ],
40
- "license": "MIT",
41
- "author": "Mailo037",
42
- "repository": {
43
- "type": "git",
44
- "url": "git+https://github.com/Mailo037/veodl.git"
45
- },
46
- "bugs": {
47
- "url": "https://github.com/Mailo037/veodl/issues"
48
- },
49
- "homepage": "https://github.com/Mailo037/veodl#readme",
50
- "preferGlobal": true,
51
- "publishConfig": {
52
- "access": "public"
53
- },
54
- "optionalDependencies": {
55
- "ffmpeg-static": "5.3.0",
56
- "ffprobe-static": "3.1.0"
57
- },
58
- "devDependencies": {
59
- "@xterm/headless": "6.0.0"
60
- }
61
- }
1
+ {
2
+ "name": "veodl",
3
+ "version": "2.0.0",
4
+ "description": "A clean, simple video downloader powered by yt-dlp. Native binary; no Node.js needed at runtime.",
5
+ "type": "module",
6
+ "bin": {
7
+ "veo": "bin/veo.js",
8
+ "veodl": "bin/veo.js"
9
+ },
10
+ "files": [
11
+ "bin/",
12
+ "docs/",
13
+ "AGENTS.md",
14
+ "README.md",
15
+ "CHANGELOG.md",
16
+ "LICENSE",
17
+ "native/"
18
+ ],
19
+ "engines": {
20
+ "node": ">=16"
21
+ },
22
+ "scripts": {
23
+ "test": "cargo test",
24
+ "build": "cargo build --release",
25
+ "check:package": "node scripts/check-package.js",
26
+ "packages": "node scripts/npm-packages.mjs",
27
+ "release": "node scripts/release.mjs"
28
+ },
29
+ "keywords": [
30
+ "cli",
31
+ "video",
32
+ "downloader",
33
+ "yt-dlp",
34
+ "audio",
35
+ "youtube",
36
+ "playlist",
37
+ "subtitles"
38
+ ],
39
+ "license": "MIT",
40
+ "author": "Mailo037",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "git+https://github.com/Mailo037/veodl.git"
44
+ },
45
+ "bugs": {
46
+ "url": "https://github.com/Mailo037/veodl/issues"
47
+ },
48
+ "homepage": "https://github.com/Mailo037/veodl#readme",
49
+ "preferGlobal": true,
50
+ "publishConfig": {
51
+ "access": "public"
52
+ }
53
+ }