Pequena ferramenta de linha de comando que baixa legendas automáticas em português de vídeos do YouTube, transforma-as em texto corrido legível, detecta o formato do vídeo (filme / entrevista / outro) e prepara um sumário — usando um LLM (qualquer endpoint compatível com a API da OpenAI) ou, na falta de credenciais, um template para preenchimento manual.
Pensado para apoiar trabalho de sala de aula, pesquisa e arquivamento de conteúdo audiovisual: a partir de uma URL, o usuário obtém uma transcrição limpa em prosa e um sumário (automático ou template) estruturado conforme o formato detectado.
Idiomas de legenda configuráveis (
ptpor padrão). O texto de saída acompanha o idioma da legenda.
O pipeline tem quatro estágios independentes — cada um pode ser executado isoladamente e re-aproveita artefatos já baixados.
| Estágio | Entrada | Saída | Descrição |
|---|---|---|---|
download |
URL do YouTube | output/<ID>.<lang>.vtt |
Baixa apenas as legendas automáticas (sem o vídeo), via yt-dlp. |
clean |
.vtt |
output/<ID>.<lang>.txt |
Limpa marcações VTT, remove duplicatas de rolagem, une linhas curtas em parágrafos legíveis. |
detect |
metadados do vídeo | rótulo filme / entrevista / outro |
Heurística por palavras-chave em título e descrição, com regra especial para transmissões ao vivo. |
summarise |
metadados + formato + texto | output/<ID>.<lang>.summary.md |
Se um endpoint LLM compatível com OpenAI estiver configurado, gera o sumário final via API; caso contrário, emite um template com placeholders para preenchimento manual. |
ℹ️ Sobre o estágio
summarise: quando o LLM está configurado (OPENAI_BASE_URL+OPENAI_API_KEY, ou as flags--llm-base-url/--llm-api-key), o sumário é produzido automaticamente. Sem credenciais, o estágio emite um template com marcadores a preencher. As regras de conteúdo por formato estão descritas abaixo.
- Entrevista: resumo dos principais pontos levantados, com contexto dos entrevistados e do meio de comunicação (canal do vídeo).
- Filme: busca externa de sinopses e críticas; levantamento de pontos para uso em sala de aula e de fragilidades/críticas a pontos fracos.
- Outro: sem template específico; revisão manual.
- Python 3.10+ (usa
list[str],Path | None,from __future__ import annotations). - yt-dlp — recomendada a versão mais recente (via
pip/conda). Versões antigas, como a empacotada em algumas distribuições Linux, falham em vídeos atuais do YouTube com erros do tipoRequested format is not availableouDid not get any data blocks, causados pelo novo streaming SABR e pela flagxpedo timedtext. - Navegador com sessão ativa no YouTube (opcional, mas necessário para muitos vídeos). O padrão é ler cookies do Chrome (
--cookies-from-browser chrome); Firefox também funciona.
Versões antigas do yt-dlp (como as empacotadas em algumas distribuições Linux via apt) falham em vídeos atuais do YouTube com erros do tipo Requested format is not available ou Did not get any data blocks, causados pelo novo streaming SABR e pela flag xpe do timedtext. Por isso, prefira instalar a versão mais recente por um gerenciador atualizado:
# Via pip (qualquer ambiente)
pip install -U yt-dlp
# Via conda
conda install -c conda-forge yt-dlpO estágio summarise produz o sumário automaticamente se houver um endpoint LLM compatível com a API Chat Completions da OpenAI configurado. Funciona com a própria OpenAI, com serviços autodomesticáveis (Ollama, vLLM, LM Studio), com provedores nacionais/regionais e com qualquer gateway que fale esse protocolo. Sem credenciais, cai graciosamente num template para preenchimento manual.
A configuração pode ser feita por variáveis de ambiente (recomendado) ou por flags na linha de comando:
| Item | Variável de ambiente | Flag CLI | Padrão |
|---|---|---|---|
| URL-base da API | OPENAI_BASE_URL |
--llm-base-url |
vazio (ex.: https://api.openai.com/v1) |
| Chave de API | OPENAI_API_KEY |
--llm-api-key |
vazio |
| Modelo | OPENAI_MODEL |
--llm-model |
gpt-4o-mini |
| Máx. de tokens da resposta | OPENAI_MAX_TOKENS |
--llm-max-tokens |
2000 |
| Timeout (s) | OPENAI_TIMEOUT |
--llm-timeout |
180 |
Exemplos:
# OpenAI oficial
export OPENAI_API_KEY="sk-..."
python3 yt_sumarios.py "<url>" --stage summarise
# Provedor compatível qualquer
export OPENAI_BASE_URL="https://llm.exemplo.com/v1"
export OPENAI_API_KEY="..."
export OPENAI_MODEL="meu-modelo"
python3 yt_sumarios.py "<url>"
# Tudo via flags (sem alterar o ambiente)
python3 yt_sumarios.py "<url>" --stage summarise \
--llm-base-url "https://llm.exemplo.com/v1" \
--llm-api-key "..." \
--llm-model "meu-modelo"A implementação usa apenas a stdlib (urllib.request), sem nenhuma dependência adicional. As instruções enviadas ao modelo variam conforme o formato detectado (entrevista/filme/outro), conforme as regras abaixo. Se a chamada ao LLM falhar (rede, auth, contexto excedido), o estágio avisa no stderr e grava o template.
⚠️ Vídeos longos: um vídeo de ~107 min gera ~90 KB de transcrição. Verifique se o modelo escolhido tem janela de contexto suficiente, ou use um modelo de contexto longo.
python3 yt_sumarios.py "https://www.youtube.com/watch?v=<ID>"Executa os quatro estágios em sequência e grava os três artefatos em output/.
python3 yt_sumarios.py "<url>" --stage download # só baixa a legenda
python3 yt_sumarios.py "<url>" --stage clean # limpa o .vtt existente
python3 yt_sumarios.py "<url>" --stage detect # só classifica o formato
python3 yt_sumarios.py "<url>" --stage summarise # gera o sumário (LLM) ou template .md# Mudar o idioma da legenda (default: pt)
python3 yt_sumarios.py "<url>" --lang en
# Mudar o diretório de saída (default: output/)
python3 yt_sumarios.py "<url>" --work /tmp/ytO módulo clean_subtitle.py também roda sozinho sobre qualquer arquivo .vtt:
python3 clean_subtitle.py entrada.vtt -o saida.txtyt_sumarios.py # Orquestrador com 4 estágios, cada um executável isoladamente
└── clean_subtitle.py # Limpeza pura de VTT -> texto corrido (importado pelo orquestrador)
output/ # Artefatos por vídeo: <ID>.<lang>.vtt, .<lang>.txt, .<lang>.summary.md
fetch_metadata(url)→VideoInfo(título, canal, duração, categorias, descrição)download_subs(url)→output/<ID>.<lang>.vttclean_vtt_file(vtt)→output/<ID>.<lang>.txt(prosa corrida, parágrafos por minuto)detect_format(info)→"filme" | "entrevista" | "outro"summarise(info, fmt, txt)→output/<ID>.<lang>.summary.md(sumário via LLM, se configurado; caso contrário, template)
Legendas automáticas do YouTube vêm com:
- marcações de karaokê (
<c>...</c>, timestamps inline); - linhas duplicadas a cada rolagem (scroll-in: cada cue repete a linha anterior e acrescenta conteúdo novo);
- marcadores de mudança de locutor (
>>,>>).
O limpador, em ordem: remove marcações, converte linhas de timestamp HH:MM:SS.mmm --> ... em marcadores HH:MM, descarta o cabeçalho VTT, remove duplicatas atravessando fronteiras de timestamp e une parágrafos curtos em blocos legíveis (~320 caracteres), preferindo pontos de fim de frase.
Para cada vídeo, em output/:
| Arquivo | Conteúdo |
|---|---|
<ID>.<lang>.vtt |
Legenda original baixada. |
<ID>.<lang>.txt |
Transcrição limpa em prosa corrida (produto principal). |
<ID>.<lang>.summary.md |
Sumário (via LLM, se configurado) ou template estruturado pelo formato detectado. |
- Chrome fechado: em alguns sistemas o
--cookies-from-browser chromeprecisa que o Chrome esteja fechado (o yt-dlp lê o banco SQLite de cookies). Se falhar, tentefirefox— perfis do Firefox também funcionam. - Qualidade das legendas automáticas: legendas
kind=asr(reconhecimento de fala) têm qualidade variável; espere erros de transcrição (nomes próprios, siglas). O limpador não faz correção ortográfica. - Vídeos longos: um vídeo de ~107 min gera ~90 KB de
.txt. Para sumarização por LLM considere chunking ou um modelo de contexto longo. - Detecção de formato: heurística por palavras-chave (listas
FILME_KEYWORDS,ENTREVISTA_KEYWORDSno topo deyt_sumarios.py). Transmissões ao vivo nunca são classificadas como filme. Para melhorar a detecção, estenda as listas em vez de adicionar checagens inline.
Distribuído sob a licença MIT. Veja o arquivo LICENSE.
A única dependência externa em runtime é o yt-dlp, que é Unlicense (domínio público) e é invocado via subprocess — portanto sem acoplamento de licença. Todo o código do projeto usa apenas a biblioteca padrão do Python (licença PSF).