Download YouTube videos or playlists as MP3 files, optionally splitting recordings into named tracks.
Try it in your browser, no install. A sample playlist stands in for YouTube.
A Node.js/TypeScript CLI orchestrates yt-dlp and ffmpeg. No YouTube API key is needed.
Requires:
- Node.js 22+ and npm
- A current
yt-dlpinstallation with its EJS challenge solver ffmpeg, plusffprobefor splitting (usually installed together)
With resolute-backports enabled, install or update the current backported version:
sudo apt-get update
sudo apt-get install -t resolute-backports yt-dlp
/usr/bin/yt-dlp --versionA plain sudo apt install yt-dlp can keep an older version from the main release repository: backports have lower priority unless explicitly selected. The available 2026.08.19 backport includes the EJS solver and has been checked against a small audio sample from YouTube.
Use the backports repository matching your Ubuntu release; resolute-backports is specific to Ubuntu 26.04. Other distributions may offer different versions or backports instructions.
Switching from a uv installation: the CLI prefers ~/.local/bin/yt-dlp over /usr/bin/yt-dlp. After successfully upgrading and verifying the apt copy, remove the uv-managed copy to let the CLI use apt:
uv tool uninstall yt-dlpIf your distribution does not offer a recent enough version, install a current user-local yt-dlp, including the EJS solver, with uv:
uv tool install --upgrade "yt-dlp[default]"This command also updates an existing uv installation. Alternatively, use pipx:
pipx install "yt-dlp[default]"
# To update an existing pipx installation:
pipx upgrade yt-dlpOr use python3 -m pip install --user -U "yt-dlp[default]" if your Python environment permits user installs. The CLI prefers ~/.local/bin over system copies. Distribution packages such as apt can lag behind YouTube changes.
Install ffmpeg with your system package manager:
# macOS
brew install ffmpeg
# Ubuntu/Debian
sudo apt update && sudo apt install -y ffmpegThen, from this repository:
npm installThis installs the development dependencies and builds the CLI. There are no npm runtime dependencies. After editing TypeScript, rebuild with npm run build.
Install external tools separately. The CLI uses Node as yt-dlp's JavaScript runtime. See yt-dlp's EJS setup guide for other installation methods.
./bin/yt-download "YOUTUBE_PLAYLIST_OR_VIDEO_URL"
./bin/yt-download "URL" ~/Music/youtubeTo install the yt-download command from this checkout:
npm link
yt-download "URL"
yt-download --timestamp-split "URL"bin/yt-download is the executable Node entry point, registered in package.json's bin field. You can also run it with npm start -- "URL".
Downloads go to ./downloads relative to your working directory by default. Existing MP3s are skipped unless --force is supplied. With no URL, an interactive terminal prompts for one.
./bin/yt-download --timestamp-split "URL"
./bin/yt-download --timestamp-split "URL" ~/Music/youtubeFor each video, including videos inside playlists:
- Use chapter metadata supplied by
yt-dlp. - If there is no usable chapter list, parse the video description for timestamps and track names.
- Split from each timestamp to the next, and from the last timestamp to the recording's end.
Supported description formats include:
00:00 - Opening Theme
03:12 Second Track
[07:45] Third Track
Fourth Track 1:02:03
Track names come from the labels alongside timestamps and are numbered sequentially:
downloads/Album/
├── 01 - Album.mp3
└── 01 - Album - tracks/
├── 01 - Opening Theme.mp3
├── 02 - Second Track.mp3
├── 03 - Third Track.mp3
└── 04 - Fourth Track.mp3
If a timestamp has no label, its timestamp becomes the name, for example 02 - 03-12.mp3. Colons and other unsafe filename characters are replaced with hyphens. Track title, track number, and album title are also written as MP3 metadata.
- At least two valid timestamps/chapters are required, in strictly increasing order and within the recording's duration. Invalid lists are not guessed or reordered.
- If the first timestamp is after zero, an
Introtrack preserves the preceding audio. Short tracks are not discarded. - If no usable timestamps are found, keep the full recording and report that it could not be split. There is no silence fallback with
--timestamp-split. - The original MP3 is always retained. Each downloaded source filename gets its own track folder rather than writing all playlist tracks into one shared directory.
- Existing track folders are skipped unless
--forceis provided. Splitting can run against an already-downloaded MP3; timestamps are refreshed throughyt-dlp. - All cuts finish in a temporary staging folder before being published. Failed cuts leave the original and existing tracks intact.
--forcereplaces generated files with matching names, not unrelated files in the track folder. If track names change, older differently named tracks are left in place.- Splitting stream-copies the audio without re-encoding. Boundaries are limited to MP3 frame precision. Embedded artwork and other source tags are not copied to the split tracks; they remain in the full MP3.
./bin/yt-download --force "URL"
./bin/yt-download --force --timestamp-split "URL"
./bin/yt-download --split "URL"
./bin/yt-download --help--split enables automatic splitting: timestamps first, then silence detection for recordings at least 15 minutes long. Silence detection uses -35dB and a 1.2-second minimum silence, keeping tracks at least 45 seconds long without discarding short fragments. Do not combine --split and --timestamp-split.
The CLI deliberately ignores external yt-dlp configuration so output paths, overwrite behavior, and postprocessing remain predictable. It uses yt-dlp's current default YouTube clients rather than pinning clients in the wrapper.
A 403: Forbidden while downloading video data happens before timestamp splitting: YouTube rejected the media request. It can be intermittent, or caused by an outdated extractor.
First update yt-dlp using the installer that manages it. For Ubuntu 26.04 with backports enabled:
sudo apt-get update
sudo apt-get install -t resolute-backports yt-dlp
/usr/bin/yt-dlp --versionFor uv, include the default extras for the EJS solver:
uv tool install --upgrade "yt-dlp[default]"
~/.local/bin/yt-dlp --versionThen retry the same yt-download command. If both copies are installed, the CLI still prefers the user-local copy; see the switching instructions above. A user-local installation leaves apt's package untouched. Do not hide the outdated-version warning with --no-update; that does not fix extraction. If a current version still returns 403, network/IP restrictions or other YouTube changes may need separate investigation.
npm run check
npm test
npm pack --dry-runPackaging rebuilds the CLI and includes bin/, compiled dist/src/, and the README, excluding tests and downloads. The package remains private until it is ready to publish.
Tests cover timestamp parsing, filename safety, track tags, overwrite behavior, playlist isolation, and failure cleanup. Audio integration tests use local fixtures and skip if ffmpeg/ffprobe are unavailable. A real yt-dlp metadata smoke test also runs when it is installed, against a local HTTP server rather than YouTube.
