CLI para baixar vídeos individuais e playlists do YouTube em formato de vídeo (MP4) ou áudio (MP3).
- Download de vídeos individuais — Baixa qualquer vídeo do YouTube
- Download de playlists completas — Baixa todos os vídeos de uma playlist
- Escolha de formato — Vídeo (MP4) ou áudio (MP3)
- Organização automática — Downloads organizados em pastas por título
- Deno integrado — Verificação e instalação automática para melhorar extração do YouTube
- FFmpeg integrado — Verificação e instalação automática do FFmpeg
- Interface interativa (TUI) — Navegue com setas ↑↓ e Enter (
inquirer), com output visual colorido (Rich) - Barras de progresso duplas — Progresso da playlist + progresso individual do vídeo com %, velocidade, tamanho e tempo restante
- Testes de integração — Testes reais de download (MP4 e MP3) com isolamento em diretório temporário
- Docstrings completas — Todo o código documentado em português
- Python 3.12+
- uv — Gerenciador de pacotes moderno
- FFmpeg — Instalado automaticamente pelo script se necessário
- Deno (opcional) — Instalado automaticamente; melhora extração de formatos do YouTube
# Windows (via winget)
winget install --id=astral-sh.uv
# Linux/macOS
curl -LsSf https://astral.sh/uv/install.sh | shAbra seu terminal e execute:
curl -fsSL https://raw.githubusercontent.com/silv4b/yt-pl-downloader/main/install.sh | bashAbra o PowerShell e execute:
irm https://raw.githubusercontent.com/silv4b/yt-pl-downloader/main/install.ps1 | iex-
Clone o repositório:
git clone https://github.com/silv4b/yt-pl-downloader.git cd yt-pl-downloader -
Instale as dependências:
uv sync
uv run python main.pyO projeto combina inquirer para navegação com setas e Rich para output visual.
╭──────────────────────────────────────╮
│ YouTube Downloader │
╰──────────────────────────────────────╯
? O que deseja fazer?: (Use ↑↓ e Enter)
Baixar vídeo individual
> Baixar playlist completa
Sair
Durante o download, uma barra de progresso é exibida:
⠴ video: Meu Vídeo Legal ━━━━━━━━━━━━━━━━━━━━━━━╸━━━ 72.1/76.3 MiB 7.4 MB/s 0:00:01
- Selecione "Baixar vídeo individual" com ↑↓ e
Enter - Cole a URL do vídeo e
Enter - Selecione Vídeo (MP4) ou Áudio (MP3) com ↑↓ e
Enter - Barra de progresso aparece durante o download
- Salvo em
downloads/downloaded_videos/<titulo>/<video|audio>/
- Selecione "Baixar playlist completa" com ↑↓ e
Enter - Cole a URL da playlist e
Enter - Selecione Vídeo (MP4) ou Áudio (MP3) com ↑↓ e
Enter - Barra de progresso mostra avanço vídeo a vídeo
- Salvo em
downloads/downloaded_playlists/<titulo>/<video|audio>/
yt-pl-downloader/
├── main.py # Entry point (CLI)
├── pyproject.toml # Configuração do projeto
├── config.yaml # Configurações de paths e defaults
│
├── app/
│ ├── cli/ # Interface de linha de comando
│ │ └── menu.py # Prompts interativos e output visual
│ │
│ ├── core/ # Infraestrutura
│ │ ├── config.py # DownloadConfig centralizado (YAML)
│ │ ├── ffmpeg_utils.py # Verificação e instalação do FFmpeg
│ │ ├── deno_utils.py # Verificação e instalação do Deno
│ │ ├── logger.py # Logging estruturado
│ │ └── utils.py # Utilitários (sanitize, etc)
│ │
│ ├── models/ # Modelos de dados
│ │ ├── video.py # VideoInfo
│ │ └── playlist.py # PlaylistInfo
│ │
│ ├── services/ # Lógica de download
│ │ ├── downloader.py # Classe base abstrata + hooks
│ │ ├── video_downloader.py # Download de vídeo único
│ │ └── playlist_downloader.py # Download de playlist
│ │
│ └── exceptions.py # Exceções customizadas
│
└── tests/ # Testes com pytest
├── test_core/
│ ├── test_config.py # Config e carregamento YAML
│ └── test_utils.py # Sanitização de nomes
├── test_models/
│ └── test_models.py # VideoInfo e PlaylistInfo
└── test_integration/
└── test_downloads.py # Downloads reais (MP4/MP3)
# Instalar dependências
uv sync
# Executar o projeto
uv run python main.py
# Rodar testes unitários
uv run pytest -m "not integration"
# Rodar todos os testes (inclui integração com downloads reais)
uv run pytest tests/ -v
# Rodar apenas testes de integração
uv run pytest -m integration
# Pular testes de integração (útil para CI rápido)
SKIP_INTEGRATION=1 uv run pytest tests/ -v
# Executar linter
uv run ruff check .
# Formatar código
uv run ruff format .
# Adicionar nova dependência
uv add <pacote>
# Adicionar dependência de desenvolvimento
uv add --dev <pacote>O projeto inclui um script de build que configura automaticamente todas as opções do PyInstaller necessárias:
# Gerar executável para a plataforma atual
uv run python build.pyO script automaticamente:
- Limpa builds anteriores (
build/,dist/) - Detecta a plataforma e adiciona o sufixo correto (
-winou-linux) - Empacota todas as dependências (
yt-dlp,Rich,inquirer,PyYAML,readchar) - Inclui metadados necessários para evitar erros de importação
O executável será criado em dist/:
- Windows:
dist/yt-pl-downloader-win.exe(~25 MB) - Linux:
dist/yt-pl-downloader-linux
Se preferir usar PyInstaller diretamente, use estes parâmetros:
uv run pyinstaller --onefile \
--name yt-pl-downloader \
--collect-all yt_dlp \
--collect-all rich \
--hidden-import inquirer \
--hidden-import yaml \
--hidden-import readchar \
--copy-metadata readchar \
--copy-metadata inquirer \
main.pyImportante: As flags
--copy-metadata readchare--copy-metadata inquirersão essenciais. Sem elas, o executável falha ao iniciar comPackageNotFoundError.
# Dar permissão de execução
chmod +x dist/yt-pl-downloader-linuxO projeto possui GitHub Actions para build automático em Windows e Linux. Ao criar uma tag com o formato v*, o build é disparado automaticamente:
git tag v0.2.0
git push origin v0.2.0- O FFmpeg é necessário para conversão de formatos. O projeto verifica e oferece instalação automática
- O Deno é opcional mas recomendado: melhora a extração de formatos do YouTube, permitindo acesso a mais resoluções
- Sem o Deno, alguns vídeos podem não estar disponíveis na melhor qualidade; a opção de instalar aparece no menu
- Os downloads são organizados automaticamente em
downloads/ - Títulos de vídeos e playlists são sanitizados para nomes de pasta válidos
- Em playlists, vídeos falhos são pulados e o download continua
- Os testes de integração realizam downloads reais; use
SKIP_INTEGRATION=1para ignorá-los
MIT
- Baseado em yt-dlp