${esc(bot.name)}
${bot.enabled?'Ativo':'Rascunho'}${esc(bot.description||'Personaliza o flow deste bot.')}
diff --git a/README.md b/README.md
index 25359ac..c1a8971 100644
--- a/README.md
+++ b/README.md
@@ -1,51 +1,51 @@
-# TS6 Botflow
+# TS6 Botflow
-Painel local XanaX para gerir bots TeamSpeak, com login Discord e editor visual de flows. Mant?m os log?tipos originais e o tema flat roxo. As pastas dos projetos de origem permanecem intactas.
+Painel local XanaX para gerir bots TeamSpeak, com login Discord e editor visual de flows. Mantém os logótipos originais e o tema flat roxo. As pastas dos projetos de origem permanecem intactas.
## Funcionalidades
-- Dashboard com bots, flows e execu??es guardados na base de dados.
-- Editor com blocos arrast?veis, liga??es, condi??es, propriedades, zoom e grava??o.
-- Blocos: temporizador, in?cio manual, informa??es do servidor, clientes, ordena??o, limite, prepara??o de texto, edi??o da descri??o de canal, mensagem, espera e registo.
-- Simula??o identificada com dados de exemplo, sem enviar pedidos ao TeamSpeak.
-- Execu??o manual ou por temporizador, com hist?rico e resultado de cada passo. Um bot n?o executa duas vezes em simult?neo.
-- Liga??es WebQuery, teste de liga??o e API keys cifradas em repouso.
-- Vari?veis por bot, acess?veis como `{{variables.nome}}`. Outros valores: `{{server.virtualserver_clientsonline}}`, `{{count}}`, `{{top}}`, `{{text}}` e `{{time}}`.
+- Dashboard com bots, flows e execuções guardados na base de dados.
+- Editor com blocos arrastáveis, ligações, condições, propriedades, zoom e gravação.
+- Blocos: temporizador, início manual, informações do servidor, clientes, ordenação, limite, preparação de texto, edição da descrição de canal, mensagem, espera e registo.
+- Simulação identificada com dados de exemplo, sem enviar pedidos ao TeamSpeak.
+- Execução manual ou por temporizador, com histórico e resultado de cada passo. Um bot não executa duas vezes em simultâneo.
+- Ligações WebQuery, teste de ligação e API keys cifradas em repouso.
+- Variáveis por bot: `{{variables.nome}}`. Outros valores: `{{server.virtualserver_clientsonline}}`, `{{count}}`, `{{top}}`, `{{text}}` e `{{time}}`.
-O primeiro arranque cria um rascunho **Estat?sticas**, desativado, para atualizar a descri??o do canal **21** a cada 30 segundos. O top inicial ordena as pessoas atualmente online pela data de entrada; n?o ? um ranking hist?rico de tempo acumulado.
+O primeiro arranque cria um rascunho **Estatísticas**, desativado, para atualizar a descrição do canal **21** a cada 30 segundos. O top inicial ordena as pessoas atualmente online pela data de entrada; não é um ranking histórico de tempo acumulado.
-Esta vers?o n?o inclui reprodu??o de m?sica, eventos SSH, webhooks, edi??o de permiss?es nem gest?o de perfis pelo painel. Cada bot tem um flow. O editor disponibiliza os blocos implementados acima.
+Esta versão não inclui reprodução de música, eventos SSH, webhooks, edição de permissões nem gestão de perfis pelo painel. Cada bot tem um flow. O editor disponibiliza os blocos implementados acima.
## Docker / Portainer
-Para Web editor com imagem constru?da no Gitea, consultar [deploy/README.md](deploy/README.md) e usar [deploy/bot-stack.yaml](deploy/bot-stack.yaml). Cada push em `main` executa os testes e publica a imagem. Depois do workflow verde, atualizar a stack no Portainer com download da imagem e recria??o do container. Restart sozinho n?o descarrega a nova imagem.
+Para Web editor com imagem construída no Gitea, consultar [deploy/README.md](deploy/README.md) e usar [deploy/bot-stack.yaml](deploy/bot-stack.yaml). Cada push em `main` executa os testes e publica a imagem. Depois do workflow verde, atualizar a stack no Portainer com download da imagem e recriação do container. Restart sozinho não descarrega a nova imagem.
-Para construir localmente com Docker Compose, usar `compose.yaml`. A aplica??o escuta na porta 3080 e preserva os dados num volume montado em `/app/data`.
+Para construir localmente com Docker Compose, usar `compose.yaml`. A aplicação escuta na porta 3080 e preserva os dados num volume montado em `/app/data`.
-Vari?veis de ambiente:
+Variáveis de ambiente:
-- `APP_URL`: endere?o do navegador, por exemplo `http://192.168.88.99:3080`.
-- `DISCORD_CLIENT_ID`: ID da aplica??o Discord.
-- `DISCORD_CLIENT_SECRET`: segredo OAuth da aplica??o.
-- `OWNER_DISCORD_ID`: ID num?rico da conta do dono.
-- `ALLOWED_DISCORD_IDS`: IDs de leitores separados por v?rgulas. Por defeito, `723613831196311603`; valor vazio remove todos os leitores.
+- `APP_URL`: endereço do navegador, por exemplo `http://192.168.88.99:3080`.
+- `DISCORD_CLIENT_ID`: ID da aplicação Discord.
+- `DISCORD_CLIENT_SECRET`: segredo OAuth da aplicação.
+- `OWNER_DISCORD_ID`: ID numérico da conta do dono.
+- `ALLOWED_DISCORD_IDS`: IDs de leitores separados por vírgulas. Por defeito, `723613831196311603`; valor vazio remove todos os leitores.
No Discord Developer Portal, adicionar o redirect exato `http://192.168.88.99:3080/auth/discord/callback`, ajustando ao `APP_URL`. O navegador e o container precisam de Internet para o OAuth; o site pode continuar apenas na rede local.
-O **Dono** pode configurar, guardar, simular e executar. O **Leitor** pode consultar. Outras contas s?o recusadas; as permiss?es s?o tamb?m verificadas no servidor.
+O **Dono** pode configurar, guardar, simular e executar. O **Leitor** pode consultar. Outras contas são recusadas; as permissões são também verificadas no servidor.
## Ligar ao TeamSpeak
-Entrar com a conta do dono. Em **Liga??es**, configurar o endere?o WebQuery HTTP/HTTPS, o ID do servidor virtual e a API key TeamSpeak. Por exemplo, `http://teamspeak6:10080` funciona quando ambos os containers partilham uma rede Docker com esse nome resolv?vel. Testar a liga??o, escolher esse servidor na configura??o do bot, simular e s? depois ativar.
+Entrar com a conta do dono. Em **Ligações**, configurar o endereço WebQuery HTTP/HTTPS, o ID do servidor virtual e a API key TeamSpeak. Por exemplo, `http://teamspeak6:10080` funciona quando ambos os containers partilham uma rede Docker com esse nome resolvível. Testar a ligação, escolher esse servidor na configuração do bot, simular e só depois ativar.
-O temporizador aceita intervalos a partir de um segundo. A execu??o seguinte aguarda a conclus?o da anterior; pedidos de rede e blocos de espera podem prolongar o intervalo efetivo. A configura??o de permiss?es e prote??o contra flood do TeamSpeak deve permitir os pedidos do bot.
+O temporizador aceita intervalos a partir de um segundo. A execução seguinte aguarda a conclusão da anterior; pedidos de rede e blocos de espera podem prolongar o intervalo efetivo. A configuração de permissões e proteção contra flood do TeamSpeak deve permitir os pedidos do bot.
-Sess?es e flows usam SQLite no volume. A chave de cifra das API keys fica em `/app/data/credentials.key`; preservar o volume completo nas c?pias de seguran?a. O hist?rico ret?m as ?ltimas 500 execu??es. N?o adicionar `.env` nem dados ao Git.
+Sessões e flows usam SQLite no volume. A chave de cifra das API keys fica em `/app/data/credentials.key`; preservar o volume completo nas cópias de segurança. O histórico retém as últimas 500 execuções. Não adicionar `.env` nem dados ao Git.
-## Desenvolvimento e valida??o
+## Desenvolvimento e validação
-Node 22.15+, mesmas vari?veis de ambiente e `npm start`. Executar `npm test` para verificar autentica??o, restri??es de acesso, persist?ncia, simula??o e execu??o WebQuery com transporte de teste. O build Docker executa os testes antes da publica??o.
+Node 22.15+, mesmas variáveis de ambiente e `npm start`. Executar `npm test` para verificar autenticação, restrições de acesso, persistência, simulação e execução WebQuery com transporte de teste. O build Docker executa os testes antes da publicação.
-O editor foi verificado em navegador desktop e m?vel. A execu??o no TeamSpeak real depende da liga??o e API key configuradas na instala??o; os testes locais n?o alteram o servidor real.
+O editor foi verificado em navegador desktop e móvel. A execução no TeamSpeak real depende da ligação e API key configuradas na instalação; os testes locais não alteram o servidor real.
-A fonte Public Sans ? distribu?da em `public/fonts` com a licen?a OFL. Os log?tipos foram copiados sem altera??es do projeto existente.
+A fonte Public Sans é distribuída em `public/fonts` com a licença OFL. Os logótipos foram copiados sem alterações do projeto existente.
diff --git a/public/app.js b/public/app.js
index 2aa3d8b..135dd1d 100644
--- a/public/app.js
+++ b/public/app.js
@@ -21,7 +21,7 @@ function navigate(name){if(dirty&&!confirm('Sair sem guardar as alterações do
function botCard(bot){const runs=data.executions.filter(e=>e.botId===bot.id);return ` ${esc(bot.description||'Personaliza o flow deste bot.')}${esc(bot.name)}
${bot.enabled?'Ativo':'Rascunho'}
O rascunho Estatísticas prepara a descrição do canal 21. Escolhe a ligação e simula antes de ativar.
O bot começa desativado. Usa o flow de estatísticas como base ou substitui os blocos.
`,async form=>{const bot=await api('/api/bots',{method:'POST',body:JSON.stringify(Object.fromEntries(form))});botId=bot.id;page='editor';});} function configureBot(id){botId=id;const bot=selectedBot();modal('Configuração do bot',`Escolhe uma ligação para executar o flow no TeamSpeak.
`,f=>api(`/api/bots/${bot.id}`,{method:'PUT',body:JSON.stringify(Object.fromEntries(f))}));document.querySelector('#config-vars').onclick=()=>{document.querySelector('#dialog').close();navigate('variables');};} diff --git a/public/fonts/OFL.txt b/public/fonts/OFL.txt index 9eef1e9..547185a 100644 --- a/public/fonts/OFL.txt +++ b/public/fonts/OFL.txt @@ -18,7 +18,7 @@ with others. The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, +fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The