Metadata-Version: 2.4
Name: vdl
Version: 1.0.3
Summary: A local-first media workflow toolkit for downloads, playlists, and automation through CLI and MCP interfaces
Project-URL: Homepage, https://gitlab.com/bildcraft/products/video-downloader
Project-URL: Repository, https://gitlab.com/bildcraft/products/video-downloader
Project-URL: Issues, https://gitlab.com/bildcraft/products/video-downloader/-/issues
Author: Temiloluwa
License: MIT
Keywords: cli,downloader,mcp,video,yt-dlp
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Video
Classifier: Topic :: Utilities
Requires-Python: >=3.12
Requires-Dist: beautifulsoup4>=4.12.0
Requires-Dist: brotli>=1.2.0
Requires-Dist: curl-cffi<0.15,>=0.10
Requires-Dist: prompt-toolkit>=3.0.43
Requires-Dist: pyyaml>=6.0.1
Requires-Dist: requests>=2.31.0
Requires-Dist: rich>=13.7.0
Requires-Dist: selenium>=4.16.0
Requires-Dist: yt-dlp-ejs>=0.8.0
Requires-Dist: yt-dlp>=2026.03.17
Provides-Extra: mcp
Requires-Dist: mcp>=1.0.0; extra == 'mcp'
Description-Content-Type: text/markdown

# VDL — Local Media Workflow Toolkit

![VDL logo](docs/assets/vdl-logo.svg)

VDL is a **local-first media workflow toolkit** for downloading, organizing, and automating video and playlist tasks through CLI, Python library, and MCP interfaces.

It is designed for reliable local workflows: single downloads, playlists, batch inputs, page discovery, idempotent execution, structured status tracking, and AI-assisted automation.

> VDL uses proven media extraction tools under the hood while adding workflow-level orchestration, state, automation, and developer-facing interfaces.

---

## Highlights

- **Local-first**: downloads, state, logs, and configuration stay on your machine.
- **Multiple interfaces**: interactive CLI, headless CLI, Python API, and MCP server.
- **Playlist workflows**: resolve, inspect, select, filter, and download playlist items.
- **Intent-aware interactive mode**: detect single videos, native playlists, playlist-member URLs, or crawlable pages before downloading.
- **Batch inputs**: handle URLs, playlists, link files, and page-discovered media.
- **Idempotent execution**: avoid accidental duplicate downloads and track status locally.
- **Automation-ready**: expose media tasks to scripts, apps, and MCP-compatible AI tools.

---

## Installation

### Standalone CLI

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

### Python package

```bash
pip install vdl
```

For MCP support:

```bash
pip install "vdl[mcp]"
```

With `uv`:

```bash
uv tool install vdl
uv tool install "vdl[mcp]"
```

---

## Quick Start

Download a video:

```bash
vdl download <url>
```

Download a playlist:

```bash
vdl playlist <playlist-url>
```

Resolve a playlist without downloading:

```bash
vdl resolve <playlist-url>
```

Start the interactive CLI:

```bash
vdl
```

Check environment setup:

```bash
vdl doctor
```

Show recent download status:

```bash
vdl status
```

---

## Interfaces

VDL exposes the same workflow capabilities through several interfaces.

```mermaid
flowchart TD
  Core["VDL Core / Library"]
  Interactive["Interactive CLI"]
  Headless["Headless CLI"]
  Python["Python Library API"]
  MCP["MCP Server"]

  Interactive --> Core
  Headless --> Core
  Python --> Core
  MCP --> Core

  Core --> Resolve["Resolve URLs, pages, and playlists"]
  Core --> Select["Selection and playlist policies"]
  Core --> Download["Download execution"]
  Core --> State["Local state, logs, and reconciliation"]
```

| Interface | Use case |
| :--- | :--- |
| Interactive CLI | Guided local workflows with prompts and sensible defaults. |
| Headless CLI | Scriptable commands for automation and repeatable jobs. |
| Python API | Embed VDL workflows into apps, services, or notebooks. |
| MCP server | Let MCP-compatible AI clients call local media workflow tools. |

---

## Workflow Model

```mermaid
flowchart LR
  Input["URLs / playlists / pages / files"] --> Resolve["Resolve intent"]
  Resolve --> Select["Select video(s)"]
  Select --> Download["Download"]
  Download --> Organize["Organize locally"]
  Organize --> Automate["CLI / Library / MCP automation"]
```

VDL turns mixed inputs into explicit download plans, applies selection and deduplication policies, executes downloads, and records state for later inspection. In interactive mode it can use `yt-dlp` metadata to distinguish native playlists from single videos, and it can crawl listing pages using site-specific rules from `websites.yaml` when the user chooses discovery.

---

## Python API

```python
import asyncio

from vdl import VDLClient

async def main() -> None:
    client = VDLClient()
    result = await client.download(
        "https://example.com/video",
        quality="1080p",
    )

    print(result.status)
    print(result.output_path)

asyncio.run(main())
```

Playlist resolution:

```python
import asyncio

from vdl import VDLClient

async def main() -> None:
    client = VDLClient()
    playlist = await client.resolve_playlist("https://example.com/playlist")

    for item in playlist.items:
        print(item.title, item.url)

asyncio.run(main())
```

---

## Tool API

Use `vdl.tools` when another Python project, agent runtime, or
function-calling LLM needs a stable tool-shaped surface without MCP. These
functions accept plain inputs and return JSON-serializable outputs.

Async example:

```python
import asyncio

from vdl.tools import plan_download

async def main() -> None:
    plan = await plan_download("https://example.com/video", quality="best")
    print(plan["source_kind"])
    print(plan["items"][0]["url"])

asyncio.run(main())
```

Sync example:

```python
from vdl.tools import doctor_sync

report = doctor_sync()
print(report["version"])
print(report["ffmpeg"])
```

MCP is not required for this interface. Install `vdl` normally and import from
`vdl.tools`.

---

## MCP Server

Install the MCP extra:

```bash
pip install "vdl[mcp]"
```

Add the server to an MCP-compatible client:

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

The MCP server exposes local media workflow tools such as:

- `download`
- `download_playlist`
- `resolve_playlist`
- `get_status`
- `doctor`

The standalone binary release includes both `vdl` and `vdl-mcp`. Python package users should install `vdl[mcp]` when MCP support is needed.

---

## Configuration

VDL stores configuration at:

```text
~/.config/vdl/config.toml
```

Default local paths follow the XDG base directory layout:

| Purpose | Default path |
| :--- | :--- |
| Config | `~/.config/vdl/config.toml` |
| State database | `~/.local/state/vdl/vdl.db` |
| Logs | `~/.local/state/vdl/logs/` |
| Cache | `~/.cache/vdl/` |
| Downloads | `~/Downloads/VDL/` |

Example configuration:

```toml
output_dir = "~/Downloads/VDL"
default_quality = "best"
max_concurrent_downloads = 3
embed_metadata = true
embed_thumbnail = true
expand_nested_playlists = false
```

---

## Commands

| Command | Description |
| :--- | :--- |
| `vdl` | Start interactive mode. |
| `vdl download <url>` | Download a video, playlist, or link input. |
| `vdl playlist <url>` | Download playlist items. |
| `vdl resolve <url>` | Resolve playlist/page items without downloading. |
| `vdl status` | Show recent download status. |
| `vdl doctor` | Check local dependencies and configuration. |
| `vdl config` | View or update configuration. |

---

## Architecture

VDL keeps business logic in the shared core/library layer. Interfaces are adapters over that core:

```text
VDL Core / Library
  ├── Interactive CLI
  ├── Headless CLI
  ├── Python API
  └── MCP server
```

This keeps the CLI, MCP server, and library interface independent while sharing the same resolution, download, state, and configuration logic.

Key modules:

| Module | Responsibility |
| :--- | :--- |
| `client.py` | Programmatic entry point and workflow orchestration. |
| `cli.py` | CLI command parsing and headless command execution. |
| `interactive.py` | Guided interactive mode. |
| `mcp_server.py` | MCP server adapter. |
| `acquisition.py` | Convert inputs into download plans. |
| `playlist.py` | Playlist resolution, inspection, and item selection. |
| `downloader.py` | Download execution. |
| `state.py` | SQLite-backed local state. |
| `config.py` | Configuration loading and persistence. |
| `crawler.py` / `site_rules.py` | Page discovery and `websites.yaml`-driven crawl filtering. |

---

## System Requirements

VDL expects the following tools for full media processing support:

- Python 3.13+
- `ffmpeg`
- `ffprobe`

VDL uses `yt-dlp` under the hood for media extraction and download support.

---

## Development

```bash
uv sync --frozen --all-extras --dev
PYTHONPATH=src uv run pytest -q
uv build --no-sources
```

Useful tasks:

```bash
task --list
task test
task build:pypi
task release
task release:validate
```

---

## Release

Release automation is handled through GitLab CI.

- PyPI package: built and published in CI through Trusted Publishing.
- macOS arm64 binary: built locally with `scripts/build-macos.sh` and uploaded to a GitLab Release.
- Linux/Windows binaries: optional CI builds behind release variables.
- Installer manifest: published by the manual `vdl-publish-pages` job after release assets exist.

For the current happy path, run `task release` on an Apple Silicon Mac from a
clean branch. It wraps the local macOS build, pushes the release tag,
uploads the macOS artifact to GitLab Release, waits for the tag pipeline, and
triggers the manual Pages publish job. The release script auto-loads `.env`
when present, so `GITLAB_TOKEN` there is enough for `glab` API calls.

See [`docs/RELEASE_PLAYBOOK.md`](docs/RELEASE_PLAYBOOK.md) for the full release process.

---

## Related Projects

- [yt-dlp](https://github.com/yt-dlp/yt-dlp) — media extraction and download support
- [FFmpeg](https://ffmpeg.org/) — audio/video processing
- [Model Context Protocol](https://modelcontextprotocol.io/) — AI tool integration standard

---

## License

MIT License.
