Skip to main content

VDL

PyPI Version Python 3.12+ License: MIT

VDL logo

VDL is a local-first media workflow runtime for building apps and workflows around video downloads, playlists, page discovery, link lists, progress events, and structured results.

It is designed around three surfaces:

Surface Default State Best For
Python library Stateless Embedding media download/discovery in apps and tools
Headless CLI Stateless Scripts, one-shot jobs, and automation
Interactive app Stateful Guided terminal UX with history, status, SQLite, and logs

External products own their own persistence and product workflows. VDL provides the media execution capability; it does not try to become a media library app.

Full developer documentation is live at: https://video-downloader-657d90.gitlab.io

flowchart TD
  StandaloneBinary["Standalone binary<br/>(curl install.sh)"]
  PythonPkg["Python package<br/>(pip install vdl)"]
  
  StandaloneBinary --> CLI["vdl CLI"]
  StandaloneBinary --> App["Interactive app"]
  StandaloneBinary --> MCP1["vdl-mcp"]
  
  PythonPkg --> Library["Python library"]
  PythonPkg --> CLI
  PythonPkg --> App
  PythonPkg --> Tools["vdl.tools"]
  PythonPkg --> MCP2["MCP server<br/>(mcp extra)"]

Install vdl Binary

Use the standalone installer when you want the commands without setting up a Python project:

macOS / Linux:

curl -fsSL https://bildcraft.gitlab.io/products/video-downloader/vdl/install.sh | sh

Windows:

irm https://bildcraft.gitlab.io/products/video-downloader/vdl/install.ps1 | iex

This gives you:

  • vdl
  • vdl-mcp

Re-running the standalone installer is safe:

  • installs if VDL is missing
  • updates if the installed version is older
  • does nothing if the same version is already installed
  • checks required dependencies before replacing binaries

Interactive Download App

Start the interactive app with:

vdl

It opens an interactive terminal interface:

VDL Interactive App

The app guides you through:

  1. Input — paste a URL, local file path, or .txt link list
  2. Quality — choose preferred resolution (best, 2160p, 1440p, 1080p, 720p, 480p, or audio)
  3. Output — set download directory (default: ~/Downloads/VDL)
  4. Options — save thumbnails and subtitles
  5. Mode — download directly or crawl the page for more links

Perfect for downloading single videos, playlists, or discovering downloadable media on websites.

YouTube 4K support

VDL standalone releases and the developer environment pin a tested yt-dlp nightly (currently 2026.10.10.233141) and include its EJS challenge scripts. YouTube extraction also needs a JavaScript runtime: Deno is preferred, or Node.js 22+ can be configured with vdl config set js_runtime_path /path/to/node. FFmpeg/ffprobe are required for merging and verification.

best uses yt-dlp's native best-quality ranking without a resolution cap. Numbered quality requests are exact: --quality 2160p fails if that resolution is unavailable. --fallback selects the best resolution at or below the request. Aliases 4k and 2k mean 2160p and 1440p. Video output uses MP4, preserving the selected video/audio codecs without re-encoding.

Default YouTube clients are used; VDL does not install or run a PO-token service. Cookies are only used when explicitly configured. Format availability still depends on the video and YouTube's restrictions.

vdl update updates standalone VDL and its bundled yt-dlp together through verified VDL releases. It does not independently update yt-dlp between releases. Use vdl doctor to see the active yt-dlp version, channel, EJS, and runtime. Source/Python package installations should update through their package manager.

The interactive app is intentionally stateful: it creates local app directories, SQLite state, and logs so it can provide history/status/session UX.

CLI Commands

Check the installed binary:

vdl --version

Run direct commands:

vdl download https://example.com/video
vdl crawl https://example.com/gallery --first 3
vdl crawl https://example.com/gallery --crawl-pagination --first 3
vdl playlist https://example.com/playlist
vdl resolve https://example.com/playlist
vdl status
vdl doctor

These headless commands are stateless by default. They do not implicitly create the interactive SQLite database or app logs.

Crawl-specific behavior is intentionally different from direct download and playlist flows:

  • vdl crawl ... --first 3 means first 3 successful downloads, not first 3 discovered links
  • crawl applies its own admission policy, including a default 7 MB minimum file size
  • --allow-tiny disables that crawl-only minimum
  • --crawl-pagination follows pagination/navigation pages discovered during crawl
  • direct downloads and playlists are not guarded by the crawl minimum, which keeps audio and other intentional small downloads working normally

When a site needs authentication, the headless commands can take cookies too:

vdl download --cookies cookies.txt https://example.com/video
vdl crawl --cookies-from-browser firefox https://example.com/gallery --first 3

Install as Python Library

Use the Python package when you want to embed VDL in another Python project:

pip install vdl

The full Python/library docs are live at: https://video-downloader-657d90.gitlab.io/python-api/

That gives you:

  • the vdl Python library
  • the vdl CLI
  • the interactive app entrypoint
  • vdl.tools

Use the library directly:

import asyncio

from vdl import CrawlerPolicy, VDLClient


async def main() -> None:
    client = VDLClient()
    result = await client.download("https://example.com/video")
    print(result.status)

    crawl_plan = await client.discover(
        "https://example.com/gallery",
        crawler_policy=CrawlerPolicy(crawl_pagination_pages=True),
    )
    crawl_results = await client.execute_plan(
        crawl_plan,
        crawler_policy=CrawlerPolicy(first_successful=3),
    )
    print(len(crawl_results))


asyncio.run(main())

The library is stateless by default and embeddable. Your application owns any database, history, user library, retries, or product-specific workflow state.

Use the tool surface:

import asyncio

from vdl.tools import download_video


async def main() -> None:
    result = await download_video("https://example.com/video")
    print(result["status"])


asyncio.run(main())

MCP Support

Install the MCP extra when you want vdl-mcp:

pip install "vdl[mcp]"

That adds MCP support on top of the Python package. If you installed the standalone binary, vdl-mcp is already included there too.

Example MCP client config:

{
  "mcpServers": {
    "vdl": {
      "command": "vdl-mcp",
      "args": []
    }
  }
}

Examples

Each demo in demos/ illustrates a single workflow:

Demo Use Case
download_video.py Download a single video
download_playlist.py Download an entire playlist
resolve_playlist.py Inspect playlist items before downloading
download_link_file.py Batch download URLs from a .txt file
crawl_websites.py Discover and download media on a webpage

All demos use placeholder URLs — copy and edit with your own.

Metadata

Release files for vdl 2.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for vdl 2.1.2
File Size Uploaded
vdl-2.1.2.tar.gz 1.6 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for vdl 2.1.2
File Interpreter ABI Platform
vdl-2.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 1.7 MB

Release files / vdl-2.1.2.tar.gz

Download URL vdl-2.1.2.tar.gz
Size 1.6 MB
Tags Source
SHA-256 checksum
How to use checksums
cf4e38a8aa4b89b362d473b6cadad69d052a98f66a7212be3cbccb8733b33bb0
BLAKE2b-256 checksum
How to use checksums
222309c186e875e95f6cc55c80aa2277f253bbde8fcca0a6fb834c0d4ef82e12
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / vdl-2.1.2-py3-none-any.whl

Download URL vdl-2.1.2-py3-none-any.whl
Size 150.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
64602b3e0bb03a885daf096121ff9b63fb3aa8af5d6502e6a7a7d8c9f2478855
BLAKE2b-256 checksum
How to use checksums
1f8626709c9de56058a54055b3a5df6bdac4d8dc00091803fda43c76502e9ae3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

2.1.2 This release

2 release files

2.1.1

2 release files

2.1.0

2 release files

2.0.2

2 release files

2.0.1

2 release files

2.0.0

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page