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 mp4 Remux container; an empty string disables remux.
--fragments -N 1 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.dev1.tar.gz (50.2 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.dev1-py3-none-any.whl (26.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: yt_pdlp-0.0.0.dev1.tar.gz
  • Upload date:
  • Size: 50.2 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.dev1.tar.gz
Algorithm Hash digest
SHA256 a0c3bce4b8561ed1a0d035a81222e24014a5e34919d04c574df9144b30cd8674
MD5 74d7826aa9520b3e1be5f7fba31514de
BLAKE2b-256 fbd4af08a43e30300b68446e65bc2acb2ae70a9e55200ad7d3e06807480e7c80

See more details on using hashes here.

Provenance

The following attestation bundles were made for yt_pdlp-0.0.0.dev1.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.dev1-py3-none-any.whl.

File metadata

  • Download URL: yt_pdlp-0.0.0.dev1-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.dev1-py3-none-any.whl
Algorithm Hash digest
SHA256 b4aa20ad166f3c7c6c115be9e218e9e23bc09e1031bda5eb594df910d2c5f07e
MD5 95ab6e582ba73aaa62717a3a12563d1d
BLAKE2b-256 5011957d625bee7f0ac1f64a8340fbeb979c637ae5208c6774a51e4ff14554d6

See more details on using hashes here.

Provenance

The following attestation bundles were made for yt_pdlp-0.0.0.dev1-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