@danhachuel/thunderbolt 0.2.27 → 0.2.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Este manual descreve a instalação local da UI Thunderbolt, baseada no MoneyPrinterTurbo, utilizando o pacote npm `@danhachuel/thunderbolt`. O fluxo recomendado instala automaticamente o ambiente Python, as dependências da aplicação, as dependências do MoneyPrinterTurbo, o Streamlit e o suporte FFmpeg através de `imageio-ffmpeg`.
4
4
 
5
- > **Versão deste manual:** 0.2.27
5
+ > **Versão deste manual:** 0.2.28
6
6
  > **Pacote npm:** `@danhachuel/thunderbolt`
7
7
  > **Porta padrão da UI:** `localhost:3030`
8
8
  > **Repositório:** [github.com/DanHachuel/thunderbolt](https://github.com/DanHachuel/thunderbolt)
@@ -100,13 +100,13 @@ Execute:
100
100
  Windows PowerShell ou MobaXterm:
101
101
 
102
102
  ```powershell
103
- npx.cmd --yes @danhachuel/thunderbolt@0.2.27 install
103
+ npx.cmd --yes @danhachuel/thunderbolt@0.2.28 install
104
104
  ```
105
105
 
106
106
  Linux/macOS:
107
107
 
108
108
  ```bash
109
- npx --yes @danhachuel/thunderbolt@0.2.27 install
109
+ npx --yes @danhachuel/thunderbolt@0.2.28 install
110
110
  ```
111
111
 
112
112
  A instalação normal é **segura para actualizações**: preserva `storage`, Blueprints, Brandings, configurações e artefactos do utilizador. Remove apenas `.venv`, o clone técnico do MoneyPrinterTurbo e dependências que serão recriadas. Uma pasta antiga sem dados do utilizador, como `C:\Users\<utilizador>\AppData\Local\hermes` da tentativa incompleta, pode ser removida; uma pasta antiga que contenha Blueprints, Brandings ou storage é preservada e apenas avisada no terminal. Feche processos Python, Node, Streamlit e MobaXterm que estejam a usar as pastas antes de executar.
@@ -339,7 +339,7 @@ Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
339
339
 
340
340
  ## 8. Configuração inicial da UI
341
341
 
342
- Na primeira execução, abra **Configurações** e reveja. Para YouTube, preencha primeiro o par **OAuth Client ID + OAuth Client Secret** se pretende autorizar uploads. A **YouTube Data API Key** é uma credencial Google Cloud diferente e fica numa área opcional, apenas para o método oficial de métricas; Client ID + Client Secret não formam uma API Key.
342
+ Na primeira execução, a barra lateral apresenta **Início**, **Pipeline**, **Automação**, **Niche Finder** e **Configurações**. Abra **Configurações > Configurações Técnicas** e reveja. O menu **Pipeline** contém **Criação de Vídeos**, **Criação de Músicas**, **Upload** e **Limpador de Metadados**. O menu **Configurações** contém **Canais**, **Blueprints**, **MCP** e **Configurações Técnicas**. Para YouTube, preencha primeiro o par **OAuth Client ID + OAuth Client Secret** se pretende autorizar uploads. A **YouTube Data API Key** é uma credencial Google Cloud diferente e fica numa área opcional, apenas para o método oficial de métricas; Client ID + Client Secret não formam uma API Key.
343
343
 
344
344
  | Configuração | Finalidade |
345
345
  |---|---|
@@ -358,30 +358,30 @@ As credenciais devem ser inseridas apenas na configuração local. A Data API Ke
358
358
 
359
359
  Após iniciar a aplicação, valide o seguinte percurso:
360
360
 
361
- 1. **Dashboard:** confirme que a UI abre e mostra o estado local.
361
+ 1. **Início:** confirme que a UI abre, mostra o estado local, as métricas e os cards das filas do Pipeline, sem botões de acções rápidas.
362
362
  2. **Blueprints:** coloque um JSON em `~/.thunderbolt/storage/blueprints/importados/` (Windows: `%LOCALAPPDATA%\\THUNDERBOLT\storage\blueprints\importados\`) ou use o carregador da interface.
363
363
  3. **Brandings:** abra a subaba **Brandings** e confirme a listagem dos ficheiros JSON.
364
364
  4. **Canais:** em **Importar do YouTube**, use o método **Página pública — sem API Key** com um URL `/channel/UC...`, um handle ou uma subpágina `/videos`; o parser resolve o ID, consulta a página pública e tenta o RSS quando necessário. Confirme que o resultado abre o formulário de revisão sem Data API Key. Se o canal não existir ou não fornecer metadados, confirme a mensagem clara e que o formulário de uma pesquisa anterior desaparece. A Data API é opcional e fica separada; em **Cadastro manual**, preencha os dados sem qualquer consulta externa.
365
- 5. **Novo vídeo:** teste primeiro o modo **Canal específico** e depois os modos de lote.
366
- 6. **Novo vídeo > Vídeos:** verifique o estado `to_do` e os botões **Iniciar** e **Parar** dentro da subaba.
365
+ 5. **Pipeline > Criação de Vídeos:** teste primeiro o modo **Canal específico** e depois os modos de lote.
366
+ 6. **Criação de Vídeos > Vídeos:** verifique o estado `to_do` e os botões **Iniciar** e **Parar** dentro da subaba. Confirme também que **Criação de Músicas** mostra o mesmo fluxo com título próprio.
367
367
  7. **Upload:** configure o OAuth Client ID e Secret, autorize primeiro o **youtube-automation-agent** na própria aba, confirme o estado **pronto para publicar**, preencha título/descrição/tags e publique um MP4 real. O botão **Autorizar fallback OAuth** existe apenas para redundância; a Data API Key, se configurada, é exclusivamente para consultas oficiais públicas e nunca substitui OAuth.
368
- 8. **Limpador de metadado:** suba um vídeo de terceiro, preencha título, preview, links, timestamps e tags, aplique a limpeza e descarregue a cópia limpa e o manifesto JSON. O original fica preservado e vídeos da aba Novo vídeo não são aceites nesta área.
369
- 9. **Configurações:** confirme que os caminhos e credenciais estão locais e não aparecem no Git.
370
- 10. **Novo vídeo:** confirme que `Pexels/Pixabay` substitui o label antigo, que `Estilo IA` aparece apenas em `full_ia` e que `Apenas Música` exige áudio e guarda `background_mode=none`.
368
+ 8. **Pipeline > Limpador de Metadados:** suba um vídeo de terceiro, preencha título, preview, links, timestamps e tags, aplique a limpeza e descarregue a cópia limpa e o manifesto JSON. O original fica preservado e vídeos das páginas de criação não são aceites nesta área.
369
+ 9. **Configurações > Configurações Técnicas:** confirme que os caminhos e credenciais estão locais e não aparecem no Git.
370
+ 10. **Criação de Vídeos:** confirme que `Pexels/Pixabay` substitui o label antigo, que `Estilo IA` aparece apenas em `full_ia` e que `Apenas Música` exige áudio e guarda `background_mode=none`.
371
371
  11. **Automação:** no cartão de cada canal, escolha o **Blueprint padrão** e a **Voz padrão**, clique em `Guardar` e confirme que o resumo do cartão se actualiza. Configure também **Automação ON** e um horário `HH:MM`; confirme a lista de vídeos cadastrados. Os mesmos defaults aparecem em **Canais** e são usados em novas tarefas. A UI não inicia jobs em segundo plano nesta entrega.
372
- 12. **Teste de vozes:** em Configurações, teste Edge/Azure ou provider configurado e confirme reprodução/download sem criação de tarefa.
372
+ 12. **Configurações > Configurações Técnicas > Teste de vozes:** teste Edge/Azure ou provider configurado e confirme reprodução/download sem criação de tarefa.
373
373
  13. **Upload directo:** configure manualmente cookies, sessionInfo e INNERTUBE_API_KEY, atribua o `DELEGATED_SESSION_ID` no canal e teste apenas com um vídeo de validação. O método envia chunks de 256 KiB e não extrai cookies do navegador.
374
- 14. **MCP Client MCP:** confirme que Short Video Maker, AutoVio, OpenMontage e OpenCut aparecem com as portas padrão editáveis. O estado **Activo** é uma preferência local; a detecção deve indicar **Não detectado** quando os serviços externos não estiverem instalados ou iniciados.
375
- 15. **MCP Servidor MCP:** abra a subaba, mantenha o host `127.0.0.1`, active **Servidor MCP ON** e clique em **Guardar e iniciar Servidor MCP**. Confirme o endpoint `/mcp` e o health endpoint `/health`. Mantenha **Permitir ferramentas de escrita** desactivado até precisar que um agente crie lotes.
376
- 16. **MCP Skill:** clique em **Guardar skill localmente** e confirme o ficheiro em `storage/skills/moneyprinterturbo-video.md`; opcionalmente use **Descarregar skill .md** para obter a cópia através do navegador.
374
+ 14. **Configurações > MCP > Client MCP:** confirme que Short Video Maker, AutoVio, OpenMontage e OpenCut aparecem com as portas padrão editáveis. O estado **Activo** é uma preferência local; a detecção deve indicar **Não detectado** quando os serviços externos não estiverem instalados ou iniciados.
375
+ 15. **Configurações > MCP > Servidor MCP:** abra a subaba, mantenha o host `127.0.0.1`, active **Servidor MCP ON** e clique em **Guardar e iniciar Servidor MCP**. Confirme o endpoint `/mcp` e o health endpoint `/health`. Mantenha **Permitir ferramentas de escrita** desactivado até precisar que um agente crie lotes.
376
+ 16. **Configurações > MCP > Skill:** clique em **Guardar skill localmente** e confirme o ficheiro em `storage/skills/moneyprinterturbo-video.md`; opcionalmente use **Descarregar skill .md** para obter a cópia através do navegador.
377
377
 
378
- ## Novo vídeo, Automação e música
378
+ ## Pipeline: Criação de Vídeos, Criação de Músicas e Automação
379
379
 
380
380
  O modo `Pexels/Pixabay` representa materiais de stock. Ao seleccionar `full_ia`, o selector `Estilo IA` apresenta os 12 estilos disponíveis. Ao seleccionar `Apenas Música`, a UI obriga a escolher uma música existente, carregar um ficheiro ou solicitar uma música a um endpoint Suno configurado. O vídeo recebe `background_mode=none`, sem fundo Pexels/Pixabay ou IA.
381
381
 
382
382
  A aba **Automação** lista os canais e vídeos, permite escolher e guardar **Blueprint padrão** e **Voz padrão** por canal, guarda **Automação ON** e valida horários diários no formato `HH:MM`. Os valores ficam sincronizados com o editor existente no cartão da aba **Canais** e são copiados para novas tarefas. É apenas uma camada de UI nesta versão, sem execução de worker.
383
383
 
384
- A área **Teste de vozes**, dentro de Configurações, é isolada da pipeline. O preview pode ser reproduzido e descarregado de `storage/voice_previews/`. Caminhos vazios, directórios, ficheiros vazios e previews sem permissões de leitura são ignorados com uma mensagem clara, sem traceback. Se uma instalação antiga mostrar que `edge-tts` está em falta, execute `npx.cmd --yes @danhachuel/thunderbolt install`; o detector reinstala apenas a dependência ausente.
384
+ A área **Teste de vozes**, dentro de **Configurações > Configurações Técnicas**, é isolada da pipeline. O preview pode ser reproduzido e descarregado de `storage/voice_previews/`. Caminhos vazios, directórios, ficheiros vazios e previews sem permissões de leitura são ignorados com uma mensagem clara, sem traceback. Se uma instalação antiga mostrar que `edge-tts` está em falta, execute `npx.cmd --yes @danhachuel/thunderbolt install`; o detector reinstala apenas a dependência ausente.
385
385
 
386
386
  ## Upload directo
387
387
 
@@ -389,19 +389,19 @@ A subaba **Upload directo** adapta o [YouTube-Video-Upload-Frontend-Api](https:/
389
389
 
390
390
  ## MCP e integrações externas
391
391
 
392
- A subaba **Client MCP** é um configurador local de quatro serviços opcionais. As portas iniciais são `3123` para Short Video Maker, `3001` para AutoVio, `8000` como referência editável para OpenMontage e `8787` para a API do OpenCut. A página consulta apenas `http://127.0.0.1:<porta>/` com timeout curto; não clona, instala ou inicia processos externos.
392
+ A subaba **Client MCP**, em **Configurações > MCP**, é um configurador local de quatro serviços opcionais. As portas iniciais são `3123` para Short Video Maker, `3001` para AutoVio, `8000` como referência editável para OpenMontage e `8787` para a API do OpenCut. A página consulta apenas `http://127.0.0.1:<porta>/` com timeout curto; não clona, instala ou inicia processos externos.
393
393
 
394
- A subaba **Servidor MCP** disponibiliza, após activação explícita, `http://127.0.0.1:3031/mcp` por JSON-RPC sobre HTTP POST. Para configurar um agente compatível, use esse URL como endpoint MCP. Se o host for alterado para uma interface externa, preencha primeiro um token e trate-o como segredo. O servidor disponibiliza ferramentas de leitura por padrão; a criação de lotes só é exposta quando **Permitir ferramentas de escrita** está activado.
394
+ A subaba **Servidor MCP**, em **Configurações > MCP**, disponibiliza, após activação explícita, `http://127.0.0.1:3031/mcp` por JSON-RPC sobre HTTP POST. Para configurar um agente compatível, use esse URL como endpoint MCP. Se o host for alterado para uma interface externa, preencha primeiro um token e trate-o como segredo. O servidor disponibiliza ferramentas de leitura por padrão; a criação de lotes só é exposta quando **Permitir ferramentas de escrita** está activado.
395
395
 
396
- A subaba **Skill** contém as acções para guardar a skill anexada em `storage/skills/` ou descarregá-la como Markdown. Esta pasta fica fora dos estados JSON e é criada pelo instalador e pelo launcher. Os quatro repositórios continuam fora do pacote npm.
396
+ A subaba **Skill**, em **Configurações > MCP**, contém as acções para guardar a skill anexada em `storage/skills/` ou descarregá-la como Markdown. Esta pasta fica fora dos estados JSON e é criada pelo instalador e pelo launcher. Os quatro repositórios continuam fora do pacote npm.
397
397
 
398
- ## 12. Limpador de metadado
398
+ ## 12. Limpador de Metadados
399
399
 
400
- A aba **Limpador de metadado** recebe somente vídeos externos já prontos. O ficheiro enviado é copiado para `storage/metadata_cleaner/originals/`; a aplicação não altera o original. Ao aplicar a operação, o FFmpeg remove os metadados existentes do contentor e cria uma nova versão em `storage/metadata_cleaner/outputs/` com o título, descrição, tags, idioma e outros campos preenchidos.
400
+ A aba **Limpador de Metadados** recebe somente vídeos externos já prontos. O ficheiro enviado é copiado para `storage/metadata_cleaner/originals/`; a aplicação não altera o original. Ao aplicar a operação, o FFmpeg remove os metadados existentes do contentor e cria uma nova versão em `storage/metadata_cleaner/outputs/` com o título, descrição, tags, idioma e outros campos preenchidos.
401
401
 
402
402
  A descrição combina **Preview**, **Links** e **Timestamps**, seguindo a estrutura do workflow `YTBMetadataGenerator.json`. O preview recomendado tem entre 100 e 200 caracteres; os capítulos devem começar por `00:00`. O manifesto JSON descarregado contém os campos para um fluxo posterior de upload. Esta adaptação local não faz scraping automático via RSS/Apify nem publica directamente no YouTube.
403
403
 
404
- Se a limpeza falhar, confirme a disponibilidade do FFmpeg em **Configurações > Caminho FFmpeg** ou execute `doctor`. O processo usa `-map_metadata -1` para remover os metadados existentes e `-c copy` para evitar uma re-encodificação desnecessária sempre que o contentor permitir.
404
+ Se a limpeza falhar, confirme a disponibilidade do FFmpeg em **Configurações > Configurações Técnicas > Caminho FFmpeg** ou execute `doctor`. O processo usa `-map_metadata -1` para remover os metadados existentes e `-c copy` para evitar uma re-encodificação desnecessária sempre que o contentor permitir.
405
405
 
406
406
  ## 11. Problemas frequentes
407
407
 
package/README.md CHANGED
@@ -10,21 +10,25 @@ A primeira versão implementa a camada UI independente com:
10
10
 
11
11
  | Área | Incluído |
12
12
  |---|---|
13
- | Dashboard | Resumo de canais, tarefas, backlog, execução e falhas |
14
- | Pipeline | Filas por etapa |
13
+ | Início | Resumo de canais, tarefas, backlog, execução e falhas, com as filas do Pipeline inline |
14
+ | Pipeline | Menu expansível com Criação de Vídeos, Criação de Músicas, Upload e Limpador de Metadados |
15
15
  | Blueprints | Leitura da pasta `storage/blueprints/`, upload/validação de JSON e criação a partir de link YouTube |
16
16
  | Brandings | Subaba própria dentro de Blueprints, upload/listagem de Brandings e criação conjunta com Blueprint |
17
17
  | Canais | Subabas de importação pública sem API Key, Data API opcional e cadastro manual independente |
18
- | Novo vídeo | Subabas Criar vídeo e Vídeos; lotes; 51 rótulos de idioma; Pexels/Pixabay, full IA com Estilo IA e Apenas Música com agente musical |
18
+ | Criação de Vídeos / Criação de Músicas | Subabas Criar vídeo e Vídeos; lotes; 51 rótulos de idioma; Pexels/Pixabay, full IA com Estilo IA e Apenas Música com agente musical; a segunda página reutiliza o mesmo fluxo com título próprio |
19
19
  | Automação | Lista de vídeos e canais, selectores editáveis de Blueprint/voz padrão, Automação ON e horário diário HH:MM; UI configurável sem worker em segundo plano |
20
20
  | Upload | YouTube via `youtube-automation-agent` adaptado internamente, OAuth directo de redundância, Upload directo experimental, TikTok, Instagram e Facebook Pages no front end |
21
21
  | MCP | Catálogo local opcional de Short Video Maker, AutoVio, OpenMontage e OpenCut, com portas editáveis e activação |
22
- | Limpador de metadado | Upload isolado de vídeos terceiros, limpeza FFmpeg, edição de título/descrição/tags e manifesto JSON |
23
- | Configurações | Provedores LLM, TTS/voz, preview de vozes, Suno, materiais, Whisper, FFmpeg, OAuth YouTube, Data API Key opcional, Upload directo, TikTok Client ID/Secret e Upload-Post |
22
+ | Limpador de Metadados | Upload isolado de vídeos terceiros, limpeza FFmpeg, edição de título/descrição/tags e manifesto JSON |
23
+ | Configurações Técnicas | Provedores LLM, TTS/voz, preview de vozes, Suno, materiais, Whisper, FFmpeg, OAuth YouTube, Data API Key opcional, Upload directo, TikTok Client ID/Secret e Upload-Post |
24
24
  | Launcher | Execução via `npx`, instalação assistida, diagnóstico e preparação para distribuição |
25
25
 
26
26
  Os adaptadores do MoneyPrinterTurbo e de publicação nas plataformas são ligados pelas configurações locais e pelos pontos de integração em `integrations/`. A UI não inventa dados quando um serviço externo ou credencial não está disponível.
27
27
 
28
+ ## Navegação da UI 0.2.28
29
+
30
+ A barra lateral mantém apenas os cinco níveis principais, nesta ordem: **Início**, **Pipeline**, **Automação**, **Niche Finder** e **Configurações**. **Pipeline** é expansível e contém **Criação de Vídeos**, **Criação de Músicas**, **Upload** e **Limpador de Metadados**. **Configurações** é expansível e contém **Canais**, **Blueprints**, **MCP** e **Configurações Técnicas**. O Início reúne o dashboard e as filas do Pipeline, sem botões de acções rápidas. Niche Finder permanece como placeholder vazio nesta versão.
31
+
28
32
  ## Instalação
29
33
 
30
34
  Recomenda-se Python 3.11 ou superior e Node.js 18 ou superior.
@@ -104,9 +108,9 @@ thunderbolt
104
108
  No Windows PowerShell, se `npx` for bloqueado por `npx.ps1`, use directamente `npx.cmd`:
105
109
 
106
110
  ```powershell
107
- npx.cmd --yes @danhachuel/thunderbolt@0.2.27 install
108
- npx.cmd --yes @danhachuel/thunderbolt@0.2.27 doctor
109
- npx.cmd --yes @danhachuel/thunderbolt@0.2.27
111
+ npx.cmd --yes @danhachuel/thunderbolt@0.2.28 install
112
+ npx.cmd --yes @danhachuel/thunderbolt@0.2.28 doctor
113
+ npx.cmd --yes @danhachuel/thunderbolt@0.2.28
110
114
  ```
111
115
 
112
116
  Como alternativa, pode permitir scripts para o seu utilizador:
@@ -159,9 +163,9 @@ A mesma aba possui a subaba **Brandings**. No formulário **Criar blueprint a pa
159
163
 
160
164
  O fluxo foi modelado a partir do blueprint de clonagem com Branding anexado, incluindo a distinção entre entrada de canal/vídeo, normalização do link, metadados de nicho/idioma, perfil do canal, estratégia de conteúdo, pesquisa, identidade visual e brand pack. Placeholders de serviços externos são tratados como configuração local; chaves presentes em workflows importados não devem ser commitadas.
161
165
 
162
- ## Limpador de metadado
166
+ ## Limpador de Metadados
163
167
 
164
- A aba **Limpador de metadado** foi adaptada do workflow `YTBMetadataGenerator.json`. Ela recebe apenas um vídeo externo já pronto, guarda uma cópia original separada, remove os metadados do contentor com FFmpeg e grava uma nova cópia com título, descrição, links, timestamps, tags e outros campos opcionais. O original nunca é alterado e os vídeos produzidos pela aba **Novo vídeo** não aparecem nesta área.
168
+ A aba **Limpador de Metadados** foi adaptada do workflow `YTBMetadataGenerator.json`. Ela recebe apenas um vídeo externo já pronto, guarda uma cópia original separada, remove os metadados do contentor com FFmpeg e grava uma nova cópia com título, descrição, links, timestamps, tags e outros campos opcionais. O original nunca é alterado e os vídeos produzidos pelas páginas **Criação de Vídeos** e **Criação de Músicas** não aparecem nesta área.
165
169
 
166
170
  A descrição segue a composição do workflow de referência: preview, secção de links e capítulos/timestamps. O resultado inclui um manifesto JSON para utilizar os metadados num fluxo posterior de upload. A versão local não usa o trigger RSS, o Apify ou a actualização automática de um vídeo YouTube; em vez disso, o utilizador fornece directamente o vídeo terceiro e controla a edição antes de publicar.
167
171
 
@@ -181,15 +185,16 @@ Use **Autorizar fallback OAuth** apenas se precisar de uma autorização separad
181
185
 
182
186
  A subaba **Upload directo** adapta o [YouTube-Video-Upload-Frontend-Api](https://github.com/Nojus10/YouTube-Video-Upload-Frontend-Api). Ela usa cookies, `sessionInfo`, `INNERTUBE_API_KEY` e `DELEGATED_SESSION_ID` fornecidos manualmente pelo utilizador, cria o vídeo através do endpoint interno e envia o ficheiro em chunks de 256 KiB. Este caminho é experimental, não extrai cookies automaticamente e fica separado do agente YouTube principal.
183
187
 
184
- ## Novo vídeo, Automação e música
188
+ ## Pipeline: Criação de Vídeos, Criação de Músicas e Automação
185
189
 
186
- Em **Novo vídeo**, o estilo visual `Pexels/Pixabay` é o modo de materiais, `full_ia` abre o selector **Estilo IA** com os 12 estilos solicitados e **Apenas Música** exige um áudio local, um upload musical ou um pedido ao endpoint Suno configurado. Neste último modo, a task fica com `background_mode=none`: não são gerados fundos Pexels/Pixabay nem fundos IA.
190
+ Em **Criação de Vídeos**, o estilo visual `Pexels/Pixabay` é o modo de materiais, `full_ia` abre o selector **Estilo IA** com os 12 estilos solicitados e **Apenas Música** exige um áudio local, um upload musical ou um pedido ao endpoint Suno configurado. **Criação de Músicas** reutiliza o mesmo conteúdo e formulário com título próprio. Neste último modo, a task fica com `background_mode=none`: não são gerados fundos Pexels/Pixabay nem fundos IA.
187
191
 
188
192
  O agente musical guarda os ficheiros em `storage/music/`, aceita formatos de áudio comuns e pode descarregar uma URL de áudio devolvida por um endpoint Suno compatível. Em **Canais**, abra **Definir Blueprint e voz padrão** no cartão do canal para guardar os defaults; em **Automação**, os mesmos dois selectores aparecem no cartão e são sincronizados. Esses valores são usados automaticamente em novas tarefas criadas para o canal. A aba **Automação** também guarda `Automação ON` e um horário diário `HH:MM` por canal e lista os vídeos cadastrados; por definição, esta entrega não executa workers de fundo.
189
193
 
190
194
  ## Teste de vozes
191
195
 
192
- A área **Configurações > Teste de vozes** é isolada da pipeline. Permite escolher Edge/Azure Speech ou um provider HTTP configurado, seleccionar voz/ID, alterar a velocidade, sintetizar uma amostra, reproduzi-la e descarregá-la. O áudio é guardado em `storage/voice_previews/` e nunca altera vídeos ou tarefas. Se uma instalação antiga não tiver `edge-tts`, execute `npx.cmd --yes @danhachuel/thunderbolt install`; o instalador detecta a dependência em falta sem reinstalar componentes válidos.
196
+ A área **Configurações > Configurações Técnicas > Teste de vozes** é isolada da pipeline.
197
+ Permite escolher Edge/Azure Speech ou um provider HTTP configurado, seleccionar voz/ID, alterar a velocidade, sintetizar uma amostra, reproduzi-la e descarregá-la. O áudio é guardado em `storage/voice_previews/` e nunca altera vídeos ou tarefas. Se uma instalação antiga não tiver `edge-tts`, execute `npx.cmd --yes @danhachuel/thunderbolt install`; o instalador detecta a dependência em falta sem reinstalar componentes válidos.
193
198
 
194
199
  ## MCP e integrações externas opcionais
195
200
 
@@ -204,9 +209,10 @@ As portas iniciais são `3123` para Short Video Maker, `3001` para a API backend
204
209
 
205
210
  ## TikTok
206
211
 
207
- A subaba **Vídeos**, dentro de **Novo vídeo**, mostra o backlog e permite iniciar/parar tarefas; deixou de existir como botão principal na barra lateral.
212
+ A subaba **Vídeos**, dentro de **Criação de Vídeos** ou **Criação de Músicas**, mostra o backlog e permite iniciar/parar tarefas; deixou de existir como botão principal na barra lateral.
208
213
 
209
- A aba **Configurações** contém apenas o TikTok Client ID e o TikTok Client Secret para TikTok. Para YouTube, o bloco principal pede o OAuth Client ID e Client Secret; a Data API Key, se usada, fica numa área opcional separada. Client ID + Client Secret não formam uma Data API Key nem um token OAuth.
214
+ A página **Configurações Técnicas** contém apenas o TikTok Client ID e o TikTok Client Secret para TikTok.
215
+ Para YouTube, o bloco principal pede o OAuth Client ID e Client Secret; a Data API Key, se usada, fica numa área opcional separada. Client ID + Client Secret não formam uma Data API Key nem um token OAuth.
210
216
  Redirect URI, scopes, autorização OAuth e tokens são geridos no TikTok for Developers Playground. O adaptador rejeita o upload quando faltam credenciais ou OAuth, em vez de indicar sucesso falso.
211
217
 
212
218
  ## Segurança
package/app/main.py CHANGED
@@ -125,6 +125,13 @@ st.markdown("""
125
125
  [data-testid="stSidebar"] [data-testid="stBaseButton-primary"]:hover { background:#343434; color:#ffffff; }
126
126
  [data-testid="stSidebar"] [data-testid="stBaseButton-primary"] span { color:#ffffff; }
127
127
  [data-testid="stSidebar"] [data-testid="stBaseButton-secondary"] span { color:#e7edf2; }
128
+ [data-testid="stSidebar"] [data-testid="stExpander"] { border:0 !important; background:transparent !important; margin:0.02rem 0 !important; }
129
+ [data-testid="stSidebar"] [data-testid="stExpander"] details { border:0 !important; background:transparent !important; }
130
+ [data-testid="stSidebar"] [data-testid="stExpander"] summary { min-height:1.72rem; padding:0.10rem 0.52rem !important; border-radius:7px; color:#e7edf2; font-size:0.86rem; font-weight:650; }
131
+ [data-testid="stSidebar"] [data-testid="stExpander"] summary:hover { background:#1c252e; }
132
+ [data-testid="stSidebar"] [data-testid="stExpander"] summary p { margin:0; line-height:1; }
133
+ [data-testid="stSidebar"] [data-testid="stExpander"] > div { padding:0 0 0 0.42rem !important; }
134
+ [data-testid="stSidebar"] [data-testid="stExpander"] > div [data-testid="stButton"] button { padding-left:0.92rem; font-size:0.83rem; min-height:1.62rem; height:1.62rem; }
128
135
  .content-card { padding: 1rem 1.1rem; border:1px solid #20384d; border-radius:14px; background:rgba(18,27,38,.92); min-height:110px; }
129
136
  .content-label { color:#8ba6bb; font-size:.8rem; text-transform:uppercase; letter-spacing:.07em; }
130
137
  .content-value { color:#f4f8fb; font-size:1.8rem; font-weight:700; margin-top:.3rem; }
@@ -212,27 +219,18 @@ def render_dashboard():
212
219
  with col:
213
220
  card(label, value, note)
214
221
  st.divider()
215
- left, right = st.columns([1.5, 1])
216
- with left:
217
- st.subheader("Pipeline")
218
- tasks = read_json("tasks.json", [])
219
- counts = {stage: sum(1 for t in tasks if t.get("stage") == stage and t.get("state") not in {"done", "cancelled"}) for stage in STAGES}
220
- for stage in STAGES:
221
- st.markdown(f'<div class="stage"><strong>{stage.title()}</strong> <span class="small-muted">{counts[stage]} tarefa(s)</span></div>', unsafe_allow_html=True)
222
- with right:
223
- st.subheader("Acções rápidas")
224
- if st.button("Criar novo vídeo", use_container_width=True):
225
- st.session_state["page"] = "Novo vídeo"
226
- st.rerun()
227
- if st.button("Importar canal", use_container_width=True):
228
- st.session_state["page"] = "Canais"
229
- st.rerun()
230
- if st.button("Abrir Blueprints", use_container_width=True):
231
- st.session_state["page"] = "Blueprints"
232
- st.rerun()
233
- if st.button("Abrir Upload", use_container_width=True):
234
- st.session_state["page"] = "Upload"
235
- st.rerun()
222
+ st.subheader("Pipeline")
223
+ st.caption("Filas locais e dependências da cascata")
224
+ queues = read_json("queues.json", {})
225
+ blueprint_count = len(list_blueprint_files())
226
+ for row_start in range(0, len(STAGES), 3):
227
+ queue_cols = st.columns(3)
228
+ for col, stage in zip(queue_cols, STAGES[row_start:row_start + 3]):
229
+ with col:
230
+ if stage == "blueprint":
231
+ card("Blueprints", blueprint_count, f"na biblioteca · {len(queues.get(stage, []))} tarefa(s) na fila")
232
+ else:
233
+ card(stage.title(), len(queues.get(stage, [])), "fila")
236
234
 
237
235
 
238
236
  def render_blueprints():
@@ -537,8 +535,8 @@ def render_channels():
537
535
  st.rerun()
538
536
 
539
537
 
540
- def render_new_video():
541
- st.title("Novo vídeo")
538
+ def render_new_video(page_title: str = "Criação de Vídeos"):
539
+ st.title(page_title)
542
540
  create_tab, videos_tab = st.tabs(["Criar vídeo", "Vídeos"])
543
541
  with create_tab:
544
542
  channels = channel_options()
@@ -623,6 +621,16 @@ def render_new_video():
623
621
  render_videos()
624
622
 
625
623
 
624
+ def render_music_creation():
625
+ """Expose the complete video-creation UI under the music-oriented navigation entry without changing the original page."""
626
+ render_new_video(page_title="Criação de Músicas")
627
+
628
+
629
+ def render_niche_finder():
630
+ st.title("Niche Finder")
631
+ st.info("Esta área está reservada para o Niche Finder e será implementada numa próxima etapa.")
632
+
633
+
626
634
  def render_videos():
627
635
  st.subheader("Vídeos e backlog")
628
636
  st.caption("Acompanhamento dos vídeos criados, estados da pipeline e controlos de execução.")
@@ -870,7 +878,7 @@ def render_upload_conventional():
870
878
 
871
879
 
872
880
  def render_settings():
873
- st.title("Configurações do Thunderbolt")
881
+ st.title("Configurações Técnicas")
874
882
  st.caption("Configuração do motor de vídeo e dos serviços usados pelo Thunderbolt. As credenciais ficam no storage local e não são enviadas para o GitHub.")
875
883
  settings = read_json("settings.json", {})
876
884
 
@@ -1216,7 +1224,7 @@ def render_mcp():
1216
1224
 
1217
1225
 
1218
1226
  def render_metadata_cleaner():
1219
- st.title("Limpador de metadado")
1227
+ st.title("Limpador de Metadados")
1220
1228
  st.caption("Limpeza e edição de metadados para vídeos de terceiros que já estão prontos.")
1221
1229
  st.warning("Esta área aceita exclusivamente vídeos externos. Vídeos criados na aba Novo vídeo não são listados nem processados aqui.")
1222
1230
 
@@ -1344,43 +1352,74 @@ def render_pipeline():
1344
1352
 
1345
1353
 
1346
1354
  def main():
1347
- pages = [
1348
- ("Dashboard", ":material/home:", "Início"),
1349
- ("Pipeline", ":material/account_tree:", "Pipeline"),
1350
- ("Blueprints", ":material/library_books:", "Blueprints"),
1351
- ("Canais", ":material/ondemand_video:", "Canais"),
1352
- ("Novo vídeo", ":material/add_circle:", "Novo vídeo"),
1353
- ("Automação", ":material/schedule:", "Automação"),
1355
+ pipeline_items = [
1356
+ ("Criação de Vídeos", ":material/add_circle:", "Criação de Vídeos"),
1357
+ ("Criação de Músicas", ":material/music_note:", "Criação de Músicas"),
1354
1358
  ("Upload", ":material/cloud_upload:", "Upload"),
1359
+ ("Limpador de Metadados", ":material/edit_note:", "Limpador de Metadados"),
1360
+ ]
1361
+ settings_items = [
1362
+ ("Canais", ":material/ondemand_video:", "Canais"),
1363
+ ("Blueprints", ":material/library_books:", "Blueprints"),
1355
1364
  ("MCP", ":material/hub:", "MCP"),
1356
- ("Limpador de metadado", ":material/edit_note:", "Limpador de metadado"),
1365
+ ("Configurações Técnicas", ":material/settings:", "Configurações Técnicas"),
1366
+ ]
1367
+ top_pages = [
1368
+ ("Início", ":material/home:", "Início"),
1369
+ ("Pipeline", ":material/account_tree:", "Pipeline"),
1370
+ ("Automação", ":material/schedule:", "Automação"),
1371
+ ("Niche Finder", ":material/search:", "Niche Finder"),
1357
1372
  ("Configurações", ":material/settings:", "Configurações"),
1358
1373
  ]
1359
- current_page = st.session_state.get("page", "Dashboard")
1360
- if current_page == "Vídeos":
1361
- current_page = "Novo vídeo"
1362
- st.session_state["page"] = current_page
1374
+ aliases = {
1375
+ "Dashboard": "Início",
1376
+ "Novo vídeo": "Criação de Vídeos",
1377
+ "Vídeos": "Criação de Vídeos",
1378
+ "Limpador de metadado": "Limpador de Metadados",
1379
+ "Configurações Técnicas": "Configurações Técnicas",
1380
+ }
1381
+ current_page = aliases.get(st.session_state.get("page", "Início"), st.session_state.get("page", "Início"))
1382
+ if current_page not in {item[0] for item in top_pages + pipeline_items + settings_items}:
1383
+ current_page = "Início"
1384
+ st.session_state["page"] = current_page
1385
+
1386
+ def navigate(target: str):
1387
+ st.session_state["page"] = target
1388
+ st.rerun()
1389
+
1390
+ def render_nav_button(target: str, icon: str, label: str, *, child: bool = False):
1391
+ if st.button(label, key=f"nav_{target}", icon=icon, use_container_width=True, type="primary" if current_page == target else "secondary"):
1392
+ navigate(target)
1393
+
1363
1394
  with st.sidebar:
1364
1395
  version_markup = f'<span class="tb-brand-version">{APP_VERSION}</span>' if APP_VERSION else ""
1365
1396
  st.markdown(f'<div class="tb-brand"><span class="tb-brand-name">Thunderbolt</span>{version_markup}</div>', unsafe_allow_html=True)
1366
- for target, icon, label in pages:
1367
- if st.button(label, key=f"nav_{target}", icon=icon, use_container_width=True, type="primary" if current_page == target else "secondary"):
1368
- st.session_state["page"] = target
1369
- st.rerun()
1397
+ for target, icon, label in top_pages:
1398
+ if target == "Pipeline":
1399
+ with st.expander("Pipeline", expanded=current_page in {item[0] for item in pipeline_items}, icon=":material/account_tree:"):
1400
+ for child_target, child_icon, child_label in pipeline_items:
1401
+ render_nav_button(child_target, child_icon, child_label, child=True)
1402
+ elif target == "Configurações":
1403
+ with st.expander("Configurações", expanded=current_page in {item[0] for item in settings_items}, icon=":material/settings:"):
1404
+ for child_target, child_icon, child_label in settings_items:
1405
+ render_nav_button(child_target, child_icon, child_label, child=True)
1406
+ else:
1407
+ render_nav_button(target, icon, label)
1408
+
1370
1409
  renderers = {
1371
- "Dashboard": render_dashboard,
1372
- "Pipeline": render_pipeline,
1373
- "Blueprints": render_blueprints,
1374
- "Canais": render_channels,
1375
- "Novo vídeo": render_new_video,
1410
+ "Início": render_dashboard,
1411
+ "Criação de Vídeos": render_new_video,
1412
+ "Criação de Músicas": render_music_creation,
1376
1413
  "Automação": render_automation,
1414
+ "Niche Finder": render_niche_finder,
1377
1415
  "Upload": render_upload,
1416
+ "Limpador de Metadados": render_metadata_cleaner,
1417
+ "Canais": render_channels,
1418
+ "Blueprints": render_blueprints,
1378
1419
  "MCP": render_mcp,
1379
- "Limpador de metadado": render_metadata_cleaner,
1380
- "Configurações": render_settings,
1420
+ "Configurações Técnicas": render_settings,
1381
1421
  }
1382
1422
  renderers.get(current_page, render_dashboard)()
1383
1423
 
1384
-
1385
1424
  if __name__ == "__main__":
1386
1425
  main()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danhachuel/thunderbolt",
3
- "version": "0.2.27",
3
+ "version": "0.2.28",
4
4
  "description": "Thunderbolt — interface local para operação de canais faceless e motor MoneyPrinterTurbo",
5
5
  "main": "scripts/cli.mjs",
6
6
  "type": "module",