Bot Telegram · fila de vídeos

Uma linha no Telegram vira um vídeo na fila

@inemaccvbot é o cliente fino da fila mkivideos: manda instrução em texto, ele enfileira, avisa quando termina e entrega o MP4 — sem renderizar nada por conta própria.

inemaccvbot — bot Telegram cliente da fila mkivideos
O que é

Cliente fino, não motor de fila

O inemaccvbot não renderiza vídeo nenhum. Ele traduz mensagens do Telegram em jobs para a fila mkivideos (daemon systemd já rodando), acompanha o andamento e entrega o resultado — nunca cria conteúdo fora de uma skill registrada.

📋 Uma linha, um job

Cada linha da mensagem vira uma instrução independente — várias linhas enfileiram vários vídeos de uma vez.

🔒 Skills registradas só

Instrução que não mapeia para explicativo, curso ou demo é recusada com explicação — o bot enfileira o que consegue mapear e avisa o que não vai fazer.

🔐 Allowlist silenciosa

Só chat ids em ALLOWED_CHAT_IDS são atendidos; qualquer outro é ignorado em silêncio e logado.

Como funciona

Telegram → fila → notificação

O parser tenta primeiro o formato leve (uma linha por job); texto fora do padrão cai no fallback claude -p (Opus, esforço médio), que só traduz — nunca pesquisa nem renderiza.

Fluxo do inemaccvbot: Telegram → bot (fino) → fila mkivideos → 4 caminhos de skill → destino → notificação de volta este repo (inemaccvbot) externo — fila e render (mkivideos) Você Telegram 1 linha = 1 job, ou texto livre inemaccvbot allowlist → parser ou Claude (livre) ping() → mkivideos add nunca renderiza Fila mkivideos daemon systemd serializa (1x) explicativo · curso · demo agente claude -p usa video-explicativo / videos-cursos-inema / video-demonstrativo + pesquisa web / narração (opcionais) transcrever · dublar delega direto pro inemavox transcrever_v1.py → .txt/.srt dublar_pro_v5.py → .mp4 dublado fila "texto" (não é vídeo) reel skill reel-edita-inema reel 9:16 empilhado a partir de avatar HeyGen (topo · avatar · explicativo) input = caminho do avatar.mp4 reelinematds skill reel-edita-inematds reel pessoal produzido: corte + PiP/ B-roll real ou gerado + legendas grandes + cold open + CTA inema.club input = caminho do bruto.mp4 · revisor obrigatório Destino livesN, ou pasta padrão da skill (MP4/TXT/SRT) watcher.ts do bot faz poll a cada 60s e notifica de volta (nome, caminho, duração, destino, narração/transcrição ou motivo da falha) reel e reelinematds são sempre CÓPIA por padrão — nunca movidos, o original fica intacto

🔎 pesquisa

Não roda no bot — só anexa uma instrução ao job. É o agente de render do mkivideos que pesquisa a web antes de escrever o roteiro (só nas skills de vídeo: explicativo/curso/demo).

📝 narração/texto

O bot escolhe um caminho em NARRACOES_DIR e pede ao agente para salvar ali a narração completa; o watcher entrega o arquivo (mensagem ou documento) quando o job termina.

🎯 livesN

Ao terminar, o watcher move (skills de vídeo/inemavox) ou copia (reel/reelinematds, que preservam o original em ~/projetos/output/.../<slug>/) o resultado pra ~/projetos/yt-pub-livesN/imports/videos.

🎬 reel vs reelinematds

reel monta um reel empilhado (headline + avatar + explicativo) a partir de um avatar HeyGen já pronto. reelinematds converte um bruto vertical seu (rosto falando, gravado sem edição) num reel produzido do zero — corte, tratamento visual, B-roll, legendas, cold open, CTA — com revisor independente antes de entregar.

Pré-requisitos

O que precisa estar no ar

O bot é só a ponte — sem qualquer um destes, ele recusa enfileirar ou nem sobe. Nenhum deles é opcional de fato, mesmo quando o bot não trava por causa deles no boot.

Node 20+

Runtime do bot (grammY + better-sqlite3). Testado com Node 24; tsconfig.json compila para ES2022/NodeNext, então qualquer LTS ativo (≥20) funciona.

# checar versão
node -v

Daemon mkivideos

É o motor de verdade: dono da fila, do worker e do render. O bot faz ping() (GET /api/stats) antes de qualquer instrução — se estiver fora do ar, recusa enfileirar em vez de perder a mensagem em silêncio.

# status do daemon
systemctl --user status mkivideos

CLI claude

Usado em dois pontos: o bot chama claude --model opus -p pra interpretar texto livre; e o próprio agente de render do mkivideos roda como sessão claude -p — é essa sessão que dá acesso à web quando a flag pesquisa é usada. Sem claude no PATH, nenhum dos dois funciona.

# checar instalação
claude --version

Skills envolvidas

O bot só nomeia as skills em config/skills.json — quem precisa tê-las instaladas e utilizáveis é o agente de render do mkivideos, não o bot: video-explicativo, videos-cursos-inema, video-demonstrativo (vídeo), reel-edita-inema (reel empilhado, comando reel) e reel-edita-inematds (reel pessoal produzido, comando reelinematds). transcrever/dublar não usam skill do Claude Code — delegam direto pros scripts do inemavox.

Token do BotFather + chat id

Token do @inemaccvbot criado no @BotFather, mais o(s) chat id(s) autorizados — ambos vão no .env. Ver o passo 3 do guia abaixo pra descobrir o chat id sem cair na armadilha.

# nunca commitado
TELEGRAM_BOT_TOKEN=<seu-token-do-botfather>
ALLOWED_CHAT_IDS=<seu-chat-id>

Pastas yt-pub-lives<N>

Só necessárias se você usar o campo livesN (destino) numa instrução. Sem a pasta, o vídeo fica no output padrão da skill mesmo — e a instrução com livesN inexistente é recusada listando os destinos válidos.

better-sqlite3 nativo

Guarda o estado local (job id ↔ chat id/flags) em state.db. É um binário nativo — npm i compila/baixa um addon C++ pra sua plataforma (em geral já vem pronto via prebuilt binary do pacote, sem precisar de toolchain de build).

Guia de uso · passo a passo

Do clone ao primeiro vídeo na fila

Comandos reais deste repositório — nenhum placeholder.

1

Clonar, instalar, copiar o .env

Instala as dependências de produção (grammY, dotenv, better-sqlite3) e cria o arquivo de config.

git clone https://github.com/inematds/inemaccvbot.git
cd inemaccvbot
npm i
cp .env.example .env  # depois preenche token, chat id etc.
2

Pegar o token no BotFather

No Telegram, fale com @BotFather e use /newbot (ou /token num bot já existente). Cole o valor em TELEGRAM_BOT_TOKEN no .env.

TELEGRAM_BOT_TOKEN=<seu-token-do-botfather>
3

Descobrir seu chat id (a armadilha)

O bot exige ALLOWED_CHAT_IDS pra sequer subir (loadConfig lança erro se faltar) — ou seja, não dá pra rodar o bot e ler o chat id no log dele, porque ele nem inicia sem essa variável. O jeito é perguntar direto pra API do Telegram, com o próprio token:

# 1. mande qualquer mensagem pro seu bot no Telegram (ele não responde ainda, tudo bem)
# 2. rode isto (timeout=25 é um long-poll — sem ele, costuma voltar vazio):
curl "https://api.telegram.org/bot<seu-token-do-botfather>/getUpdates?timeout=25"
# 3. no JSON, o chat id está em result[0].message.chat.id

Preencha ALLOWED_CHAT_IDS com esse número (vários separados por vírgula, se mais de um chat vai falar com o bot).

4

Build e teste rápido (opcional)

Compila TypeScript pra dist/ e roda uma vez em foreground, só pra validar o .env antes de virar serviço.

npm run build  # gera dist/index.js
npm run start  # roda dist/index.js em foreground
# ou, sem buildar, direto do TypeScript:
npm run dev    # tsx src/index.ts
5

Instalar como serviço systemd (uso contínuo)

Registra a unit de usuário. Ver a seção Operação do serviço logo abaixo pra deixar isso realmente sempre ativo (inclusive após logout/reboot) e pro dia a dia de reiniciar/depurar.

mkdir -p ~/.config/systemd/user
cp deploy/inemaccvbot.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now inemaccvbot
6

Mandar instruções no Telegram

Uma linha por job — cabem várias na mesma mensagem.

explicativo: O que é RAG | 9:16 | lives3
explicativo: Computação quântica | pesquisa | narracao | lives2
curso: https://inematds.github.io/skillsx/ | modulo t1m1
demo: https://app.exemplo.com | lives7
7

Acompanhar e receber

Comandos de controle da fila e entrega do resultado.

/fila            # running + queued com posição
/status <id>     # detalhe do job (sem id: visão geral + stats)
/cancelar <id>   # cancela job na fila
/enviar <id>     # manda o MP4 aqui (≤50 MB, senão só o caminho)
/skills          # o que o bot sabe fazer
/help            # ajuda completa (ou /start)
Operação do serviço · systemd --user

Deixar sempre ativo e saber reiniciar

deploy/inemaccvbot.service roda node dist/index.js com um PATH explícito no unit — necessário porque uma unit de usuário do systemd não herda o PATH do seu shell, e o bot chama claude e node via shell-out.

✅ Sempre ativo (sobe no boot, volta sozinho se cair)

mkdir -p ~/.config/systemd/user
cp deploy/inemaccvbot.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now inemaccvbot
loginctl enable-linger $USER

enable registra a unit em WantedBy=default.target — sobe sozinho em todo boot/login; --now já inicia agora. Restart=on-failure + RestartSec=10 (já no unit) faz o bot voltar sozinho se o processo morrer.

loginctl enable-linger $USER é o passo fácil de esquecer. Sem ele, uma unit --user só existe enquanto você tem sessão de login aberta: o bot morre ao deslogar e não sobe num reboot sem ninguém logado. Com o linger habilitado, o systemd mantém os serviços --user rodando independente de sessão.

# conferir que está ativo
systemctl --user status inemaccvbot

🔁 Restartar, parar, depurar (dia a dia)

systemctl --user restart inemaccvbot  # reinicia
systemctl --user stop inemaccvbot     # para
systemctl --user start inemaccvbot    # inicia de novo
systemctl --user disable --now inemaccvbot  # para de subir sozinho E para agora

Mudou código-fonte? Restart sozinho não basta — o serviço roda dist/, não src/: npm run build && systemctl --user restart inemaccvbot. Mudou só o .env? Um restart simples já é suficiente (lido no boot do processo via dotenv/config).

journalctl --user -u inemaccvbot -f  # log do systemd, ao vivo
tail -f inemaccvbot.log              # log próprio do bot (LOG_FILE), com rotação

⚠️ Se o serviço não sobe

O erro aparece no journalctl --user -u inemaccvbot -f. As duas causas mais comuns: variável obrigatória faltando no .envloadConfig lança variável obrigatória ausente no .env: <NOME> explicitamente, sem precisar adivinhar; ou o daemon mkivideos fora do ar — o bot ainda sobe (não depende do mkivideos pra iniciar), mas toda instrução é recusada com "fila mkivideos indisponível" até systemctl --user status mkivideos voltar a ficar ativo.

Exemplos

Campos aceitos em qualquer ordem

O formato é <skill>: <assunto ou link> | campo | campo | .... Texto livre também funciona — Claude interpreta, mas só mapeando para skills registradas.

🎬 explicativo

explicativo: O que é RAG | 9:16 | lives3
Vídeo explicativo PT-BR (skill video-explicativo). Campos aceitos por qualquer skill: 9:16/vertical (default é 16:9/horizontal), pesquisa/pesquisar, narracao/narração/texto, livesN.

🎓 curso

curso: https://inematds.github.io/skillsx/ | modulo t1m1
Vídeo de curso INEMA a partir do link (skill videos-cursos-inema). Campos: modulo X, curso X.

🖥️ demo

demo: https://app.exemplo.com | lives7
Vídeo demonstrativo de um app/site (skill video-demonstrativo).

🎬 reel

/reel /home/user/avatar.mp4 quero com texto e imagem ilustrativa
Reel 9:16 empilhado a partir de avatar HeyGen (skill reel-edita-inema). Também aceita reel: <caminho> | lives3 ou anexo <20 MB com legenda "reel".

🚀 reelinematds

/reelinematds /home/user/bruto.mp4 sem música
Reel pessoal produzido a partir de um bruto vertical (skill reel-edita-inematds) — corte, PiP/B-roll, legendas, cold open, CTA final, revisor. Mesmos campos do reel.

💬 texto livre

<url> crie um vídeo explicativo ... e me retorne também a narração em texto
Cai no fallback Claude — extrai todo job que mapeia e avisa ⚠️ não vou fazer: ... só para o que sobra fora do escopo.

Roadmap

O que vem depois

O v1 (spec docs/superpowers/specs/2026-07-16-inemaccvbot-design.md) está implementado e revisado. Itens abaixo são evolução, não bug — ver docs/V2-BACKLOG.md.

v2
Skill de carrosselVirá de uma parte do timesmkt3 (ainda não existe). Quando existir, basta adicionar entrada em config/skills.json e reiniciar — o registro é plugável, sem mudança de código.
residual
Guarda de espaço em --pastaÚnico slot argv sem validação de espaço (só alcançável via PROJETOS_DIR, config de operador — não input de usuário).
residual
Token -- no assuntoÉ engolido pelo loop de flags do mkivideos (pré-existente, cosmético, só afeta usuários da allowlist).
residual
Log de ALLOWED_CHAT_IDSEntrada malformada falha fechado em silêncio (seguro, mas um typo vira "o bot não responde" sem explicação); sugestão é logar os ids carregados no boot.