Skip to content

Public API Contract

VDL distinguishes between stable public API (safe to import and depend on) and internal implementation details that may change without warning.

Stable Public API

These imports and classes are supported across minor and patch versions. Use them freely in your applications and scripts.

Main Client and Config

from vdl import VDLClient, VDLConfig

The primary entry point for all download, playlist, discovery, and query operations.

Models (Safe to Import)

from vdl import (
    # Status and configuration
    DownloadStatus,
    DownloadResult,
    DownloadMetadata,      # typed result metadata (replaces dict)
    DownloadSidecars,      # thumbnail and subtitle sidecar paths
    IfExists,
    SkipReason,

    # Quality selection
    Quality,

    # Playlist operations
    PlaylistInfo,
    PlaylistItem,

    # Planning and execution
    AcquisitionPlan,
    AcquisitionItem,
    PlanKind,
    BatchSummary,

    # Crawling and discovery
    CrawlerPolicy,
    CrawlerDecision,

    # Progress and cancellation
    DownloadProgress,

    # Health check
    DoctorReport,

    # State reconciliation
    ReconciliationEntry,
    ReconciliationReport,
)

Quality Selection

from vdl import Quality            # now in public __all__
from vdl.models import Quality     # also fine

# Quality options
Quality.BEST, Quality.P2160, Quality.P1440, Quality.P1080, 
Quality.P720, Quality.P480, Quality.AUDIO

Progress Event

VDLClient.progress is a subscribable event for receiving progress updates across all downloads on the client without threading a callback through every call:

client = VDLClient()
client.progress += my_async_handler    # subscribe
client.progress -= my_async_handler    # unsubscribe

Cancellation Control

from vdl.cancellation import CancellationToken, CancellationController

# Create a cancellation token to stop ongoing downloads
token = CancellationToken()
# Pass to download(), discover(), execute_plan()
# Call token.cancel() to trigger cancellation

Exception Hierarchy

from vdl import (
    VDLError,
    VDLConfigError,
    VDLInputError,
    VDLDownloadError,
    VDLPlaylistError,
    VDLStateError,
    VDLDependencyError,
    VDLSelectionError,
    VDLCrawlerError,
)

# Catch by type to distinguish failure modes
try:
    result = await client.download(url)
except VDLConfigError:
    print("Configuration error")
except VDLDownloadError as e:
    print(f"Download failed: {e}")
except VDLDependencyError:
    print("Missing ffmpeg or yt-dlp")

Duplicate Detection Service

from vdl import DuplicateDetectionService, DuplicateDecision

# Available for preflight duplicate checks before download
service = client.execution_service.duplicate_detection
decision = await service.check(request)

Request Factory

from vdl import DownloadRequestFactory, DownloadRequest

# Build and customize download requests
factory = DownloadRequestFactory(config=config)
request = factory.create(url, quality=Quality.P720)

Logger Interface

from vdl import Logger, NullLogger

# Implement Logger to capture events
class MyLogger(Logger):
    def log(self, level: str, event: str, **kwargs) -> None:
        print(f"[{level}] {event}: {kwargs}")

# Wire into client
client = VDLClient(logger=MyLogger())

Runtime Components

from vdl.runtime import build_library_components, build_interactive_components

# Headless (stateless) wiring for CLI, scripts, libraries
components = build_library_components()

# Interactive (stateful) wiring with SQLite and logs
components = build_interactive_components()

Internal / Unstable APIs

The following modules are internal implementation details and may change without warning:

Core Implementation (DO NOT IMPORT)

vdl.core.*                        # All core modules and submodules
vdl.apps.*                        # CLI and MCP implementations
vdl.models (partially)            # Some internal dataclass fields

Specific Internal Modules

Do not import from these; they are subject to refactoring:

# ✗ DON'T use these
from vdl.client import VDLClient       # Use: from vdl import VDLClient
from vdl.config import VDLConfig       # Use: from vdl import VDLConfig
from vdl.core.download.downloader import ...
from vdl.core.acquisition.planner import ...
from vdl.core.discovery.crawler import ...
from vdl.core.state.state import StateStore
from vdl.core.support.error_translation import ...
from vdl.core.retry import ...
from vdl.runtime import ...            # Implementation detail

Hidden Implementation Details

Do not rely on internal class fields, private methods (prefixed with _), or undocumented attributes. These are:

  • Internal service implementations (YtDlpDownloader, SQLiteStateStore)
  • Private module-level variables
  • Dataclass __post_init__, __repr__, or internal fields
  • Protocol implementations (fakes for testing)

Forward Compatibility

What Guarantees Exist

  • Public API function signatures are stable within a major version
  • Enum values are stable (adding new values is okay, removing is not)
  • Dataclass field order is stable (adding optional fields is okay, removing is not)
  • Exception hierarchy is stable (adding new exception types is okay)

What May Change

  • Private module implementations and internal functions
  • Optional dataclass fields and their defaults
  • Internal service wiring and component order
  • Config file format and location (will be documented in release notes)
  • CLI flags and subcommand behavior (use --help for current state)

Version Compatibility

Use this in pyproject.toml or requirements.txt:

# Pins to a major version; accepts bug fixes and features
vdl = "^2.0.0"

# Or with optional MCP support
vdl = { version = "^2.0.0", extras = ["mcp"] }

Checking API Availability

To verify a public API is available, check the __all__ export in vdl/__init__.py:

from vdl import __all__
assert "VDLClient" in __all__
assert "DownloadResult" in __all__

See Also