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.dev2.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.dev2-py3-none-any.whl (26.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: yt_pdlp-0.0.0.dev2.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.dev2.tar.gz
Algorithm Hash digest
SHA256 3113b4ef9c990a9f67a8d803363155aa12da0656662eb262c555275f4111bbe5
MD5 7f280d78dafa091927fae0c6d1163163
BLAKE2b-256 663f5a6a6f01d855ec4e47838130f6e7731cb586be954abf27a440178510fd64

See more details on using hashes here.

Provenance

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

File metadata

  • Download URL: yt_pdlp-0.0.0.dev2-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.dev2-py3-none-any.whl
Algorithm Hash digest
SHA256 8e718020062e2e3535f9f77a45e5c7bc3f02cde2e0dd4c1af40e4f0ee4bea57d
MD5 5c2d3533e948261135d6418304235c4a
BLAKE2b-256 89b35275517dd36858028ad503894df910e005bc786fcbcdefd91682e1ac6946

See more details on using hashes here.

Provenance

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