Pitch: Transformando vídeos do Youtube e X/Twitter de horas em artigos que dá pra ler
Disclaimer: construí este projeto para testar conceitos e técnicas de desenvolvimento com o Claude Code e aplicar na prática os conhecimentos que venho adquirindo. É um laboratório pessoal que acabou virando algo útil pra mim, e documento aqui para quem estiver interessado em como um pipeline assim se monta na prática.
Vídeo longo é um formato hostil pra quase tudo que não seja assistir do começo ao fim, sentado. Um podcast de 2, 3, 4 horas no YouTube é díficil de ser consumido até para assuntos interessantes.
Vídeo é pior ainda pra:
- Pesquisar: Ctrl+F não existe. Achar "o trecho onde o fulano falou sobre X" requer navegar timestamps manualmente.
- Citar: link com timestamp resolve mal, e transcrever é trabalhoso.
- Reler: não tem marcador visual, não tem progresso, não tem seções nomeadas.
- Skim: não dá pra bater o olho e decidir se vale o investimento de tempo.
Artigo resolve tudo isso. Mas quase nenhum podcast tem versão escrita decente, e legendas automáticas do YouTube são ilegíveis — paredão de texto sem pontuação, cheio de "é, tipo, né, então".
O objetivo do projeto
Vídeo to text é transformar vídeos do YouTube ou Twitter/X em artigos organizados por seções temáticas.
Cada artigo tem:
- Título e subtítulo limpos
- Índice clicável
- Seções temáticas (não cronológicas — reorganizadas por assunto)
- Barra de progresso de leitura
- "Continuar de onde parou" salvo por dispositivo
- Sidebar de referências: livros citados linkados no Amazon, ferramentas com site oficial, pessoas com Twitter, conceitos com Wikipedia, posts relacionados
- Switcher de idioma PT/EN no header
Zero framework. HTML estático servido no GitHub Pages. Carrega rápido em qualquer coisa, inclusive 3G sofrido.
A pipeline
URL do vídeo (YouTube ou Twitter/X)
↓
Detecta provider pela URL
↓
YouTube: youtube-transcript-api (legendas oficiais quando existem)
Twitter/X: yt-dlp baixa áudio → mlx-whisper transcreve local
↓
Transcrição bruta em inglês (ou idioma original do vídeo)
↓
Claude (organização): lê transcrição, remove "né", "tipo", timestamps,
sponsor reads, reorganiza em seções temáticas,
produz texto natural em PT-BR e em EN
↓
Python gera HTML com JSON-LD, Open Graph, hreflang, sidebar de referências
↓
Git commit + push → GitHub Pages publica
Sem CMS, sem banco de dados, sem etapa de build em frontend. O script src/build_html.py tem ~400 linhas de Python puro e escreve HTML semântico direto:
return f'''<!DOCTYPE html>
<html lang="{html_lang}">
<head>
<link rel="alternate" hreflang="pt-BR" href="{pt_href}">
<link rel="alternate" hreflang="en" href="{en_href}">
<script type="application/ld+json">{jsonld}</script>
<link rel="stylesheet" href="../../css/style.css">
</head>
<body class="page-article">
<header class="site-header">...</header>
<article class="container">
<h1>{title}</h1>
<nav><h3>Conteúdo</h3><ol>{toc_html}</ol></nav>
{body_html}
</article>
{references_sidebar}
</body>
</html>'''
O Whisper local
Pra vídeos do Twitter/X (ou YouTube quando a legenda oficial está bloqueada) o pipeline usa mlx-whisper — a implementação MLX do Whisper, otimizada nativa pro Apple Silicon. Custo de transcrição: zero. Velocidade: ~5× real-time num M1 Pro. Um podcast de 1 hora transcreve em uns 12 minutos.
import mlx_whisper
result = mlx_whisper.transcribe(
audio_path,
path_or_hf_repo="mlx-community/whisper-large-v3-turbo",
word_timestamps=False,
)
Em Linux ou Windows dá pra trocar por faster-whisper (CTranslate2), mesma ideia. O importante é não mandar áudio pra API de ninguém — Whisper rodando local é bom o suficiente e é grátis.
Markdown para agentes
A Cloudflare tem uma feature chamada Markdown for Agents que converte HTML em Markdown na edge quando um agente de IA faz a requisição com Accept: text/markdown. Essa feature só existe no plano pago (Pro ou Business).
Dá pra replicar em ~150 linhas de JavaScript rodando no plano Free (100k requests/dia) do Cloudflare Workers. HTMLs bem estruturados não precisam de nada muito sofisticado — regex resolve:
export default {
async fetch(request) {
const accept = request.headers.get("Accept") || "";
if (!accept.includes("text/markdown")) {
return fetch(request); // passa HTML direto pra humanos
}
// Agente pediu markdown. Busca HTML do origin e converte.
const response = await fetch(new Request(request.url, {
headers: { Accept: "text/html" }
}));
const html = await response.text();
const articleHtml = html.match(/<article[^>]*>([\s\S]*?)<\/article>/i)?.[1];
const markdown = htmlToMarkdown(articleHtml);
return new Response(frontmatter + markdown, {
headers: {
"Content-Type": "text/markdown; charset=utf-8",
"x-markdown-tokens": String(Math.ceil(markdown.length / 4)),
"Vary": "Accept",
}
});
}
};
Resultado: um HTML de artigo que custa ~53.000 tokens pra um agente parsear vira ~13.000 tokens em Markdown — redução de 75%. Sem Turndown, sem JSDOM (nenhum dos dois roda em Worker runtime), só regex e uns cuidados com <pre> e <code>.
Dá pra testar:
# Humano recebe HTML
curl -sI https://adhenawer.net/posts/original/state-ai-2026.html | grep -i content-type
# content-type: text/html; charset=utf-8
# Agente recebe Markdown
curl -s https://adhenawer.net/posts/original/state-ai-2026.html \
-H "Accept: text/markdown" | head -10
# ---
# title: "The State of AI in 2026"
# lang: en
# ---
# ## THE NOVEMBER INFLECTION POINT
# ...
Referências extraídas automaticamente
Cada artigo tem uma sidebar fixa com referências extraídas da transcrição. Categorias:
- Livros → busca no Amazon
- Ferramentas → site oficial
- Papers → arXiv ou blog do autor
- Pessoas → Twitter/X (prioridade), fallback pra Wikipedia
- Conceitos → Wikipedia
- Empresas → site oficial
- Posts relacionados → cross-link interno pro mesmo tema em outros artigos
A extração é feita por subagentes do Claude em paralelo — um por artigo, cada um recebe a transcrição e devolve um JSON estruturado:
{
"video_id": "...",
"books": [
{
"title": "Functional Programming in Scala",
"author": "Paul Chiusano & Rúnar Bjarnason",
"url": "https://www.amazon.com/s?k=functional+programming+in+scala+chiusano",
"context": "..."
}
],
"people": [
{
"name": "Boris Cherny",
"role": {"pt": "Chefe do Claude Code, Anthropic", "en": "Head of Claude Code, Anthropic"},
"url": "https://twitter.com/bcherny"
}
],
"related_posts": [
{
"slug_pt": "...",
"slug_en": "...",
"reason": {"pt": "...", "en": "..."}
}
]
}
Fluxo dentro do Claude Code
O projeto roda dentro do Claude Code (a CLI oficial da Anthropic). No terminal, dentro do repo:
> adiciona artigo de https://youtu.be/VIDEO_ID
O agente executa o pipeline sozinho: busca transcrição, organiza em seções, traduz pra PT-BR, gera o HTML, atualiza o docs/index.html, atualiza o sitemap.xml, extrai referências, commita e faz push. Revisão do diff fica por conta do humano.
Isso funciona por dois motivos:
CLAUDE.md: um arquivo markdown na raiz que contém a base de conhecimento do projeto (convenções, estrutura de pastas, formato de slug). Funciona como memória persistente entre sessões.- Subagentes para paralelismo: tarefas que podem ser quebradas em unidades independentes (como extrair referências de N artigos) rodam em subagentes paralelos com contexto isolado. Main context não é poluído.
Stack completo
| Camada | Tecnologia |
|---|---|
| Interface | Claude Code (CLI) |
| Modelo | Claude Opus 4.6 (plano Max da Anthropic) |
| Transcrição YouTube | youtube-transcript-api |
| Transcrição Twitter/X | yt-dlp + mlx-whisper |
| Organização/tradução | Claude |
| Build HTML | Python puro (~400 linhas) |
| Frontend | HTML estático, CSS em um arquivo |
| Hosting | GitHub Pages |
| Domínio + CDN | Cloudflare (Free) |
| Edge / agentes | Cloudflare Worker (Free) — Markdown on demand |
| Analytics | Umami Cloud (Free tier) |
Infraestrutura sem custo mensal. O único gasto recorrente é a assinatura Claude Max, que já uso para outras coisas — o projeto é um consumidor a mais dessa cota.
O que tem de aberto
Código todo em github.com/adhenawer/video-to-text:
src/pipeline.py— orquestrador de ponta a pontasrc/providers/— abstração multi-provider (YouTube, Twitter/X). Adicionar um novo provider (Vimeo, TikTok) exige implementardetect(url),extract_id(url)efetch_transcript(url).src/build_html.py— geração de HTMLworkers/markdown-agent/src/index.js— Worker do Cloudflaretranscripts/— transcrições originais + traduzidas + JSONs de referências
Artigos
O índice completo de artigos está em adhenawer.net (PT-BR) e adhenawer.net/en/ (inglês).