API em Flask para integrar interacao do chat com a stream, com suporte a comandos, eventos da Twitch, feedback sonoro no OBS e consultas de progresso da Steam.
Esta aplicacao foi pensada para rodar no host do Render.
- Em producao, o Render define automaticamente a porta via variavel
PORT. - O endpoint publico esperado e o do proprio servico Render.
- Mantem dados por jogo em
dados.json, usando chave normalizada do nome do jogo (ex:torchlight-infinite). - Recebe comandos do chat via endpoints expostos para integrarem com Nightbot ou automacoes similares.
- Recebe eventos da Twitch via listener/webhook e dispara feedback sonoro na stream.
- Retorna informacoes de progresso de conquistas da Steam para o jogo atual da live.
- Expoe rotas de health check para manter o servico online no Render.
Integracao finalizada com resgate de power-up na Twitch e feedback sonoro na stream.
Fluxo geral:
- A Twitch envia o evento para o webhook da API.
- O listener processa o payload e atualiza o estado em memoria.
- A webpage do OBS consulta esse estado via JavaScript.
- O JavaScript reage ao novo evento e toca o audio configurado.
- O mesmo padrao permite acionar a API por comandos do chat, por exemplo via Nightbot, usando os endpoints HTTP expostos.
Esse fluxo permite unir comandos do chat, eventos da Twitch e resposta visual/sonora na stream sem depender de extensoes pesadas no OBS.
TWITCH_CHANNEL_IDTWITCH_DEV_IDTWITCH_SECRETTWITCH_TOKENSTEAM_WEB_API_KEY(ouSTEAM_API_KEY)STEAM_TARGET_STEAMID64PUBLIC_BASE_URL(exemplo:https://seu-servico.onrender.com)GITHUB_TOKEN,GITHUB_OWNER,GITHUB_REPOGITHUB_FILE_PATHpara publicardados.jsonGITHUB_STEAM_GAMES_FILE_PATHpara publicarsteam_games.json
Para fazer um reward da Twitch falar no overlay do OBS, configure:
TWITCH_TTS_REWARD_IDSTWITCH_TTS_REWARD_ID(single reward ID fallback)TWITCH_TTS_LANG(opcional, padraopt-BR)
Quando um reward configurado e resgatado:
- O backend gera um arquivo de audio MP3 usando
gTTS. - O payload enviado para o overlay inclui
tts_audio_url. - O JavaScript do OBS toca esse arquivo (em vez de depender apenas do
speechSynthesislocal).
O texto falado vem de user_input. Se vier vazio, o backend monta uma frase curta com user_name + reward title.
Teste rapido sem Twitch:
/twitch/powerup/test?text=Mensagem+de+testeSe text for omitido, o teste segue o caminho legado de audio (nossa.ogg).
Observacoes:
- Os arquivos TTS gerados ficam em
/mp3/tts-generated/. - O backend remove arquivos antigos automaticamente para evitar crescimento infinito.
- Se a geracao de audio falhar, o overlay ainda tenta o fallback via
speechSynthesis. - O
gTTSdepende de acesso a internet para gerar os arquivos.
O fluxo foi desenhado para ser simples de operar na live:
- O chat dispara um comando do Nightbot.
- O Nightbot chama um endpoint da API.
- A API atualiza o estado interno ou os dados do jogo.
- O listener JavaScript da pagina do OBS observa o estado ou consome o endpoint.
- A stream recebe o feedback sonoro ou a atualizacao visual.
-
POST /twitch/eventsub- Callback da Twitch EventSub
-
GET|POST /twitch/eventsub/subscribe- Cria assinatura EventSub para
channel.channel_points_custom_reward_redemption.add
- Cria assinatura EventSub para
-
GET /twitch/powerup/state- Estado simples (seq/ultimo reward) para polling da webpage
-
GET /obs/powerup- Webpage blank para Browser Source do OBS
-
GET /obs/nossa.mp3- Audio tocado quando houver novo trigger do power-up na stream
-
GET /mp3/<arquivo>.mp3- Arquivos MP3 estaticos e TTS gerado (
/mp3/tts-generated/...)
- Arquivos MP3 estaticos e TTS gerado (
-
GET|POST /twitch/powerup/test- Endpoint de teste manual para disparar power-up
- Com
?text=...gera TTS em arquivo e envia para o overlay
Novo overlay para Torchlight com roleta interativa que gira quando um reward específico é resgatado na Twitch.
- Usuario resgata o reward "Roleta de FE (Torchlight)" na Twitch.
- A Twitch envia o evento para o webhook em
/twitch/eventsub. - O backend atualiza
POWERUP_EVENT_STATEcomseq,last_rewardelast_event. - A pagina OBS em
/torchlight/roleta/obsfaz polling a cada 1 segundo em/twitch/powerup/state. - Ao detectar mudanca no
seq, a pagina identifica que é um novo evento. - A roleta gira por 4 segundos com animacao suave (cubic easeOut).
- Ao final da animacao, o centro exibe o valor sorteado (50, 75, 100, 125, 200 ou 300).
- A roleta fica visivel por 30 segundos e desaparece automaticamente.
No painel de Creator Dashboard da Twitch, crie um reward customizado com:
- Titulo:
Roleta de FE (Torchlight) - ID do reward:
28bce937-6821-426c-a186-713398767e9c(ou outro, configuravel) - Custo: à sua escolha (recomendado 1000-5000 pontos)
- Imagem: opcional, logo de Torchlight
-
GET /torchlight/roleta/obs- Retorna a pagina HTML com estrutura da roleta (pointer, wheel, labels, center display)
-
GET /torchlight/roleta/obs.js- JavaScript com logica de polling, animacao, som e matching de valores
-
GET /torchlight/roleta/obs.css- CSS com estilo do wheel (conic-gradient), labels posicionadas via trigonometria, pointer (triangulo vermelho no topo)
-
GET /twitch/powerup/state- Retorna JSON com
seq(contador de atualizacoes),last_reward(ID do ultimo reward) elast_event(timestamp) - Exemplo:
{"seq": 42, "last_reward": "28bce937...", "last_event": 1704067200}
- Retorna JSON com
-
GET|POST /twitch/powerup/test- Testa manualmente o trigger da roleta sem precisar resgatar o reward na Twitch
- Parametros opcionais:
?label=Roleta%20de%20FE%20%28Torchlight%29- filtra por titulo do reward (case-insensitive)?id=28bce937-6821-426c-a186-713398767e9c- filtra por ID do reward
- Exemplo:
http://localhost:5000/twitch/powerup/test?label=Roleta%20de%20FE
- Valores: 6 fatias com numeros [50, 75, 100, 125, 200, 300]
- Peso: Distribuicao em porcentagem 22% / 22% / 22% / 22% / 8% / 4%, mantendo a fatia de 300 menor
- Cores: Cada fatia tem cor distinta (vermelho, azul, verde, amarelo, roxo, laranja)
- Animacao: Gira 6+ voltas completas + angulo aleatorio extra, desacelerando suavemente
- Som: Tom de 1kHz tocado durante a rotacao a cada 10 graus
- Precision: O valor exato apontado pelo triangulo vermelho (topo) e calculado usando trigonometria e conic-gradient com
from -90deg
- Crie uma Browser Source e aponte para
https://seu-servico.onrender.com/torchlight/roleta/obs. - Configure as dimensoes: largura e altura
420px(quadrado para o wheel). - Habilite
Atualizar pagina quando cena fica inativapara evitar cache. - Coloque a source em uma cena dedicada ou sobreposição da cena de Torchlight.
- A roleta ficara invisivel ate que o reward seja resgatado.
- Para testar sem resgatar, chame:
curl http://localhost:5000/twitch/powerup/test?label=Roleta%20de%20FE%20%28Torchlight%29
Dentro da pagina HTML (/torchlight/roleta/obs), o atributo data-default-reward define qual reward ativa a roleta:
<div id="wrapper" data-default-reward="28bce937-6821-426c-a186-713398767e9c,Roleta de FE (Torchlight)">Pode-se filtrar por ID, titulo ou ambos (separados por virgula). A filtragem e case-insensitive.
Se necessario, pode-se passar ?reward=ID ou ?label=TITULO como query string na URL da Browser Source para sobrescrever.
GET /steam/achievements/-
Retorna as conquistas desbloqueadas e o total de conquistas do jogo da stream usando o SteamID64 configurado no Render.
-
Se
?game=nao for enviado, usa o jogo atual da live vindo da Twitch. -
Resposta em texto puro no formato:
Outer Wilds: 2 de 31 (6,45% concluído) -
Atualmente o mapping inclui:
Outer Wilds -> 753640 -
Quando um jogo novo precisa ser resolvido, o mapa local
steam_games.jsone atualizado e pode ser publicado automaticamente no GitHub se as variaveis de publish estiverem configuradas. -
Requer as variaveis de ambiente
STEAM_WEB_API_KEY(ouSTEAM_API_KEY) eSTEAM_TARGET_STEAMID64.
-
O arquivo dados.json guarda os contadores por jogo. Exemplo:
{
"outer-wilds": {
"mortes": 20
}
}Isso permite manter o historico por jogo e usar a mesma base para futuras expansoes.
- Adicione uma Browser Source apontando para
https://seu-servico.onrender.com/obs/powerup. - Habilite
Control audio via OBSna Browser Source para garantir saida no mixer. - Dispare a criacao da assinatura em
/twitch/eventsub/subscribe. - Teste manual com
/twitch/powerup/test?text=Mensagem+de+teste. - Ao ocorrer um novo resgate na Twitch, a pagina deve tocar o MP3 gerado para TTS (ou audio mapeado quando nao for TTS).
app.py: API principal.dados.json: arquivo com os dados por jogo.obs_browser_refresh.lua: script para ser adicionado dentro do proprio OBS (Tools > Scripts) e forcar o refresh da Browser Source.obs_powerup.html: webpage para Browser Source que escuta trigger de power-up e toca audio.
O arquivo obs_browser_refresh.lua existe para atualizar o Browser Source diretamente dentro do OBS, evitando dependencia do plugin/WebSocket para esse refresh.
- Instale dependencias:
pip install -r requirements.txt- Execute a API:
python app.py-
GET /death/get -
GET /death/read- Retorno: apenas o numero de mortes (exemplo:
16)
- Retorno: apenas o numero de mortes (exemplo:
-
GET /death/read/obs- Retorno: texto para overlay (exemplo:
16 mortes)
- Retorno: texto para overlay (exemplo:
-
GET /death/current-game- Retorno JSON com
game_name,game_keyemortesdo jogo atual
- Retorno JSON com
-
GET /death/all- Retorno JSON com total geral e todos os jogos no formato salvo em
dados.json
- Retorno JSON com total geral e todos os jogos no formato salvo em
-
GET /stream/current-game- Retorno: apenas o
game_nameatual da stream em texto puro (ex:Outer Wilds)
- Retorno: apenas o
-
GET|POST /death/increment- Soma 1 no contador do jogo atual da stream
-
GET|POST /death/decrement- Subtrai 1 no contador do jogo atual da stream
-
GET /death/clear- Limpa os dados e volta para o estado padrao
-
GET|POST /death/save- Salva o contador por jogo no mesmo formato dos demais endpoints de mortes
- Parametros aceitos (prioridade):
jogo(ougame)mortes
- Compatibilidade legada mantida:
keyevalue
- Exemplo de body JSON recomendado:
{
"jogo": "torchlight infinite",
"mortes": 860
}- Exemplo de persistencia em `dados.json`:
{
"torchlight-infinite": {
"mortes": 860
}
}- Retorno: numero salvo em texto puro (ex: `860`)
GET /GET /healthz
Todas retornam status 200 quando o servico esta saudavel.