Skip to main content

Download a YouTube playlist with several concurrent yt-dlp workers and a live Textual UI.

Project description

yt-pdlp

Download a large YouTube playlist with several yt-dlp workers running concurrently, showing each worker's live progress in a Textual terminal UI. It supports a planning dry-run and a post-run flush report that reconciles how many videos actually landed versus failed.

Why

yt-dlp has no built-in option to download multiple playlist items in parallel — its -N / --concurrent-fragments flag only parallelises fragments within a single video, so playlist items are processed one at a time. Downloading a ~1,000-item playlist (such as Watch Later) therefore crawls. yt-pdlp runs several downloads at once in one process, with a live UI and resumability.

Requirements

  • Python ≥ 3.11
  • ffmpeg on your PATH (needed to remux to mp4)
  • A browser you are signed in to YouTube with (default: Chrome) — Watch Later is private, so cookies are required.

Install & run

This project uses uv:

uv sync                       # create the environment
uv run yt-pdlp --help  # see all options

Usage

yt-pdlp is a command group with a default command, so a bare invocation downloads:

# Download Watch Later with 4 workers (the defaults)
uv run yt-pdlp

# Six workers, a specific playlist, into ./videos
uv run yt-pdlp -j 6 -u "https://www.youtube.com/playlist?list=PLxxxx" -o ./videos

# Plan only — contacts YouTube read-only, downloads nothing
uv run yt-pdlp --dry-run

# Reconcile an existing output directory without downloading
uv run yt-pdlp flush -o ./videos

download options (the default command)

Option Short Default Meaning
--jobs -j 4 Number of concurrent workers.
--url -u Watch Later Playlist (or any yt-dlp-supported) URL.
--output -o ./downloads Output directory (created if absent).
--browser -b chrome Browser to read cookies from.
--format -f None Remux container; an empty string or None disables remux.
--fragments -N 8 concurrent_fragment_downloads per worker (intra-video).
--dry-run off Plan only; download nothing.
--plain auto Disable the Textual UI; emit line-based progress (auto-on when stdout is not a terminal).

flush options

Option Short Default Meaning
--output -o ./downloads Locate and reconcile this output's state directory.
--url -u (optional) Re-flatten this playlist to define the "requested" set instead of using the cached list.

How it works

  • A shared work queue holds every playlist entry. --jobs workers each pull the next entry and download it, so the work load-balances naturally across videos of very different lengths.
  • Each worker owns its own yt_dlp.YoutubeDL instance and reports progress through a UI-agnostic event stream. A Textual front-end renders per-worker panels and an overall counter; a plain front-end prints line-based progress when there is no terminal.
  • A shared download archive records only successful downloads, so re-running the same command skips what is already done and retries what failed.
  • The browser cookie store is read once and written to a reusable cookie file; every worker then reads the file (browsers lock their cookie database, so reading it from many workers at once would contend).

State directory

Everything lives under <output>/.ytdlp-state/:

File Purpose
cookies.txt Cookies exported once from the browser. Sensitive — it holds a live session; keep it private.
entries.json The flattened playlist: a list of {id, url, title}.
archive.txt The yt-dlp download archive (resume + skip).
failed.txt Outstanding URLs after a run or flush, one per line — retry with yt-dlp -a failed.txt … or just re-run.
report.txt The last completion report.

Downloaded media files go directly under <output>/.

A note on concurrency

The realistic sweet spot is 4–8 workers. The bottleneck is YouTube's per-account/IP throttling (HTTP 429), not your machine — beyond a handful of workers, total throughput usually drops. yt-pdlp warns when you ask for more than 8 but does not stop you.

Development

uv run pytest -q                       # tests
uv run ruff check src tests            # lint
uv run ruff format --check src tests   # formatting
uv run ty check src                    # type-check

The download engine is deliberately decoupled from the UI, and yt-dlp, the network, and the terminal are faked in tests only so the whole tool runs offline in CI.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

yt_pdlp-0.0.0.dev3.tar.gz (43.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

yt_pdlp-0.0.0.dev3-py3-none-any.whl (26.4 kB view details)

Uploaded Python 3

File details

Details for the file yt_pdlp-0.0.0.dev3.tar.gz.

File metadata

  • Download URL: yt_pdlp-0.0.0.dev3.tar.gz
  • Upload date:
  • Size: 43.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for yt_pdlp-0.0.0.dev3.tar.gz
Algorithm Hash digest
SHA256 4025820387b2cf748483a17fb4d72cdaf00f636554dbdc2799bc2fecfbc56078
MD5 9894186b2c289111cadff9ab1f69e70d
BLAKE2b-256 fb917f7bc2eeb54cb58e12d8c8f4e3fe91295160772f7a3da154a42fcec758ee

See more details on using hashes here.

Provenance

The following attestation bundles were made for yt_pdlp-0.0.0.dev3.tar.gz:

Publisher: release.yml on synmux/yt-pdlp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file yt_pdlp-0.0.0.dev3-py3-none-any.whl.

File metadata

  • Download URL: yt_pdlp-0.0.0.dev3-py3-none-any.whl
  • Upload date:
  • Size: 26.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for yt_pdlp-0.0.0.dev3-py3-none-any.whl
Algorithm Hash digest
SHA256 70265796d99de73733b828d6d9fb22d27860269f077dfb896e8b740b4ab3f7bf
MD5 d1180f1bd70bcd91f369d87f9202b794
BLAKE2b-256 7e37f86b34e5c5e27d112a9133088950cf563b9be45856dac984a4414269ffb5

See more details on using hashes here.

Provenance

The following attestation bundles were made for yt_pdlp-0.0.0.dev3-py3-none-any.whl:

Publisher: release.yml on synmux/yt-pdlp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page