Communitygithub.com

binay-py/event-recap-video

Transforme uma pilha de fotos e vídeos de um evento (conferência, viagem, retiro, casamento) em um vídeo de resumo chamativo com ffmpeg — uma versão principal 16:9, uma versão 9:16 e um reel sincronizado com a batida de ~45 s. Use quando o usuário quiser um vídeo de resumo/destaque/montagem a partir de suas próprias gravações.

O que é event-recap-video?

Este skill automatiza a criação de vídeos de resumo de eventos a partir de fotos e vídeos pessoais, utilizando ffmpeg para renderização e Python para análise e edição. Ele suporta três saídas principais: um corte horizontal 16:9, um vertical 9:16, e um reel de ~45 segundos sincronizado com batida (ideal para Instagram/TikTok). O skill gerencia todo o pipeline: extração de mídia (incluindo Google Photos via CDP), análise de metadados (EXIF, blur, duplicatas, loudness), edição baseada em regras (hook frio, alternância de músicas, ducking de áudio), e pós-processamento com equalização e normalização de loudness. É testado em bibliotecas de até 780 itens e requer ffmpeg/ffprobe no PATH, Python 3.10+ e algumas dependências Python. O skill é ideal para desenvolvedores e criadores de conteúdo que desejam automatizar a produção de vídeos de eventos de alta qualidade sem edição manual.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/binay-py/claude-skills/tree/HEAD/skills/event-recap-video

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Vídeo de resumo de evento

Testado de ponta a ponta em uma biblioteca de 780 itens. Requer ffmpeg/ffprobe no PATH e Python 3.10+ com pip install pillow pillow-heif numpy.

Os scripts ficam ao lado deste arquivo. Copie para o projeto:

  • scripts/analyze.py, build.py, reel.py, motion.py, fonts.py → raiz do projeto
  • scripts/work/*.py → <project>/work/
  • examples/*.json → raiz do projeto, depois edite-os

Estrutura do projeto: raw/ (originais intocados), music/, work/ (cache), output/, edit.json (a edição completa). As fontes são encontradas automaticamente no Windows/macOS/Linux; sobrescreva com FONT_SERIF, FONT_SERIF_BOLD, FONT_SANS_BOLD, FONT_BLACK, FONT_EMOJI.

1. Obter mídia

  • Coloque cada exportação/zip em sua própria pasta em raw/. Nunca modifique os originais.
  • O Google Photos não tem API para uma biblioteca existente: conduza o navegador logado do usuário via CDP (veja o skill brave-cdp neste repositório). Itens da grade são a[href*="/photo/"]; cabeçalhos de dia são [role=checkbox][aria-label^="Select all photos from"].
  • Selecione cabeçalhos de dia com eventos reais de mouse (Input.dispatchMouseEvent), verifique o texto "N selected", pressione Shift+D. A aba deve estar em primeiro plano (Page.bringToFront) ou a grade fica cinza.
  • O Google limpa a seleção após um download e o aria-checked do cabeçalho pode ficar desatualizado; recarregue antes de reselecionar.
  • Browser.setDownloadBehavior com allowAndName salva o zip sob seu GUID sem extensão; monitore Browser.downloadProgress para completed.

2. Analisar e selecionar

  • python analyze.py → work/media.json (hora de captura do EXIF / creation_time do vídeo no fuso local, desfoque, brilho, duplicatas, loudness) + contatos por dia em work/sheets/.
  • python work/vsheets.py → tiras de 3 quadros por vídeo. VEJA cada folha. Pule clipes que giram durante a gravação, gravações de bolso e clipes noturnos escuros.
  • python work/loudest.py ID:seconds ... encontra a janela mais alta (canto, fala, comemoração). Verifique com uma tira de quadros de 1 fps antes de cortar.
  • Arquivos compartilhados/encaminhados não têm data de captura (recua para mtime do arquivo) — posicione-os visualmente.

3. Edição (o que o público gostou)

  • Comece com VÍDEO (~90% dos clipes); fotos apenas para fotos fortes de grupo. Cortes com muitas fotos parecem lentos.
  • Hook de abertura fria: 8–10 clipes de 1,2–1,8 s, hook_xf 0,1 cortes quase secos, depois o cartão de título. Em seguida, dias em ordem com um pequeno "label": "Dia N · data" no primeiro clipe de cada dia, cortes de 3–4 s, e alguns momentos de 9–12 s marcados com "speech": true (a música diminui sob eles).
  • A música faz ou quebra o hook. Encadeie 2 faixas de ritmo semelhante ("music": [a, b], crossfade de 3 s) em vez de repetir uma. python work/bpm.py arquivo.mp3 estima o ritmo.
  • Chaves do edit.json: title, subtitle, closing, closing_sub, title_bg / closing_bg (+ _bg_at para ids de vídeo), music / vertical_music, music_volume, duck_volume, ambient_volume, photo_seconds, hook_xf, closing_seconds, horizontal_hook, horizontal, vertical_hook, vertical. Segmento: {"id", "at" (centro 0–1) | "start", "dur", "speech", "label", "xf"}.
  • python work/shortlist.py → output/shortlist.jpg (um quadro em cada corte). Mostre ao usuário antes de renderizar.

4. Renderizar e QC

  • python build.py [horizontal|vertical|vertical-full] — cache por segmento em work/seg, cadeia xfade, loudnorm −14 LUFS, x264.
  • EDIT=outro.json OUT_SUFFIX=-v2 python build.py renderiza uma edição alternativa sem mexer na principal.
  • QC de cada renderização: nb_frames == duration*30 (cadeias xfade podem perder quadros), contagem blackdetect 0, ebur128 ≈ −14 LUFS, e uma folha de tiles de quadros (fps=1/5,tile=8x6) para verificar rotação e títulos cortados.
  • ffmpeg 7+ prefere -/filter_complex file em vez do obsoleto -filter_complex_script.

5. Reel sincronizado com batida (IG / TikTok / FB) — reel.py + reel.json

  • python reel.py → output/reel.mp4 (~45 s), construído sobre o renderizador de segmentos do build.py.
  • Os cortes caem exatamente na grade de batidas (dica bpm, fase automática, tempos de corte arredondados por quadro). Verifique o ritmo: estimativas ingênuas geralmente retornam metade/dobro (85 vs 154).
  • Primeiro segundo = o momento mais surpreendente, com uma linha "POV: …". Cortes de 4 batidas, 6-8 batidas em momentos heroicos, zoom lento para dentro em cada clipe, flash branco no início das seções.
  • Texto: sem serifa pesada, branco com contorno preto grosso, ~24% do topo (livre dos botões do TikTok/IG), fade up com deslizamento. 5–7 linhas curtas no total; a última é o nome do evento.

6. Corte de meme / motion — motion.py + motion.json (apenas quando o usuário pedir memes/stickers)

  • Muitas pessoas acham esse estilo exagerado para um evento emocionante. Padrão para seções 3–5.
  • Uma faixa longa e constante (~3 min) em vez de encadeamento; grade de batida via busca de filtro comb.
  • Por clipe: beats, speed (0,5 câmera lenta / 2 avanço rápido), freeze (batidas; parada de fita + silêncio + dessaturar), adesivo cap (caixa arredondada, inclinação, pop elástico, emoji colorido), títulos day com quem e woosh, title, verse, shake, punch, flash, zoom.
  • Se uma renderização for morta, exclua os arquivos de clipe que falham no ffprobe antes de reexecutar (o cache os reutilizaria).

7. Entrega vertical e social

  • Quando alguém aprovar a edição 16:9 e pedir 9:16, entregue a MESMA edição vertical (python build.py vertical-full). Não reformate uma edição aprovada; "torná-la mais atraente" significa apenas polimento.
  • Plataformas (especialmente Facebook) silenciam posts com música não licenciada. Ofereça uma versão com som original (uma edição com "music": null) e/ou uma cópia silenciosa (ffmpeg -i in.mp4 -an -c copy out.mp4) para que a música possa ser adicionada da biblioteca licenciada da plataforma.
  • Polimento final: eq=contrast=1.07:saturation=1.2:gamma=0.97,colorbalance=rm=0.03:bm=-0.03:rh=0.02:bh=-0.02,unsharp=5:5:0.45,vignette=angle=PI/5.5 + áudio highpass=80,dynaudnorm,acompressor,loudnorm=I=-14.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Habilidades Relacionadas