CLI tool to download YouTube videos at maximum quality for video editing
Project description
vidgrab
PT-BR | EN
CLI para baixar vídeos do YouTube na maior qualidade técnica disponível — streams de vídeo e áudio separados (DASH), mesclados via FFmpeg sem nenhum reencode. Feito para quem usa vídeo como material bruto em edição.
PT-BR
Como funciona
A maioria das ferramentas de download aplica reencode para juntar vídeo e áudio — o que degrada a qualidade e desperdiça tempo. O vidgrab faz diferente:
YouTube → stream de vídeo (H.264 / VP9 / AV1) ─┐
→ stream de áudio (AAC / Opus) ─┴→ FFmpeg mux → arquivo final
Os dois streams são baixados separadamente no formato DASH (maior qualidade disponível) e mesclados em modo cópia — sem recodificação, sem perda de qualidade.
Funcionalidades
| Funcionalidade | Detalhe | |
|---|---|---|
| ⚡ | Downloads paralelos | Até 8 simultâneos via --workers |
| 🔁 | Retry inteligente | Backoff exponencial em rate-limits (até 5 tentativas) |
| 🔍 | Dry run | Veja título, resolução e tamanho antes de baixar |
| ⏸ | Resume automático | Downloads interrompidos são retomados de onde pararam |
| 📋 | Batch download | Arquivo .txt com uma URL por linha |
| 🎬 | Playlists | Expande e baixa todos os vídeos de uma playlist |
| 📁 | Skip inteligente | Detecta arquivo existente pelo ID e pula automaticamente |
| 📄 | Metadados JSON | Sidecar .json com título, canal, data, tags e mais |
| 🔒 | Conteúdo restrito | Suporte a cookies (Netscape) para vídeos com age-gate |
| ⚙️ | Config file | Defaults pessoais em ~/.config/vidgrab/config.toml |
| 🏷 | Nomes previsíveis | {data}-{slug}-{video_id}.{ext} em todo download |
| ⚠️ | Aviso de licença | Alerta quando o vídeo não é Creative Commons |
Dependências externas
| Ferramenta | Para quê | Como instalar |
|---|---|---|
| Python 3.11+ | Runtime | python.org |
| ffmpeg | Mesclar streams de vídeo e áudio | Veja abaixo |
| yt-dlp | Engine de download | Instalado automaticamente via Poetry |
| Deno (opcional) | Acesso a todos os formatos do YouTube, incluindo 4K/HDR | Veja abaixo |
Instalando o ffmpeg
Windows
winget install ffmpeg
macOS
brew install ffmpeg
Linux (Debian/Ubuntu)
sudo apt install ffmpeg
Ou baixe o executável em https://ffmpeg.org/download.html e adicione ao PATH.
Instalando o Deno (recomendado para 4K/HDR)
Sem o Deno, o yt-dlp usa um método alternativo que pode não enxergar todos os formatos disponíveis. Com o Deno instalado, a extração é completa.
Windows
winget install DenoLand.Deno
macOS
brew install deno
Linux
curl -fsSL https://deno.land/install.sh | sh
Instalação
Via pip (recomendado):
pip install vidgrab
Via pipx (isolado):
pipx install vidgrab
From source (desenvolvimento):
git clone https://github.com/gsjonio/video_grabber.git
cd video_grabber
poetry install
poetry run vidgrab --help
Automated installers:
- Linux/macOS:
bash install.sh - Windows:
install.bat
These scripts check for Python 3.11+ and ffmpeg, then install via pip.
Uso
# Vídeo único — qualidade máxima
vidgrab https://youtu.be/dQw4w9WgXcQ
# Inspecionar antes de baixar (dry run)
vidgrab https://youtu.be/dQw4w9WgXcQ --dry-run
# Limitar a 1080p
vidgrab https://youtu.be/dQw4w9WgXcQ --max-height 1080
# Salvar em diretório específico
vidgrab https://youtu.be/dQw4w9WgXcQ --output ~/Videos/raw
# Baixar playlist inteira
vidgrab "https://youtube.com/playlist?list=PLxxxx" --playlist
# Múltiplas URLs de um arquivo .txt com 5 workers
vidgrab --batch urls.txt --workers 5
# Forçar re-download mesmo se o arquivo já existir
vidgrab https://youtu.be/dQw4w9WgXcQ --force
# Conteúdo com restrição de idade
vidgrab https://youtu.be/dQw4w9WgXcQ --cookies ~/cookies.txt
# Salvar metadados em JSON
vidgrab https://youtu.be/dQw4w9WgXcQ --write-json
Arquivo --batch
Uma URL por linha. Linhas com # são ignoradas.
# Meus vídeos
https://youtu.be/dQw4w9WgXcQ
https://youtu.be/VIDEO_ID_2
Config file
Salve seus defaults pessoais em ~/.config/vidgrab/config.toml para não precisar repetir as flags:
output = "~/Videos/raw"
workers = 5
max_height = 1080
Flags passadas na linha de comando sempre têm prioridade sobre o config file.
Nomeação dos arquivos
{data_upload}-{slug-do-titulo}-{video_id}.{ext}
Exemplo: 20240315-never-gonna-give-you-up-dQw4w9WgXcQ.mp4
Com --write-json, um sidecar .json é criado ao lado do vídeo:
{
"video_id": "dQw4w9WgXcQ",
"title": "Rick Astley - Never Gonna Give You Up",
"channel": "Rick Astley",
"upload_date": "2009-10-25",
"duration_seconds": 212,
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"description": "...",
"tags": ["pop", "80s"]
}
Container e qualidade
| Streams disponíveis | Container de saída |
|---|---|
| H.264 + AAC | mp4 (sem reencode) |
| VP9 / AV1 + Opus | mkv (sem reencode) |
O objetivo é nunca recodificar — apenas mesclar os streams.
Referência de opções
| Opção | Atalho | Descrição |
|---|---|---|
[URLS]... |
Uma ou mais URLs do YouTube | |
--batch FILE |
-b |
Arquivo .txt com uma URL por linha |
--output DIR |
-o |
Diretório de saída (padrão: ~/Downloads) |
--max-height INT |
Limitar resolução vertical (ex.: 1080) |
|
--playlist |
Tratar URLs como playlists | |
--force |
-f |
Re-download mesmo se o arquivo já existe |
--cookies FILE |
Arquivo de cookies (formato Netscape) | |
--write-json |
Salvar metadados em .json ao lado do vídeo |
|
--workers INT |
-w |
Downloads paralelos (padrão: 3, máx: 8) |
--dry-run |
Mostrar o que seria baixado, sem baixar | |
--quiet |
-q |
Suprimir toda saída exceto erros (útil para scripts) |
--version |
-V |
Exibir versão |
--install-completion |
Instalar autocomplete no shell atual | |
--help |
Exibir ajuda |
Qualidade de código
O projeto usa uma stack completa de qualidade, integrada ao CI e aos pre-commit hooks:
| Ferramenta | Função |
|---|---|
| Ruff | Linter + formatador (9 categorias de regras) |
| Pylint | Análise estática avançada |
| Mypy (strict) | Type checking completo — dict[str, Any] em todas as fronteiras com yt-dlp |
| pytest + pytest-cov | 38 testes unitários, cobertura reportada ao Codecov |
| pre-commit | Ruff, Pylint, Mypy e Markdownlint rodando antes de cada commit |
| GitHub Actions | Lint, testes, CodeQL e release automática por tag |
| Dependabot | Atualizações semanais de dependências Python e Actions |
Estrutura do projeto
vidgrab/
├── cli.py # Interface Typer — parsing de argumentos e orquestração
├── downloader.py # Lógica core — parallelismo, retry, classificação de erros
├── models.py # VideoMetadata e DownloadResult como dataclasses tipadas
├── exceptions.py # Hierarquia de exceções (geo-block, age-gate, unavailable…)
└── config.py # Loader de ~/.config/vidgrab/config.toml via tomllib
tests/
├── test_downloader.py # _slugify, _classify_error, _format_selector, DownloadConfig
├── test_models.py # VideoMetadata serialization / deserialization
├── test_cli.py # _collect_urls com batch e URLs posicionais
└── test_config.py # config.load com TOML válido, inválido e ausente
English
CLI to download YouTube videos at the highest technically available quality — separate DASH video and audio streams, muxed via FFmpeg with no re-encoding. Built for raw footage in video editing workflows.
How it works
Most download tools re-encode to merge video and audio — degrading quality and wasting time. vidgrab does it differently:
YouTube → video stream (H.264 / VP9 / AV1) ─┐
→ audio stream (AAC / Opus) ─┴→ FFmpeg mux → final file
Both streams are downloaded separately in DASH format (highest quality available) and muxed in copy mode — no transcoding, no quality loss.
Features
| Feature | Detail | |
|---|---|---|
| ⚡ | Parallel downloads | Up to 8 simultaneous via --workers |
| 🔁 | Smart retry | Exponential backoff on rate-limits (up to 5 attempts) |
| 🔍 | Dry run | Preview title, resolution and size before downloading |
| ⏸ | Auto resume | Interrupted downloads pick up where they left off |
| 📋 | Batch download | .txt file with one URL per line |
| 🎬 | Playlists | Expands and downloads every video in a playlist |
| 📁 | Smart skip | Detects existing file by video ID and skips automatically |
| 📄 | JSON metadata | Sidecar .json with title, channel, date, tags and more |
| 🔒 | Restricted content | Cookie support (Netscape format) for age-gated videos |
| ⚙️ | Config file | Personal defaults at ~/.config/vidgrab/config.toml |
| 🏷 | Predictable names | {date}-{slug}-{video_id}.{ext} on every download |
| ⚠️ | License warning | Alerts when a video is not under a Creative Commons license |
External dependencies
| Tool | Purpose | How to install |
|---|---|---|
| Python 3.11+ | Runtime | python.org |
| ffmpeg | Merge video + audio streams | See below |
| yt-dlp | Download engine | Installed automatically via Poetry |
| Deno (optional) | Access all YouTube formats including 4K/HDR | See below |
Installing ffmpeg
Windows
winget install ffmpeg
macOS
brew install ffmpeg
Linux (Debian/Ubuntu)
sudo apt install ffmpeg
Or grab the binary from https://ffmpeg.org/download.html and add it to your PATH.
Installing Deno (recommended for 4K/HDR)
Without Deno, yt-dlp falls back to an alternative extraction method that may not expose all available formats. With Deno, extraction is complete.
Windows
winget install DenoLand.Deno
macOS
brew install deno
Linux
curl -fsSL https://deno.land/install.sh | sh
Installation
Via pip (recommended):
pip install vidgrab
Via pipx (isolated):
pipx install vidgrab
From source (development):
git clone https://github.com/gsjonio/video_grabber.git
cd video_grabber
poetry install
poetry run vidgrab --help
Automated installers:
- Linux/macOS:
bash install.sh - Windows:
install.bat
These scripts check for Python 3.11+ and ffmpeg, then install via pip.
Usage
# Single video — maximum quality
vidgrab https://youtu.be/dQw4w9WgXcQ
# Inspect before downloading (dry run)
vidgrab https://youtu.be/dQw4w9WgXcQ --dry-run
# Cap at 1080p
vidgrab https://youtu.be/dQw4w9WgXcQ --max-height 1080
# Save to a specific directory
vidgrab https://youtu.be/dQw4w9WgXcQ --output ~/Videos/raw
# Download an entire playlist
vidgrab "https://youtube.com/playlist?list=PLxxxx" --playlist
# Download from a .txt file with 5 parallel workers
vidgrab --batch urls.txt --workers 5
# Force re-download even if the file already exists
vidgrab https://youtu.be/dQw4w9WgXcQ --force
# Age-restricted content
vidgrab https://youtu.be/dQw4w9WgXcQ --cookies ~/cookies.txt
# Save metadata as JSON
vidgrab https://youtu.be/dQw4w9WgXcQ --write-json
--batch file format
One URL per line. Lines starting with # are ignored.
# My videos
https://youtu.be/dQw4w9WgXcQ
https://youtu.be/VIDEO_ID_2
Config file
Save your personal defaults at ~/.config/vidgrab/config.toml to avoid repeating flags:
output = "~/Videos/raw"
workers = 5
max_height = 1080
Flags passed on the command line always take precedence over the config file.
Output filename pattern
{upload_date}-{title-slug}-{video_id}.{ext}
Example: 20240315-never-gonna-give-you-up-dQw4w9WgXcQ.mp4
With --write-json, a sidecar .json is saved next to each video:
{
"video_id": "dQw4w9WgXcQ",
"title": "Rick Astley - Never Gonna Give You Up",
"channel": "Rick Astley",
"upload_date": "2009-10-25",
"duration_seconds": 212,
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"description": "...",
"tags": ["pop", "80s"]
}
Container and quality
| Available streams | Output container |
|---|---|
| H.264 + AAC | mp4 (no re-encode) |
| VP9 / AV1 + Opus | mkv (no re-encode) |
The goal is to never re-encode — only mux the streams.
Option reference
| Option | Short | Description |
|---|---|---|
[URLS]... |
One or more YouTube URLs | |
--batch FILE |
-b |
.txt file with one URL per line |
--output DIR |
-o |
Output directory (default: ~/Downloads) |
--max-height INT |
Cap vertical resolution (e.g. 1080) |
|
--playlist |
Treat URLs as playlists | |
--force |
-f |
Re-download even if the file already exists |
--cookies FILE |
Cookies file (Netscape format) | |
--write-json |
Save metadata as a .json sidecar next to the video |
|
--workers INT |
-w |
Parallel downloads (default: 3, max: 8) |
--dry-run |
Show what would be downloaded without downloading | |
--quiet |
-q |
Suppress all output except errors (useful for scripting) |
--version |
-V |
Show version and exit |
--install-completion |
Install shell autocomplete for the current shell | |
--help |
Show help |
Code quality
The project uses a full quality stack, integrated into CI and pre-commit hooks:
| Tool | Role |
|---|---|
| Ruff | Linter + formatter (9 rule categories) |
| Pylint | Advanced static analysis |
| Mypy (strict) | Full type checking — dict[str, Any] at every yt-dlp boundary |
| pytest + pytest-cov | 38 unit tests, coverage reported to Codecov |
| pre-commit | Ruff, Pylint, Mypy and Markdownlint run before every commit |
| GitHub Actions | Lint, tests, CodeQL and automatic release on tag push |
| Dependabot | Weekly updates for Python deps and Actions |
Project structure
vidgrab/
├── cli.py # Typer interface — argument parsing and orchestration
├── downloader.py # Core logic — parallelism, retry, typed error classification
├── models.py # VideoMetadata and DownloadResult as typed dataclasses
├── exceptions.py # Exception hierarchy (geo-block, age-gate, unavailable…)
└── config.py # ~/.config/vidgrab/config.toml loader via tomllib
tests/
├── test_downloader.py # _slugify, _classify_error, _format_selector, DownloadConfig
├── test_models.py # VideoMetadata serialization / deserialization
├── test_cli.py # _collect_urls with batch and positional URLs
└── test_config.py # config.load with valid, invalid and missing TOML
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vidgrab-1.0.0.tar.gz.
File metadata
- Download URL: vidgrab-1.0.0.tar.gz
- Upload date:
- Size: 20.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.14.2 Windows/11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
96dc6539e7e32ab614cfbb3ff0603ec45786e6607adb0d924d28ecc4373459f6
|
|
| MD5 |
e7f66913c0b8ebcdce5681b9617506cf
|
|
| BLAKE2b-256 |
807ca8d2a38e30f80186e256128e383452f816a628829024c88fa990de48113c
|
File details
Details for the file vidgrab-1.0.0-py3-none-any.whl.
File metadata
- Download URL: vidgrab-1.0.0-py3-none-any.whl
- Upload date:
- Size: 18.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.14.2 Windows/11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
705c261e42e5e1516bb6c7d36735c7897c8c60f30708672b0ad0e8a276a0a51b
|
|
| MD5 |
2e2af902ebac295d96f108c46a44ab6c
|
|
| BLAKE2b-256 |
f25db25d71631bef332335815934c4abb746c7eeb0e34f41dc73a887a667ed1e
|