Automatizar Renderização de Vídeos com GitHub Actions
Você tem vídeos que precisam passar pelo mesmo processo toda vez: adicionar intro, watermark, ajustar áudio — e no final fazer upload de volta pro Drive. Fazer isso manualmente num notebook do Colab funciona, mas te prende na frente do computador esperando. Testei e coloquei pra funcionar um pipeline completo usando GitHub Actions + Python + ffmpeg + OAuth do Google que faz tudo isso automaticamente, de graça, sem servidor próprio, e sem abrir o Colab nunca mais. Neste tutorial você vai ver exatamente como montar esse sistema — incluindo os erros que aparecem no caminho e como resolver cada um deles.
A arquitetura é direta: o GitHub Actions sobe um Ubuntu, instala o ffmpeg e as bibliotecas Python, baixa os vídeos do seu Google Drive via Service Account, processa com ffmpeg, e faz o upload do resultado usando OAuth do usuário — porque Service Account não tem cota de armazenamento no Drive pessoal. A planilha do Google Sheets funciona como painel de controle: você escreve rodar numa célula e o engine processa tudo automaticamente na próxima execução.
Por que montar esse pipeline vale o esforço
100% gratuito
GitHub Actions oferece 2.000 minutos/mês para repositórios privados e ilimitados para públicos. Para renderizações periódicas, o plano free nunca esgota.
ffmpeg completo
O runner Ubuntu já tem o ffmpeg disponível. Você usa toda a potência — overlays, filtros de áudio, concat, scale — sem instalar nada localmente.
Planilha como painel
Controla tudo via Google Sheets. Adiciona o nome do arquivo na planilha, escreve "rodar" na célula de trigger e o engine faz o resto — sem código, sem terminal.
Autenticação dupla segura
Service Account para leitura e OAuth do usuário para upload. Chaves armazenadas como Secrets criptografados no GitHub — nunca expostas nos logs.
Sem duplicação
O script checa se o arquivo editado já existe na planilha antes de processar. Rodadas subsequentes pulam o que já foi feito e só processam vídeos novos.
Cron automático
Você define o horário no workflow e o GitHub dispara sozinho. Também tem o botão "Run workflow" para disparar na hora que quiser sem esperar o agendamento.
Como o pipeline funciona do início ao fim
GitHub Actions sobe o ambiente e autentica
No horário agendado (ou pelo botão manual), o GitHub sobe uma máquina Ubuntu, instala Python, ffmpeg e as bibliotecas. Em seguida carrega o credentials.json da Service Account via Secret e os três tokens OAuth (client_id, client_secret, refresh_token) como variáveis de ambiente. O render.py faz dois logins simultâneos: Service Account para ler Drive e Sheets, OAuth para escrever no Drive.
Lê o trigger na planilha e processa os vídeos
O script lê a aba config da planilha e verifica se a célula trigger_colab contém rodar. Se sim, passa para a aba videos, baixa cada arquivo listado que ainda não tem editado, processa com ffmpeg (intro + watermark + corpo + concat) e sobe o resultado para o Drive usando o OAuth do usuário — que tem cota normal de armazenamento.
Atualiza a planilha e encerra limpo
Para cada vídeo concluído, o script preenche as colunas nomedoarquivo_editado e arquivo_disponivel na planilha, grava feito no trigger e remove todos os arquivos temporários do disco. Na próxima execução, esses vídeos são pulados automaticamente.
Para quem esse sistema foi feito
Criadores de conteúdo
Que precisam aplicar intro, marca d'água e ajustes de áudio em lotes de vídeos sem fazer isso manualmente um por um.
Entusiastas de automação
Que já usam o Colab para scripts recorrentes e querem eliminar a dependência de ficar abrindo o navegador para executar.
Desenvolvedores Python
Que querem um exemplo real e testado de integração entre GitHub Actions, Google Drive API, Sheets API e ffmpeg.
Quem quer custo zero
Sem VPS, sem Cloud Run, sem custos mensais. O runner gratuito do GitHub processa os vídeos e encerra — você paga zero.
Tutorial completo: configurando do zero
Passo 1 Estrutura do repositório no GitHub
Crie um repositório no GitHub (público ou privado) e organize assim:
meu-repo/
├─ render.py ← script principal
└─ .github/
└─ workflows/
└─ run_notebook.yml ← workflow do GitHub Actions
Passo 2 Criar a Service Account no Google Cloud
A Service Account é usada para ler arquivos do Drive e acessar a planilha — ela não faz upload. Funciona como uma conta de robô sem interação humana:
- Acesse o Google Cloud Console e crie ou selecione seu projeto.
- Vá em APIs e Serviços → Biblioteca e ative a Google Drive API.
- Ative também a Google Sheets API — sem ela a leitura da planilha falha com erro 403.
- Vá em IAM → Contas de serviço → Criar conta de serviço. Dê um nome (ex:
github-actions-drive). - Na aba Chaves, clique em Adicionar chave → JSON e salve o arquivo.
- Compartilhe sua planilha com o email da Service Account (campo
client_emailno JSON) — papel Editor. - Compartilhe também a pasta raiz do Drive com esse mesmo email — papel Editor.
Passo 3 Criar o OAuth Client para upload no Drive
Service Accounts não têm cota de armazenamento — por isso o upload precisa usar suas credenciais pessoais via OAuth. Veja como configurar:
- No Cloud Console → APIs e Serviços → Credenciais → Criar credencial → ID do cliente OAuth 2.0.
- Tipo: Aplicativo de área de trabalho. Dê um nome e clique em Criar.
- Anote o
client_ide oclient_secretexibidos. - Vá em Tela de permissão OAuth e configure o tipo como Externo.
-
Na aba Usuários de teste, clique em + Adicionar usuários e adicione seu email (ex:
seuemail@gmail.com).
ℹ️ Por que isso é necessário? Enquanto seu app OAuth estiver com status "Testando", o Google só permite que usuários explicitamente cadastrados na lista de teste consigam se autenticar. Se você pular essa etapa e tentar gerar o refresh token, vai receber um erro de acesso negado. O limite é de 100 usuários de teste — mais que suficiente para uso pessoal.
Passo 4 Gerar o refresh token com o setup_oauth.py
Rode este script uma única vez no seu computador local. Ele abre o navegador, você autoriza e ele imprime o refresh token:
pip install google-auth-oauthlib
from google_auth_oauthlib.flow import InstalledAppFlow
CLIENT_ID = "COLE_SEU_CLIENT_ID_AQUI"
CLIENT_SECRET = "COLE_SEU_CLIENT_SECRET_AQUI"
SCOPES = [
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/spreadsheets",
]
client_config = {
"installed": {
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"redirect_uris": ["urn:ietf:wg:oauth:2.0:oob", "http://localhost"],
}
}
flow = InstalledAppFlow.from_client_config(client_config, SCOPES)
creds = flow.run_local_server(port=0)
print("OAUTH_CLIENT_ID :", CLIENT_ID)
print("OAUTH_CLIENT_SECRET :", CLIENT_SECRET)
print("OAUTH_REFRESH_TOKEN :", creds.refresh_token)
O navegador vai abrir pedindo que você faça login com o email cadastrado como usuário de teste. Após aceitar, o terminal imprime os três valores.
Passo 5 Adicionar os Secrets no GitHub
Vá em Settings → Secrets and variables → Actions → New repository secret e adicione:
| Nome do Secret | O que colocar |
|---|---|
GDRIVE_CREDENTIALS | Conteúdo inteiro do arquivo JSON da Service Account |
OAUTH_CLIENT_ID | client_id impresso pelo setup_oauth.py |
OAUTH_CLIENT_SECRET | client_secret impresso pelo setup_oauth.py |
OAUTH_REFRESH_TOKEN | refresh_token impresso pelo setup_oauth.py |
Passo 6 Workflow do GitHub Actions
Crie o arquivo .github/workflows/run_notebook.yml:
name: BVTK Render Engine
on:
workflow_dispatch: # botão Run workflow manual
schedule:
- cron: "0 * * * *" # todo início de hora (UTC)
jobs:
render:
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Instalar ffmpeg
run: sudo apt-get install -y ffmpeg
- name: Instalar dependências Python
run: |
python -m pip install --upgrade pip
pip install \
gspread \
google-api-python-client \
google-auth \
google-auth-oauthlib \
google-auth-httplib2
- name: Salvar credenciais Service Account
run: echo '${{ secrets.GDRIVE_CREDENTIALS }}' > credentials.json
- name: Executar render
env:
OAUTH_CLIENT_ID: ${{ secrets.OAUTH_CLIENT_ID }}
OAUTH_CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }}
OAUTH_REFRESH_TOKEN: ${{ secrets.OAUTH_REFRESH_TOKEN }}
run: python render.py
- name: Remover credenciais do disco
if: always()
run: rm -f credentials.json
Passo 7 Estrutura da planilha Google Sheets
A planilha tem duas abas. A aba config controla o trigger:
| chave | valor |
|---|---|
| trigger_colab | rodar ← escreva isso para processar / o script grava "feito" quando termina |
A aba videos lista os arquivos a processar:
| nomedoarquivo | nomedoarquivo_editado | arquivo_disponivel |
|---|---|---|
| video1.mp4 | ← preenchido pelo script | ← preenchido pelo script |
| video2.mp4 |
Passo 8 Estrutura de pastas no Drive
pasta-raiz/ ← FOLDER_ID no render.py
├─ videosx/ ← assets de processamento
│ ├─ 16X9.mp4 ← intro formato paisagem
│ ├─ 9X16.mp4 ← intro formato retrato
│ ├─ 1X1.mp4 ← intro formato quadrado
│ └─ WATERMARK.png ← marca d'água (PNG com transparência)
├─ video1.mp4 ← vídeos a processar
├─ video2.mp4
└─ video1_editado.mp4 ← resultado (criado pelo script)
/folders/. Exemplo: em drive.google.com/drive/folders/1uy8yhml9ao..., o ID é 1uy8yhml9ao....
Passo 9 Testando o workflow
- Na planilha, aba config, célula B2: escreva
rodar. - No GitHub → aba Actions → clique no workflow → Run workflow.
- Acompanhe os logs em tempo real clicando na execução.
- Ao terminar, os arquivos
_editado.mp4aparecem na pasta raiz do Drive e a planilha é atualizada.
Perguntas frequentes — erros que aparecem e como resolver
Esses são os erros reais que aparecem durante a configuração desse pipeline. Documentei cada um com a causa exata e a solução que funcionou.
drive.mount() e auth.authenticate_user() — que só funcionam dentro do Colab; (b) o workflow usava actions/checkout@v3 e actions/setup-python@v4 com Node 20 que está sendo descontinuado. A solução é usar o render.py puro (sem dependências do Colab) e atualizar para @v4 e @v5 respectivamente.
render.py deste tutorial já implementa essa autenticação dupla: Service Account para download e Sheets, OAuth para upload.
gspread usa a Service Account para acessar a planilha, e a Service Account só consegue abrir planilhas que foram compartilhadas com ela. Verifique o campo client_email no arquivo JSON da Service Account — é um email no formato nome@projeto.iam.gserviceaccount.com. Abra a planilha no Google Sheets, clique em Compartilhar e adicione esse email com permissão de Editor.
videosx dentro da pasta raiz configurada no FOLDER_ID. Esse erro aparece em dois cenários: (a) a subpasta tem nome diferente — o script faz comparação em minúsculas, então VideoSX, VIDEOSX e videosx são tratados iguais, mas videos sem o "x" não encontra; (b) a Service Account não tem acesso à pasta raiz — compartilhe a pasta com o email da Service Account.
anullsrc a 48000Hz) é juntada com o corpo do vídeo (áudio original a 44100Hz). O ffmpeg ajusta os timestamps automaticamente e o arquivo final fica correto. É um aviso cosmético, não um erro — os vídeos renderizados são totalmente utilizáveis.
trigger_colab na aba config não contém exatamente rodar (com minúsculas, sem espaços extras); (b) os vídeos listados na planilha já têm valor na coluna nomedoarquivo_editado — o script pula vídeos que já foram editados; (c) o nome do arquivo na planilha não bate com o nome exato do arquivo no Drive — a comparação é case-sensitive e exata.
Recursos e documentação oficial
Referência completa de workflow syntax, triggers, runners e Secrets.
Upload, download, listagem e gerenciamento de arquivos via código Python.
Leitura e escrita de células, abas e valores via Service Account.
Onde você cria a Service Account, o OAuth Client e ativa as APIs necessárias.
Valide visualmente sua expressão cron antes de colocar no workflow.

Comentários
Comente só assim vamos crescer juntos!