Metadata-Version: 2.4
Name: youtube-downloader
Version: 1.0.0
Summary: CLI tool to download YouTube playlists, liked videos, and individual videos
Author-email: Ruben Huizenga <RubenHuizenga@proton.me>
License-Expression: MIT
Project-URL: Homepage, https://forgejo.rubysrc.dev/ruby/youtube-downloader
Project-URL: Repository, https://forgejo.rubysrc.dev/ruby/youtube-downloader
Project-URL: Issues, https://forgejo.rubysrc.dev/ruby/youtube-downloader/issues
Keywords: youtube,yt-dlp,downloader,cli
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Multimedia :: Video
Classifier: Topic :: Utilities
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: yt-dlp>=2026.8.19
Requires-Dist: typer>=0.27.2
Dynamic: license-file

# youtube-downloader

[![CI](https://forgejo.rubysrc.dev/ruby/youtube-downloader/badges/workflows/ci.yml/badge.svg)](https://forgejo.rubysrc.dev/ruby/youtube-downloader/actions)
[![Release](https://forgejo.rubysrc.dev/ruby/youtube-downloader/badges/release.svg)](https://forgejo.rubysrc.dev/ruby/youtube-downloader/releases)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

CLI tool to download YouTube playlists, your Liked Videos list, or individual videos with resumable re-runs and clear reporting of deleted/private videos.

## Install

```
uv sync
```

This creates `.venv` and installs the package with its dev dependencies (pytest, ruff, mypy, pre-commit). Without [uv](https://docs.astral.sh/uv/), fall back to pip 25.1+:

```
python3 -m venv .venv
.venv/bin/pip install -e . --group dev
```

## One-time setup

Your Liked Videos list is private, so the tool needs to read cookies from a browser you're logged into YouTube with:

```
uv run youtube-downloader config set-cookies-browser firefox
```

Supported browser values: `chrome`, `firefox`, `edge`, `brave`, and others supported by yt-dlp's `--cookies-from-browser`.

## Usage

Prefix commands with `uv run` (e.g. `uv run youtube-downloader liked`) unless the venv is activated.

```
youtube-downloader liked                              # download your Liked Videos
youtube-downloader liked -n 20                         # only download 20 new videos this run
youtube-downloader liked --start 1 --end 50            # only consider the first 50 liked videos
youtube-downloader liked --dry-run                      # preview what would download, no downloading
youtube-downloader playlist <URL>                      # download a playlist
youtube-downloader playlist <URL> -n 10                # only download 10 new videos from it
youtube-downloader video <URL> [<URL> ...]              # download one or more individual videos
youtube-downloader config show                          # see current defaults
```

`video` accepts full URLs (`https://www.youtube.com/watch?v=...`, `https://youtu.be/...`) or bare video IDs, and any number of them in one call.

### Options

All three download commands (`liked`, `playlist`, `video`) accept:

| Option | Default | Description |
| --- | --- | --- |
| `-o, --output-dir <path>` | `~/Videos/YouTube` | Directory to save videos into. |
| `--browser <name>` | config default | Browser to read cookies from (`chrome`, `firefox`, `edge`, `brave`, ...). Required for `liked`. |
| `--format-preset <mp4\|best\|audio-only>` | `mp4` | `mp4` (best mp4-compatible video+audio), `best` (best available, any container), or `audio-only` (extract to mp3). |
| `--archive-file <path>` | `<output-dir>/.youtube-downloader/archive.txt` | Download-archive file used to track already-downloaded videos. |
| `--dry-run` | off | List what would be downloaded without downloading anything. |
| `--no-progress` | off | Suppress per-file progress output (quiet mode). |

`liked` and `playlist` additionally accept:

| Option | Default | Description |
| --- | --- | --- |
| `-n, --limit <n>` | unlimited | Stop after this many *new* videos are downloaded (already-archived videos don't count against it). |
| `--start <n>` | 1 | 1-based position in the list to start enumerating from. |
| `--end <n>` | end of list | 1-based position in the list to stop enumerating at. |

Any option can also be set as a persistent default (see [Configuration](#configuration)) so you don't have to repeat `--browser`/`--output-dir`/`--format-preset` on every run.

Re-running any command skips videos already downloaded (tracked via the archive file) and only fetches new ones. Deleted/private/unavailable videos are skipped automatically and listed in the end-of-run summary — they'll be retried automatically if they ever become available again. `--dry-run` runs are never recorded to the archive file or the run log.

## Configuration

`youtube-downloader config show` prints the resolved config file path (`~/.config/youtube-downloader/config.toml`) and current defaults. `youtube-downloader config set-cookies-browser <browser>` is the only setting with a dedicated command; other defaults (`output_dir`, `format_preset`, `archive_file`) can be set by editing the TOML file directly:

```toml
[defaults]
browser = "firefox"
output_dir = "/home/you/Videos/YouTube"
format_preset = "mp4"
archive_file = "/home/you/Videos/YouTube/.youtube-downloader/archive.txt"
```

Command-line flags always override config file defaults.

## Development

```
uv run pytest          # run tests
uv run ruff check .    # lint
uv run ruff format .   # format
uv run mypy            # type-check
```

Unit tests cover config parsing, unavailable-video classification, and summary formatting. End-to-end downloading (auth, real playlists) requires manual verification against a real YouTube account/browser.

[pre-commit](https://pre-commit.com) hooks are configured in `.pre-commit-config.yaml`; run `pre-commit install` once after cloning to enable them.

## Releasing

Pushing a tag matching `v*.*.*` triggers `.forgejo/workflows/publish.yml`, which builds the package, creates a Forgejo release with the built sdist/wheel attached, and uploads them to this instance's package registry. To cut a release:

1. Bump `version` in `pyproject.toml`.
2. Commit and push to `main`.
3. Tag the commit and push the tag, e.g. `git tag v1.1.0 && git push origin v1.1.0`.

The workflow refuses to publish if the tag doesn't match `pyproject.toml`'s version. Requires a repo secret `PUBLISH_TOKEN` set in the repo settings; a personal access token scoped to both `write:package` (registry upload) and `write:repository` (release creation).

## License

[MIT](LICENSE)
