Metadata-Version: 2.4
Name: ycdl
Version: 0.1.0
Summary: YouTube channel video/Shorts downloader - CLI and lightweight web UI, with a .txt info file of metrics per video.
Project-URL: Homepage, https://github.com/tolgahanuzun/ycdl
Project-URL: Repository, https://github.com/tolgahanuzun/ycdl
Project-URL: Issues, https://github.com/tolgahanuzun/ycdl/issues
Author-email: Tolgahan Üzün <mail@tolgahanuzun.com>
License: MIT
License-File: LICENSE
Keywords: cli,downloader,fastapi,shorts,youtube,yt-dlp
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Video
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Requires-Dist: fastapi>=0.110
Requires-Dist: pydantic>=2.5
Requires-Dist: rich>=13.0
Requires-Dist: typer>=0.12
Requires-Dist: uvicorn[standard]>=0.27
Requires-Dist: yt-dlp>=2024.1.0
Provides-Extra: dev
Requires-Dist: httpx>=0.27; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Provides-Extra: mcp
Requires-Dist: mcp>=1.2; extra == 'mcp'
Description-Content-Type: text/markdown

# ycdl

[![CI](https://github.com/tolgahanuzun/ycdl/actions/workflows/ci.yml/badge.svg)](https://github.com/tolgahanuzun/ycdl/actions/workflows/ci.yml)
[![Python](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
[![Powered by yt-dlp](https://img.shields.io/badge/powered%20by-yt--dlp-red)](https://github.com/yt-dlp/yt-dlp)

A tool to list and download the **latest N videos or Shorts** from YouTube channels.
It ships both a fast **CLI** (`ycdl`) and a lightweight **web UI** (FastAPI + plain HTML/CSS/JS, no build step). For every downloaded video it writes a `.txt` info file containing metrics such as **views / likes / comments**.

> [!NOTE]
> This tool only uses yt-dlp; no API key is required.

## Features

- Search by channel **URL, `@handle` or name**
- **Shorts**, **regular videos** or **both** (filterable)
- Web UI with a **thumbnail grid**, **multi-select** and **live progress** (SSE)
- Bulk download from the CLI without the UI
- A `<id>-<title>.txt` **info file** per video (+ optional `.info.json`)
- **Persistent search history** (shared by CLI and UI) you can re-run with one click
- Quality selection, **audio-only (mp3)**, concurrent downloads
- **MCP server** so AI tools (Cursor, Claude, ...) can list/download for you
- Installable via `pip`, exposes `ycdl` / `ycdownload` commands

## Requirements

- Python 3.10+
- [ffmpeg](https://ffmpeg.org/) (recommended for merging video+audio and mp3 conversion)
  - macOS: `brew install ffmpeg`
  - Ubuntu/Debian: `sudo apt install ffmpeg`
  - Windows: [ffmpeg.org](https://ffmpeg.org/download.html)

## Installation

Clone the repository and install from source:

```bash
git clone https://github.com/tolgahanuzun/ycdl.git
cd ycdl
pip install .
```

For development (editable install with dev tools):

```bash
pip install -e ".[dev]"
```

> Not yet published to PyPI; install from source for now.

## Quick start

### Web UI (recommended)

```bash
ycdl serve --open
```

Opens `http://127.0.0.1:8888` in the browser. Enter a channel, list, select and download.

### CLI

```bash
# List (without downloading)
ycdl list @MrBeast --last 20 --type shorts

# Download the latest 20 Shorts from a channel
ycdl download @MrBeast --last 20 --type shorts -o ./downloads

# Regular videos only, 720p, 4 concurrent
ycdl download @MrBeast -n 10 --type videos -q 720 --concurrency 4

# Download a single video
ycdl download "https://www.youtube.com/watch?v=VIDEO_ID"

# Show the metrics of a single video
ycdl info "https://www.youtube.com/shorts/VIDEO_ID"
```

`python -m ycdl ...` works the same way.

## CLI commands

| Command | Description |
| --- | --- |
| `ycdl list <channel>` | List the channel's latest videos (no download) |
| `ycdl download <channel\|url>` | Download the latest N videos or a single video |
| `ycdl info <url>` | Show the metrics of a single video |
| `ycdl history` | Show saved searches (`--clear` to wipe) |
| `ycdl serve` | Start the web UI |
| `ycdl mcp` | Run as an MCP server (for Cursor, Claude, etc.) |

### Key options

| Option | Default | Description |
| --- | --- | --- |
| `--last, -n` | `20` | How many recent videos |
| `--type, -t` | `both` | `shorts` / `videos` / `both` |
| `--output, -o` | `downloads` | Download directory |
| `--quality, -q` | `best` | `best` / `1080` / `720` / `480` |
| `--audio-only` | off | Audio only (mp3) |
| `--concurrency, -c` | `3` | Number of concurrent downloads |
| `--no-txt` | - | Do not write the `.txt` info file |
| `--no-info-json` | - | Do not write `.info.json` |

## Output layout

```
downloads/
└── <Channel Name>/
    ├── <id>-<title>.mp4
    ├── <id>-<title>.txt        # views, likes, comments, duration, date, description...
    └── <id>-<title>.info.json  # compact machine-readable metadata (optional)
```

Example `.txt`:

```
============================================================
Sample Video Title
============================================================

Channel       : Test Channel
Video ID      : abc123
URL           : https://www.youtube.com/watch?v=abc123
Type          : Shorts
Upload date   : 2026-01-01
Duration      : 0:45

--- Metrics ---
Views         : 1,234,567
Likes         : 8,900
Comments      : 120
```

## Environment variables

| Variable | Description |
| --- | --- |
| `YCDL_OUTPUT_DIR` | Default download directory |
| `YCDL_QUALITY` | Default quality |
| `YCDL_CONCURRENCY` | Default concurrency |
| `YCDL_HISTORY_FILE` | Search history file (default `~/.ycdl/history.json`) |

## Development

```bash
pip install -e ".[dev]"
ruff check src tests
ruff format src tests
pytest -q
```

## MCP server (Cursor, Claude, etc.)

ycdl can run as an [MCP](https://modelcontextprotocol.io/) server, so AI tools can
list and download videos for you ("download the latest 20 Shorts from @MrBeast").

Install the optional MCP extra (from source) and run it:

```bash
pip install -e ".[mcp]"
ycdl mcp            # stdio transport
```

Exposed tools: `list_channel`, `video_info`, `download`, `search_history`, `clear_history`.

### Connect from Cursor

Add this to your Cursor MCP config (`~/.cursor/mcp.json` or the project's
`.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "ycdl": {
      "command": "ycdl",
      "args": ["mcp", "--output", "/absolute/path/to/downloads"]
    }
  }
}
```

If `ycdl` is installed in a virtualenv, use that interpreter, e.g.
`"command": "/path/to/.venv/bin/ycdl"`. The same config shape works for other
MCP-compatible clients (Claude Desktop, etc.).

## Architecture

- `core/` — yt-dlp wrappers (channel listing, downloading, metadata, job management). Shared by the CLI and the server.
- `cli.py` — Typer-based CLI.
- `server/` — FastAPI API + static web UI (live progress via SSE).
- `mcp_server.py` — MCP server exposing the same core as tools.

## Disclaimer

This tool is intended for personal use. You are responsible for respecting copyright
and the YouTube Terms of Service for any content you download.

## License

[MIT](LICENSE)
