- Adicionado estrutura completa do projeto - Configurado MCP server para Premiere Pro - Adicionado documentação e skills - Configurado Gitignore para o projeto
2057 lines
38 KiB
Markdown
2057 lines
38 KiB
Markdown
A seguir está um documento-base completo para orientar o desenvolvimento do **primeiro módulo funcional do sistema: leitura da timeline do Premiere por meio do MCP**.
|
|
|
|
Ele foi estruturado para servir como especificação técnica, guia de implementação e referência para os próximos módulos.
|
|
|
|
# Módulo de leitura da timeline do Premiere via MCP
|
|
|
|
## 1. Objetivo do módulo
|
|
|
|
O objetivo deste primeiro módulo é permitir que o sistema consiga:
|
|
|
|
1. Conectar-se ao MCP responsável pela integração com o Premiere;
|
|
2. Identificar se o Premiere está acessível;
|
|
3. Consultar a sequência ativa;
|
|
4. Ler as faixas de vídeo e áudio;
|
|
5. Ler os clipes presentes na timeline;
|
|
6. Obter as propriedades relevantes de cada clipe;
|
|
7. Converter a resposta bruta do MCP para objetos internos do sistema;
|
|
8. Validar os dados recebidos;
|
|
9. Armazenar o resultado em um modelo de domínio;
|
|
10. Disponibilizar essa informação para os próximos módulos do scanner.
|
|
|
|
Este módulo **não deverá realizar cortes, mover clipes, excluir elementos ou tomar decisões de edição**.
|
|
|
|
Ele terá somente a responsabilidade de **ler e representar a timeline atual**.
|
|
|
|
---
|
|
|
|
# 2. Princípio arquitetural
|
|
|
|
O módulo deverá seguir esta separação:
|
|
|
|
```text
|
|
Premiere Pro
|
|
↓
|
|
MCP do Premiere
|
|
↓
|
|
ClienteMCP
|
|
↓
|
|
AcessoAoEditor
|
|
↓
|
|
ConversorDeTimeline
|
|
↓
|
|
Modelos do domínio
|
|
↓
|
|
DescobertaDaTimeline
|
|
↓
|
|
ContextoDeAnalise
|
|
```
|
|
|
|
Cada camada possui uma responsabilidade específica.
|
|
|
|
| Camada | Responsabilidade |
|
|
| ---------------------- | ---------------------------------------------------------- |
|
|
| MCP | Disponibilizar ferramentas para comunicação com o Premiere |
|
|
| `ClienteMCP` | Executar chamadas técnicas ao MCP |
|
|
| `AcessoAoEditor` | Expor operações compreensíveis de leitura |
|
|
| `ConversorDeTimeline` | Converter respostas externas em objetos internos |
|
|
| Domínio | Representar projeto, sequência, faixas e clipes |
|
|
| `DescobertaDaTimeline` | Orquestrar a descoberta da timeline |
|
|
| `ContextoDeAnalise` | Armazenar os dados obtidos pelo scanner |
|
|
|
|
A regra fundamental é:
|
|
|
|
> Nenhuma classe do scanner deverá chamar diretamente uma ferramenta MCP pelo nome técnico.
|
|
|
|
Por exemplo, o scanner não deve fazer isto:
|
|
|
|
```python
|
|
cliente_mcp.chamar(
|
|
"get_active_sequence",
|
|
{}
|
|
)
|
|
```
|
|
|
|
Ele deve fazer isto:
|
|
|
|
```python
|
|
timeline = acesso_ao_editor.obter_timeline_ativa()
|
|
```
|
|
|
|
Assim, o scanner não fica dependente da implementação específica do MCP.
|
|
|
|
---
|
|
|
|
# 3. Escopo da primeira versão
|
|
|
|
A primeira versão deverá implementar somente a leitura.
|
|
|
|
## Incluído
|
|
|
|
* Conexão com o MCP;
|
|
* Teste de conectividade;
|
|
* Leitura da sequência ativa;
|
|
* Leitura das faixas;
|
|
* Leitura dos clipes;
|
|
* Leitura dos dados básicos dos clipes;
|
|
* Conversão dos dados;
|
|
* Validação;
|
|
* Registro de erros;
|
|
* Retorno estruturado;
|
|
* Testes com dados simulados.
|
|
|
|
## Não incluído inicialmente
|
|
|
|
* Corte de clipes;
|
|
* Exclusão de clipes;
|
|
* Movimentação de clipes;
|
|
* Aplicação de plano de edição;
|
|
* Transcrição;
|
|
* Análise visual;
|
|
* Detecção de cenas;
|
|
* Detecção de retakes;
|
|
* Análise de áudio;
|
|
* Decisão automática;
|
|
* Alteração da timeline;
|
|
* Execução de comandos destrutivos.
|
|
|
|
Essas funcionalidades serão adicionadas posteriormente.
|
|
|
|
---
|
|
|
|
# 4. Estrutura inicial de pastas
|
|
|
|
A estrutura inicial recomendada é:
|
|
|
|
```text
|
|
projeto/
|
|
│
|
|
├── integracoes/
|
|
│ └── premiere/
|
|
│ ├── __init__.py
|
|
│ │
|
|
│ ├── cliente_mcp.py
|
|
│ ├── sessao_mcp.py
|
|
│ ├── erros_mcp.py
|
|
│ │
|
|
│ ├── leitura/
|
|
│ │ ├── __init__.py
|
|
│ │ ├── acesso_ao_editor.py
|
|
│ │ ├── acesso_a_timeline.py
|
|
│ │ └── acesso_a_clipes.py
|
|
│ │
|
|
│ ├── conversores/
|
|
│ │ ├── __init__.py
|
|
│ │ ├── conversor_de_timeline.py
|
|
│ │ ├── conversor_de_faixas.py
|
|
│ │ └── conversor_de_clipes.py
|
|
│ │
|
|
│ └── contratos/
|
|
│ ├── __init__.py
|
|
│ └── contrato_de_acesso_ao_editor.py
|
|
│
|
|
├── dominio/
|
|
│ ├── __init__.py
|
|
│ │
|
|
│ ├── entidades/
|
|
│ │ ├── projeto.py
|
|
│ │ ├── sequencia.py
|
|
│ │ ├── timeline.py
|
|
│ │ ├── faixa.py
|
|
│ │ └── clipe.py
|
|
│ │
|
|
│ └── objetos_de_valor/
|
|
│ ├── intervalo_de_tempo.py
|
|
│ ├── tipo_de_midia.py
|
|
│ └── identificador_de_midia.py
|
|
│
|
|
├── scanner/
|
|
│ ├── __init__.py
|
|
│ │
|
|
│ ├── coordenacao/
|
|
│ │ ├── analisador_de_timeline.py
|
|
│ │ ├── pipeline_do_scanner.py
|
|
│ │ └── contexto_de_analise.py
|
|
│ │
|
|
│ └── descoberta/
|
|
│ └── descoberta_da_timeline.py
|
|
│
|
|
├── configuracao/
|
|
│ └── configuracao_do_scanner.py
|
|
│
|
|
└── testes/
|
|
├── integracoes/
|
|
├── dominio/
|
|
└── scanner/
|
|
```
|
|
|
|
Essa é uma estrutura inicial. Ela poderá ser expandida quando o projeto crescer.
|
|
|
|
---
|
|
|
|
# 5. Classe `ClienteMCP`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
integracoes/premiere/cliente_mcp.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
A classe `ClienteMCP` será responsável exclusivamente pela comunicação técnica com o servidor MCP.
|
|
|
|
Ela deverá:
|
|
|
|
* Estabelecer conexão;
|
|
* Encerrar conexão;
|
|
* Executar chamadas;
|
|
* Enviar argumentos;
|
|
* Receber respostas;
|
|
* Controlar timeout;
|
|
* Detectar erros de comunicação;
|
|
* Registrar informações técnicas;
|
|
* Retornar respostas brutas.
|
|
|
|
Ela não deverá:
|
|
|
|
* Interpretar clipes;
|
|
* Criar objetos de domínio;
|
|
* Saber o que é uma cena;
|
|
* Saber o que é um retake;
|
|
* Decidir qual ferramenta deve ser usada para descobrir a timeline;
|
|
* Executar regras de negócio.
|
|
|
|
## Interface conceitual
|
|
|
|
```python
|
|
class ClienteMCP:
|
|
"""Responsável pela comunicação técnica com o servidor MCP."""
|
|
|
|
def conectar(self) -> None:
|
|
"""Estabelece conexão com o servidor MCP."""
|
|
|
|
def desconectar(self) -> None:
|
|
"""Encerra a conexão com o servidor MCP."""
|
|
|
|
def esta_conectado(self) -> bool:
|
|
"""Informa se existe uma conexão ativa."""
|
|
|
|
def chamar(
|
|
self,
|
|
nome_da_ferramenta: str,
|
|
argumentos: dict | None = None,
|
|
) -> dict:
|
|
"""Executa uma ferramenta MCP e retorna a resposta bruta."""
|
|
```
|
|
|
|
## Exemplo de comportamento
|
|
|
|
```python
|
|
cliente = ClienteMCP()
|
|
|
|
cliente.conectar()
|
|
|
|
resposta = cliente.chamar(
|
|
nome_da_ferramenta="get_active_sequence",
|
|
argumentos={},
|
|
)
|
|
|
|
cliente.desconectar()
|
|
```
|
|
|
|
O nome `get_active_sequence` é apenas ilustrativo. O nome real deverá ser descoberto a partir das ferramentas efetivamente disponíveis no MCP utilizado.
|
|
|
|
## Regras
|
|
|
|
1. Não colocar lógica de conversão nessa classe.
|
|
2. Não colocar lógica de domínio nessa classe.
|
|
3. Não colocar lógica de scanner nessa classe.
|
|
4. Não criar métodos como `detectar_retake()` ou `obter_cenas()`.
|
|
5. Não misturar leitura e escrita nessa primeira versão.
|
|
6. Centralizar aqui o tratamento técnico de erros MCP.
|
|
|
|
---
|
|
|
|
# 6. Classe `SessaoMCP`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
integracoes/premiere/sessao_mcp.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
A classe `SessaoMCP` representará o estado da integração com o Premiere.
|
|
|
|
Ela poderá armazenar:
|
|
|
|
* Estado da conexão;
|
|
* Data da última conexão;
|
|
* Projeto identificado;
|
|
* Sequência ativa;
|
|
* Ferramentas disponíveis;
|
|
* Última chamada executada;
|
|
* Último erro ocorrido.
|
|
|
|
## Interface conceitual
|
|
|
|
```python
|
|
class SessaoMCP:
|
|
"""Representa o estado atual da comunicação com o Premiere."""
|
|
|
|
def __init__(self):
|
|
self.conectado = False
|
|
self.projeto_atual = None
|
|
self.sequencia_ativa = None
|
|
self.ultima_ferramenta_executada = None
|
|
self.ultimo_erro = None
|
|
```
|
|
|
|
## Observação
|
|
|
|
Na primeira implementação, essa classe pode ser simples. Ela não precisa controlar toda a conexão sozinha.
|
|
|
|
Sua função é evitar que informações de estado fiquem espalhadas em várias classes.
|
|
|
|
---
|
|
|
|
# 7. Classe `ErrosMCP`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
integracoes/premiere/erros_mcp.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Centralizar os erros relacionados à integração com o MCP.
|
|
|
|
## Classes sugeridas
|
|
|
|
```python
|
|
class ErroMCP(Exception):
|
|
"""Erro genérico relacionado à comunicação com o MCP."""
|
|
|
|
|
|
class ErroDeConexaoMCP(ErroMCP):
|
|
"""Erro ao conectar ou manter conexão com o MCP."""
|
|
|
|
|
|
class ErroDeFerramentaMCP(ErroMCP):
|
|
"""Erro ao executar uma ferramenta MCP."""
|
|
|
|
|
|
class ErroDeRespostaMCP(ErroMCP):
|
|
"""Erro quando a resposta do MCP é inválida ou incompleta."""
|
|
|
|
|
|
class FerramentaMCPNaoEncontrada(ErroMCP):
|
|
"""Erro quando a ferramenta solicitada não está disponível."""
|
|
```
|
|
|
|
## Por que isso é importante?
|
|
|
|
Sem erros específicos, o sistema teria apenas:
|
|
|
|
```python
|
|
raise Exception("Erro")
|
|
```
|
|
|
|
Com erros específicos, podemos distinguir:
|
|
|
|
* MCP indisponível;
|
|
* Ferramenta inexistente;
|
|
* Resposta inválida;
|
|
* Falta de sequência ativa;
|
|
* Permissão insuficiente;
|
|
* Timeout;
|
|
* Erro interno do Premiere.
|
|
|
|
Isso será importante para o scanner decidir se deve:
|
|
|
|
* Interromper a execução;
|
|
* Tentar novamente;
|
|
* Ignorar uma etapa;
|
|
* Registrar um aviso.
|
|
|
|
---
|
|
|
|
# 8. Classe `AcessoAoEditor`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
integracoes/premiere/leitura/acesso_ao_editor.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
A classe `AcessoAoEditor` será a principal porta de entrada para as operações de leitura do Premiere.
|
|
|
|
Ela deverá esconder os detalhes do MCP.
|
|
|
|
O restante do sistema deverá trabalhar com métodos de alto nível, como:
|
|
|
|
```python
|
|
obter_timeline_ativa()
|
|
obter_sequencia_ativa()
|
|
obter_faixas()
|
|
obter_clipes()
|
|
obter_detalhes_do_clipe()
|
|
```
|
|
|
|
## Interface conceitual
|
|
|
|
```python
|
|
class AcessoAoEditor:
|
|
"""Fornece operações estruturadas de leitura do editor."""
|
|
|
|
def obter_timeline_ativa(self):
|
|
"""Obtém os dados da timeline ativa."""
|
|
|
|
def obter_sequencia_ativa(self):
|
|
"""Obtém os dados da sequência ativa."""
|
|
|
|
def obter_faixas(self):
|
|
"""Obtém as faixas da sequência ativa."""
|
|
|
|
def obter_clipes(self):
|
|
"""Obtém os clipes presentes na timeline."""
|
|
|
|
def obter_detalhes_do_clipe(
|
|
self,
|
|
identificador_do_clipe: str,
|
|
):
|
|
"""Obtém detalhes de um clipe específico."""
|
|
```
|
|
|
|
## O que essa classe não deve fazer
|
|
|
|
Ela não deve:
|
|
|
|
* Converter diretamente para todos os objetos de domínio;
|
|
* Fazer transcrição;
|
|
* Detectar cenas;
|
|
* Executar cortes;
|
|
* Gerar plano de edição;
|
|
* Tomar decisões sobre retakes.
|
|
|
|
Sua responsabilidade é fornecer dados de leitura de maneira organizada.
|
|
|
|
---
|
|
|
|
# 9. Classe `AcessoATimeline`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
integracoes/premiere/leitura/acesso_a_timeline.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Especializar o acesso à estrutura da timeline.
|
|
|
|
Ela poderá:
|
|
|
|
* Obter a sequência ativa;
|
|
* Obter informações gerais da timeline;
|
|
* Obter duração;
|
|
* Obter taxa de quadros;
|
|
* Obter resolução;
|
|
* Obter faixas;
|
|
* Obter elementos posicionados na timeline.
|
|
|
|
## Interface conceitual
|
|
|
|
```python
|
|
class AcessoATimeline:
|
|
"""Realiza operações de leitura relacionadas à timeline."""
|
|
|
|
def __init__(self, cliente_mcp):
|
|
self.cliente_mcp = cliente_mcp
|
|
|
|
def obter_timeline_ativa(self):
|
|
"""Consulta a timeline ativa no Premiere."""
|
|
|
|
def obter_sequencia_ativa(self):
|
|
"""Consulta a sequência ativa."""
|
|
|
|
def obter_faixas(self):
|
|
"""Consulta as faixas da sequência ativa."""
|
|
```
|
|
|
|
## Exemplo conceitual
|
|
|
|
```python
|
|
class AcessoATimeline:
|
|
"""Realiza consultas estruturadas da timeline."""
|
|
|
|
def __init__(self, cliente_mcp):
|
|
self.cliente_mcp = cliente_mcp
|
|
|
|
def obter_sequencia_ativa(self):
|
|
"""Obtém a sequência ativa por meio do MCP."""
|
|
|
|
resposta = self.cliente_mcp.chamar(
|
|
nome_da_ferramenta="get_active_sequence",
|
|
argumentos={},
|
|
)
|
|
|
|
return resposta
|
|
```
|
|
|
|
O nome da ferramenta deverá ser substituído pelo nome real fornecido pelo MCP.
|
|
|
|
---
|
|
|
|
# 10. Classe `AcessoAClipes`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
integracoes/premiere/leitura/acesso_a_clipes.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Ler os clipes presentes na timeline.
|
|
|
|
Ela deverá obter informações como:
|
|
|
|
* Identificador;
|
|
* Nome;
|
|
* Nome do arquivo;
|
|
* Caminho do arquivo;
|
|
* Faixa;
|
|
* Início na timeline;
|
|
* Fim na timeline;
|
|
* Duração;
|
|
* Início utilizado no arquivo original;
|
|
* Fim utilizado no arquivo original;
|
|
* Tipo de mídia;
|
|
* Estado offline;
|
|
* Velocidade;
|
|
* Opacidade;
|
|
* Volume;
|
|
* Informações de vínculo;
|
|
* Informações de origem.
|
|
|
|
## Interface conceitual
|
|
|
|
```python
|
|
class AcessoAClipes:
|
|
"""Realiza operações de leitura dos clipes da timeline."""
|
|
|
|
def __init__(self, cliente_mcp):
|
|
self.cliente_mcp = cliente_mcp
|
|
|
|
def obter_clipes(self):
|
|
"""Obtém todos os clipes da timeline ativa."""
|
|
|
|
def obter_detalhes_do_clipe(
|
|
self,
|
|
identificador_do_clipe: str,
|
|
):
|
|
"""Obtém os detalhes de um clipe específico."""
|
|
```
|
|
|
|
## Regra importante
|
|
|
|
A classe deverá retornar dados brutos ou estruturas intermediárias.
|
|
|
|
A conversão para objetos como `Clipe` deverá ser feita pelo conversor.
|
|
|
|
---
|
|
|
|
# 11. Classe `ConversorDeTimeline`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
integracoes/premiere/conversores/conversor_de_timeline.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Converter a resposta do MCP para o modelo interno de `Timeline`.
|
|
|
|
O MCP pode retornar nomes e estruturas específicas. O sistema não deve depender diretamente delas.
|
|
|
|
## Interface conceitual
|
|
|
|
```python
|
|
class ConversorDeTimeline:
|
|
"""Converte dados brutos do Premiere em uma timeline do domínio."""
|
|
|
|
def converter(self, dados_brutos):
|
|
"""Converte os dados externos em uma entidade Timeline."""
|
|
```
|
|
|
|
## Exemplo
|
|
|
|
```python
|
|
class ConversorDeTimeline:
|
|
"""Converte uma resposta externa em uma Timeline interna."""
|
|
|
|
def converter(self, dados_brutos):
|
|
"""Cria uma Timeline a partir dos dados recebidos."""
|
|
|
|
timeline = Timeline(
|
|
identificador=dados_brutos["id"],
|
|
nome=dados_brutos["name"],
|
|
)
|
|
|
|
return timeline
|
|
```
|
|
|
|
## Responsabilidades adicionais
|
|
|
|
* Normalizar nomes de campos;
|
|
* Converter tempos;
|
|
* Converter identificadores;
|
|
* Garantir tipos corretos;
|
|
* Aplicar valores padrão;
|
|
* Validar campos obrigatórios;
|
|
* Ignorar campos desconhecidos;
|
|
* Registrar campos ausentes.
|
|
|
|
---
|
|
|
|
# 12. Classe `ConversorDeFaixas`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
integracoes/premiere/conversores/conversor_de_faixas.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Converter as faixas retornadas pelo MCP em objetos `Faixa`.
|
|
|
|
## Informações esperadas
|
|
|
|
* Identificador;
|
|
* Nome;
|
|
* Tipo da faixa;
|
|
* Índice;
|
|
* Ordem;
|
|
* Clipes pertencentes;
|
|
* Estado de bloqueio;
|
|
* Estado de visibilidade;
|
|
* Estado de ativação.
|
|
|
|
## Interface conceitual
|
|
|
|
```python
|
|
class ConversorDeFaixas:
|
|
"""Converte faixas externas em entidades do domínio."""
|
|
|
|
def converter(self, dados_brutos):
|
|
"""Converte os dados de uma faixa."""
|
|
```
|
|
|
|
## Tipos de faixa
|
|
|
|
O domínio deverá distinguir, pelo menos:
|
|
|
|
```python
|
|
class TipoDeFaixa(Enum):
|
|
VIDEO = "video"
|
|
AUDIO = "audio"
|
|
DESCONHECIDA = "desconhecida"
|
|
```
|
|
|
|
O tipo real deverá ser ajustado conforme os dados retornados pelo MCP.
|
|
|
|
---
|
|
|
|
# 13. Classe `ConversorDeClipes`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
integracoes/premiere/conversores/conversor_de_clipes.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Converter cada clipe externo em uma entidade `Clipe`.
|
|
|
|
## Interface conceitual
|
|
|
|
```python
|
|
class ConversorDeClipes:
|
|
"""Converte dados externos de clipes em entidades do domínio."""
|
|
|
|
def converter(self, dados_brutos):
|
|
"""Converte um clipe externo em um Clipe."""
|
|
```
|
|
|
|
## Exemplo de campos normalizados
|
|
|
|
```python
|
|
clipe = Clipe(
|
|
identificador="clip_001",
|
|
nome="Camera A",
|
|
arquivo="video_001.mov",
|
|
intervalo_na_timeline=IntervaloDeTempo(
|
|
inicio=10.0,
|
|
fim=25.0,
|
|
),
|
|
intervalo_na_origem=IntervaloDeTempo(
|
|
inicio=120.0,
|
|
fim=135.0,
|
|
),
|
|
identificador_da_faixa="video_1",
|
|
)
|
|
```
|
|
|
|
O modelo real deverá ser definido depois de observar uma resposta verdadeira do MCP.
|
|
|
|
---
|
|
|
|
# 14. Classe `Projeto`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
dominio/entidades/projeto.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Representar o projeto de edição.
|
|
|
|
## Campos iniciais
|
|
|
|
* Identificador;
|
|
* Nome;
|
|
* Caminho;
|
|
* Sequências;
|
|
* Data de leitura;
|
|
* Metadados adicionais.
|
|
|
|
## Exemplo
|
|
|
|
```python
|
|
class Projeto:
|
|
"""Representa um projeto de edição."""
|
|
|
|
def __init__(
|
|
self,
|
|
identificador,
|
|
nome,
|
|
caminho=None,
|
|
):
|
|
self.identificador = identificador
|
|
self.nome = nome
|
|
self.caminho = caminho
|
|
self.sequencias = []
|
|
```
|
|
|
|
---
|
|
|
|
# 15. Classe `Sequencia`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
dominio/entidades/sequencia.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Representar uma sequência de edição.
|
|
|
|
## Campos iniciais
|
|
|
|
* Identificador;
|
|
* Nome;
|
|
* Duração;
|
|
* Taxa de quadros;
|
|
* Resolução;
|
|
* Áudio;
|
|
* Faixas;
|
|
* Marcadores;
|
|
* Metadados.
|
|
|
|
## Exemplo
|
|
|
|
```python
|
|
class Sequencia:
|
|
"""Representa uma sequência de edição."""
|
|
|
|
def __init__(
|
|
self,
|
|
identificador,
|
|
nome,
|
|
duracao=None,
|
|
taxa_de_quadros=None,
|
|
):
|
|
self.identificador = identificador
|
|
self.nome = nome
|
|
self.duracao = duracao
|
|
self.taxa_de_quadros = taxa_de_quadros
|
|
self.faixas = []
|
|
```
|
|
|
|
---
|
|
|
|
# 16. Classe `Timeline`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
dominio/entidades/timeline.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Representar a estrutura completa da timeline que será analisada.
|
|
|
|
## Campos iniciais
|
|
|
|
* Identificador;
|
|
* Nome;
|
|
* Sequência;
|
|
* Faixas;
|
|
* Clipes;
|
|
* Duração;
|
|
* Taxa de quadros;
|
|
* Resolução;
|
|
* Metadados;
|
|
* Data da leitura;
|
|
* Origem dos dados.
|
|
|
|
## Exemplo
|
|
|
|
```python
|
|
class Timeline:
|
|
"""Representa uma timeline de edição."""
|
|
|
|
def __init__(
|
|
self,
|
|
identificador,
|
|
nome,
|
|
):
|
|
self.identificador = identificador
|
|
self.nome = nome
|
|
self.faixas = []
|
|
self.clipes = []
|
|
self.metadados = {}
|
|
```
|
|
|
|
## Regras
|
|
|
|
A `Timeline` não deve:
|
|
|
|
* Consultar o MCP;
|
|
* Ler arquivos;
|
|
* Executar comandos;
|
|
* Fazer análise de áudio;
|
|
* Detectar retakes.
|
|
|
|
Ela apenas representa os dados.
|
|
|
|
---
|
|
|
|
# 17. Classe `Faixa`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
dominio/entidades/faixa.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Representar uma faixa de vídeo ou áudio.
|
|
|
|
## Campos iniciais
|
|
|
|
* Identificador;
|
|
* Nome;
|
|
* Tipo;
|
|
* Índice;
|
|
* Clipes;
|
|
* Estado de bloqueio;
|
|
* Estado de visibilidade;
|
|
* Estado de ativação.
|
|
|
|
## Exemplo
|
|
|
|
```python
|
|
class Faixa:
|
|
"""Representa uma faixa de vídeo ou áudio."""
|
|
|
|
def __init__(
|
|
self,
|
|
identificador,
|
|
nome,
|
|
tipo,
|
|
indice,
|
|
):
|
|
self.identificador = identificador
|
|
self.nome = nome
|
|
self.tipo = tipo
|
|
self.indice = indice
|
|
self.clipes = []
|
|
```
|
|
|
|
---
|
|
|
|
# 18. Classe `Clipe`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
dominio/entidades/clipe.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Representar um clipe de mídia presente na timeline.
|
|
|
|
## Campos iniciais
|
|
|
|
* Identificador;
|
|
* Nome;
|
|
* Arquivo de origem;
|
|
* Caminho do arquivo;
|
|
* Tipo de mídia;
|
|
* Faixa;
|
|
* Intervalo na timeline;
|
|
* Intervalo na origem;
|
|
* Duração;
|
|
* Estado offline;
|
|
* Velocidade;
|
|
* Opacidade;
|
|
* Volume;
|
|
* Dados de vínculo;
|
|
* Metadados;
|
|
* Informações de origem.
|
|
|
|
## Exemplo
|
|
|
|
```python
|
|
class Clipe:
|
|
"""Representa um clipe de mídia na timeline."""
|
|
|
|
def __init__(
|
|
self,
|
|
identificador,
|
|
nome,
|
|
intervalo_na_timeline,
|
|
intervalo_na_origem=None,
|
|
arquivo=None,
|
|
identificador_da_faixa=None,
|
|
):
|
|
self.identificador = identificador
|
|
self.nome = nome
|
|
self.intervalo_na_timeline = intervalo_na_timeline
|
|
self.intervalo_na_origem = intervalo_na_origem
|
|
self.arquivo = arquivo
|
|
self.identificador_da_faixa = identificador_da_faixa
|
|
self.metadados = {}
|
|
```
|
|
|
|
---
|
|
|
|
# 19. Classe `IntervaloDeTempo`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
dominio/objetos_de_valor/intervalo_de_tempo.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Representar um intervalo temporal válido.
|
|
|
|
Ele será utilizado para:
|
|
|
|
* Posição de clipes;
|
|
* Duração;
|
|
* Trechos de áudio;
|
|
* Segmentos de transcrição;
|
|
* Cenas;
|
|
* Retakes;
|
|
* Operações de corte.
|
|
|
|
## Exemplo
|
|
|
|
```python
|
|
class IntervaloDeTempo:
|
|
"""Representa um intervalo temporal."""
|
|
|
|
def __init__(self, inicio, fim):
|
|
if inicio < 0:
|
|
raise ValueError(
|
|
"O início não pode ser negativo."
|
|
)
|
|
|
|
if fim < inicio:
|
|
raise ValueError(
|
|
"O fim não pode ser anterior ao início."
|
|
)
|
|
|
|
self.inicio = inicio
|
|
self.fim = fim
|
|
|
|
@property
|
|
def duracao(self):
|
|
"""Retorna a duração do intervalo."""
|
|
|
|
return self.fim - self.inicio
|
|
```
|
|
|
|
## Métodos futuros
|
|
|
|
```python
|
|
def contem(self, instante):
|
|
"""Verifica se um instante está dentro do intervalo."""
|
|
|
|
def sobrepoe(self, outro):
|
|
"""Verifica se dois intervalos se sobrepõem."""
|
|
|
|
def intersecao(self, outro):
|
|
"""Retorna a interseção entre dois intervalos."""
|
|
```
|
|
|
|
---
|
|
|
|
# 20. Contrato `ContratoDeAcessoAoEditor`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
integracoes/premiere/contratos/contrato_de_acesso_ao_editor.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Definir o contrato que qualquer integração de editor deverá cumprir.
|
|
|
|
Isso permitirá futuramente utilizar:
|
|
|
|
* Premiere;
|
|
* OpenCut;
|
|
* DaVinci Resolve;
|
|
* Outro editor;
|
|
* Simulador para testes.
|
|
|
|
## Exemplo
|
|
|
|
```python
|
|
from abc import ABC, abstractmethod
|
|
|
|
|
|
class ContratoDeAcessoAoEditor(ABC):
|
|
"""Define operações mínimas de leitura de um editor."""
|
|
|
|
@abstractmethod
|
|
def obter_timeline_ativa(self):
|
|
"""Obtém a timeline ativa."""
|
|
raise NotImplementedError
|
|
|
|
@abstractmethod
|
|
def obter_clipes(self):
|
|
"""Obtém os clipes da timeline."""
|
|
raise NotImplementedError
|
|
|
|
@abstractmethod
|
|
def obter_faixas(self):
|
|
"""Obtém as faixas da timeline."""
|
|
raise NotImplementedError
|
|
```
|
|
|
|
## Benefício
|
|
|
|
A classe `DescobertaDaTimeline` poderá depender desse contrato:
|
|
|
|
```python
|
|
class DescobertaDaTimeline:
|
|
"""Descobre a timeline por meio de uma integração de editor."""
|
|
|
|
def __init__(self, acesso_ao_editor):
|
|
self.acesso_ao_editor = acesso_ao_editor
|
|
```
|
|
|
|
Assim, ela não saberá se os dados vieram do Premiere ou de um simulador.
|
|
|
|
---
|
|
|
|
# 21. Classe `DescobertaDaTimeline`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
scanner/descoberta/descoberta_da_timeline.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Orquestrar a descoberta da timeline.
|
|
|
|
Ela deverá:
|
|
|
|
1. Solicitar a timeline ao acesso do editor;
|
|
2. Receber os dados externos;
|
|
3. Converter os dados;
|
|
4. Validar o resultado;
|
|
5. Armazenar a timeline no contexto;
|
|
6. Retornar o contexto atualizado.
|
|
|
|
## Ela não deverá
|
|
|
|
* Chamar diretamente o MCP;
|
|
* Saber o nome das ferramentas MCP;
|
|
* Fazer transcrição;
|
|
* Fazer análise visual;
|
|
* Detectar retakes;
|
|
* Aplicar cortes;
|
|
* Gerar plano de edição.
|
|
|
|
## Exemplo
|
|
|
|
```python
|
|
class DescobertaDaTimeline:
|
|
"""Descobre a estrutura da timeline do editor."""
|
|
|
|
def __init__(
|
|
self,
|
|
acesso_ao_editor,
|
|
conversor_de_timeline,
|
|
):
|
|
self.acesso_ao_editor = acesso_ao_editor
|
|
self.conversor_de_timeline = conversor_de_timeline
|
|
|
|
def executar(self, contexto):
|
|
"""Obtém, converte e armazena a timeline."""
|
|
|
|
dados_brutos = (
|
|
self.acesso_ao_editor.obter_timeline_ativa()
|
|
)
|
|
|
|
timeline = (
|
|
self.conversor_de_timeline.converter(
|
|
dados_brutos
|
|
)
|
|
)
|
|
|
|
contexto.timeline = timeline
|
|
|
|
return contexto
|
|
```
|
|
|
|
---
|
|
|
|
# 22. Classe `ContextoDeAnalise`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
scanner/coordenacao/contexto_de_analise.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Transportar os dados durante o processo de análise.
|
|
|
|
Ele deverá armazenar:
|
|
|
|
* Timeline;
|
|
* Projeto;
|
|
* Sequência;
|
|
* Clipes;
|
|
* Faixas;
|
|
* Arquivos;
|
|
* Metadados;
|
|
* Áudios;
|
|
* Transcrições;
|
|
* Cenas;
|
|
* Eventos;
|
|
* Retakes;
|
|
* Avisos;
|
|
* Erros;
|
|
* Status;
|
|
* Informações de execução.
|
|
|
|
## Exemplo
|
|
|
|
```python
|
|
class ContextoDeAnalise:
|
|
"""Armazena os dados produzidos durante a análise."""
|
|
|
|
def __init__(self):
|
|
self.projeto = None
|
|
self.timeline = None
|
|
self.clipes = []
|
|
self.faixas = []
|
|
self.metadados = {}
|
|
self.avisos = []
|
|
self.erros = []
|
|
```
|
|
|
|
## Regra
|
|
|
|
O contexto não deve executar análises.
|
|
|
|
Ele apenas transporta e armazena informações.
|
|
|
|
---
|
|
|
|
# 23. Classe `PipelineDoScanner`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
scanner/coordenacao/pipeline_do_scanner.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Executar as etapas de análise na ordem definida.
|
|
|
|
Na primeira versão, o pipeline poderá conter apenas:
|
|
|
|
```text
|
|
DescobertaDaTimeline
|
|
```
|
|
|
|
Posteriormente, serão adicionadas:
|
|
|
|
```text
|
|
DescobertaDeClipes
|
|
DescobertaDeArquivos
|
|
ExtracaoDeMetadados
|
|
ExtracaoDeAudio
|
|
TranscricaoDeAudio
|
|
AnaliseVisual
|
|
DeteccaoDeCenas
|
|
DeteccaoDeRetakes
|
|
```
|
|
|
|
## Exemplo
|
|
|
|
```python
|
|
class PipelineDoScanner:
|
|
"""Coordena a execução das etapas do scanner."""
|
|
|
|
def __init__(self, etapas):
|
|
self.etapas = etapas
|
|
|
|
def executar(self, contexto):
|
|
"""Executa todas as etapas na ordem definida."""
|
|
|
|
for etapa in self.etapas:
|
|
contexto = etapa.executar(contexto)
|
|
|
|
return contexto
|
|
```
|
|
|
|
## Regra
|
|
|
|
O pipeline não deve:
|
|
|
|
* Conhecer detalhes do MCP;
|
|
* Conhecer nomes de ferramentas externas;
|
|
* Implementar transcrição;
|
|
* Implementar análise visual;
|
|
* Tomar decisões de edição.
|
|
|
|
Ele apenas coordena as etapas.
|
|
|
|
---
|
|
|
|
# 24. Classe `AnalisadorDeTimeline`
|
|
|
|
Arquivo:
|
|
|
|
```text
|
|
scanner/coordenacao/analisador_de_timeline.py
|
|
```
|
|
|
|
## Responsabilidade
|
|
|
|
Ser o ponto de entrada do processo de análise.
|
|
|
|
Ela deverá:
|
|
|
|
1. Receber a configuração;
|
|
2. Criar o contexto;
|
|
3. Iniciar o pipeline;
|
|
4. Retornar o resultado.
|
|
|
|
## Exemplo
|
|
|
|
```python
|
|
class AnalisadorDeTimeline:
|
|
"""Coordena o processo completo de análise da timeline."""
|
|
|
|
def __init__(self, pipeline):
|
|
self.pipeline = pipeline
|
|
|
|
def analisar(self):
|
|
"""Executa o processo de análise."""
|
|
|
|
contexto = ContextoDeAnalise()
|
|
|
|
return self.pipeline.executar(contexto)
|
|
```
|
|
|
|
## Regra
|
|
|
|
Essa classe não deverá implementar as análises diretamente.
|
|
|
|
Ela apenas inicia o processo.
|
|
|
|
---
|
|
|
|
# 25. Fluxo completo da primeira versão
|
|
|
|
O fluxo deverá ser:
|
|
|
|
```text
|
|
AnalisadorDeTimeline
|
|
↓
|
|
Cria ContextoDeAnalise
|
|
↓
|
|
PipelineDoScanner
|
|
↓
|
|
DescobertaDaTimeline
|
|
↓
|
|
AcessoAoEditor
|
|
↓
|
|
AcessoATimeline
|
|
↓
|
|
ClienteMCP
|
|
↓
|
|
MCP do Premiere
|
|
↓
|
|
Resposta bruta
|
|
↓
|
|
ConversorDeTimeline
|
|
↓
|
|
Timeline do domínio
|
|
↓
|
|
ContextoDeAnalise
|
|
↓
|
|
Resultado final
|
|
```
|
|
|
|
---
|
|
|
|
# 26. Exemplo de montagem dos componentes
|
|
|
|
A composição inicial poderá ser semelhante a:
|
|
|
|
```python
|
|
cliente_mcp = ClienteMCP()
|
|
|
|
acesso_a_timeline = AcessoATimeline(
|
|
cliente_mcp=cliente_mcp,
|
|
)
|
|
|
|
acesso_ao_editor = AcessoAoEditor(
|
|
acesso_a_timeline=acesso_a_timeline,
|
|
)
|
|
|
|
conversor_de_timeline = ConversorDeTimeline()
|
|
|
|
descoberta_da_timeline = DescobertaDaTimeline(
|
|
acesso_ao_editor=acesso_ao_editor,
|
|
conversor_de_timeline=conversor_de_timeline,
|
|
)
|
|
|
|
pipeline = PipelineDoScanner(
|
|
etapas=[
|
|
descoberta_da_timeline,
|
|
],
|
|
)
|
|
|
|
analisador = AnalisadorDeTimeline(
|
|
pipeline=pipeline,
|
|
)
|
|
|
|
resultado = analisador.analisar()
|
|
```
|
|
|
|
A forma exata dependerá da implementação real do cliente MCP.
|
|
|
|
---
|
|
|
|
# 27. Primeira etapa prática: descobrir as ferramentas do MCP
|
|
|
|
Antes de escrever a integração definitiva, será necessário identificar exatamente:
|
|
|
|
1. Como o MCP é iniciado;
|
|
2. Como o cliente se conecta;
|
|
3. Quais ferramentas estão disponíveis;
|
|
4. Como consultar a sequência ativa;
|
|
5. Como consultar as faixas;
|
|
6. Como consultar os clipes;
|
|
7. Como obter detalhes de um clipe;
|
|
8. Qual é o formato de resposta;
|
|
9. Como os tempos são representados;
|
|
10. Como os identificadores são representados;
|
|
11. Como erros são retornados;
|
|
12. Se o MCP permite chamadas encadeadas;
|
|
13. Se existe necessidade de manter sessão;
|
|
14. Se as respostas são síncronas ou assíncronas.
|
|
|
|
Não se deve inventar os nomes das ferramentas.
|
|
|
|
Os nomes usados no código deverão ser baseados na implementação real do MCP disponível no ambiente.
|
|
|
|
---
|
|
|
|
# 28. Estratégia para descobrir a API real
|
|
|
|
O desenvolvimento deverá seguir esta ordem:
|
|
|
|
## Passo 1 — Verificar conexão
|
|
|
|
Criar um teste mínimo que confirme:
|
|
|
|
```text
|
|
O cliente consegue se conectar?
|
|
```
|
|
|
|
## Passo 2 — Listar ferramentas
|
|
|
|
Obter a lista de ferramentas disponíveis no MCP.
|
|
|
|
Registrar:
|
|
|
|
* Nome;
|
|
* Descrição;
|
|
* Argumentos;
|
|
* Tipos;
|
|
* Retorno;
|
|
* Erros possíveis.
|
|
|
|
## Passo 3 — Executar uma consulta simples
|
|
|
|
Por exemplo:
|
|
|
|
```text
|
|
Obter informações do projeto atual
|
|
```
|
|
|
|
## Passo 4 — Consultar a sequência ativa
|
|
|
|
Identificar:
|
|
|
|
* Nome;
|
|
* ID;
|
|
* Duração;
|
|
* FPS;
|
|
* Resolução;
|
|
* Número de faixas.
|
|
|
|
## Passo 5 — Consultar as faixas
|
|
|
|
Identificar:
|
|
|
|
* Faixas de vídeo;
|
|
* Faixas de áudio;
|
|
* Ordem;
|
|
* Índices;
|
|
* IDs.
|
|
|
|
## Passo 6 — Consultar os clipes
|
|
|
|
Identificar todos os campos retornados.
|
|
|
|
## Passo 7 — Salvar uma resposta real
|
|
|
|
As respostas reais deverão ser armazenadas em arquivos de teste, por exemplo:
|
|
|
|
```text
|
|
testes/fixtures/
|
|
├── projeto.json
|
|
├── sequencia.json
|
|
├── faixas.json
|
|
└── clipes.json
|
|
```
|
|
|
|
Esses arquivos serão usados para testar os conversores sem precisar abrir o Premiere em todos os testes.
|
|
|
|
---
|
|
|
|
# 29. Modelo de resposta bruta
|
|
|
|
O formato abaixo é apenas um exemplo conceitual:
|
|
|
|
```json
|
|
{
|
|
"id": "sequence_001",
|
|
"name": "Sequência principal",
|
|
"duration": 120.5,
|
|
"frame_rate": 29.97,
|
|
"width": 1920,
|
|
"height": 1080,
|
|
"video_tracks": [
|
|
{
|
|
"id": "video_1",
|
|
"name": "V1",
|
|
"index": 1,
|
|
"clips": [
|
|
{
|
|
"id": "clip_001",
|
|
"name": "Camera A",
|
|
"source_file": "/videos/camera_a.mov",
|
|
"timeline_start": 0.0,
|
|
"timeline_end": 12.5,
|
|
"source_start": 35.2,
|
|
"source_end": 47.7
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"audio_tracks": []
|
|
}
|
|
```
|
|
|
|
Esse formato não deve ser considerado definitivo.
|
|
|
|
O formato definitivo deverá ser obtido diretamente do MCP real.
|
|
|
|
---
|
|
|
|
# 30. Validação dos dados recebidos
|
|
|
|
Antes de converter os dados, o sistema deverá verificar:
|
|
|
|
## Timeline
|
|
|
|
* Existe identificador?
|
|
* Existe nome?
|
|
* A duração é válida?
|
|
* A taxa de quadros é válida?
|
|
* A resolução é válida?
|
|
|
|
## Faixas
|
|
|
|
* Existe identificador?
|
|
* Existe tipo?
|
|
* Existe índice?
|
|
* A lista de clipes é válida?
|
|
|
|
## Clipes
|
|
|
|
* Existe identificador?
|
|
* Existe posição inicial?
|
|
* Existe posição final?
|
|
* O fim é maior que o início?
|
|
* O arquivo de origem foi informado?
|
|
* O clipe está offline?
|
|
* A faixa existe?
|
|
|
|
## Erros de validação
|
|
|
|
A validação não deve simplesmente gerar um erro genérico.
|
|
|
|
Deverá registrar informações como:
|
|
|
|
```text
|
|
Campo ausente: timeline.id
|
|
Clipe inválido: clip_004
|
|
Intervalo inválido: início maior que fim
|
|
Faixa desconhecida: audio_99
|
|
Arquivo de origem não encontrado
|
|
```
|
|
|
|
---
|
|
|
|
# 31. Tratamento de timeline vazia
|
|
|
|
O sistema deverá tratar corretamente situações como:
|
|
|
|
* Nenhuma sequência ativa;
|
|
* Sequência sem clipes;
|
|
* Sequência sem faixas;
|
|
* Timeline vazia;
|
|
* Projeto recém-criado;
|
|
* Projeto com mídia offline.
|
|
|
|
Essas situações não devem necessariamente ser consideradas falhas técnicas.
|
|
|
|
Por exemplo:
|
|
|
|
```text
|
|
Sequência encontrada, mas sem clipes.
|
|
```
|
|
|
|
Isso pode ser um resultado válido.
|
|
|
|
O sistema deverá diferenciar:
|
|
|
|
```text
|
|
Falha de comunicação
|
|
```
|
|
|
|
de:
|
|
|
|
```text
|
|
Timeline válida, porém vazia
|
|
```
|
|
|
|
---
|
|
|
|
# 32. Tratamento de mídia offline
|
|
|
|
Um clipe offline não deve impedir a leitura completa da timeline.
|
|
|
|
O objeto `Clipe` deverá conter algo como:
|
|
|
|
```python
|
|
clipe.offline = True
|
|
```
|
|
|
|
O sistema deverá manter:
|
|
|
|
* ID do clipe;
|
|
* Nome;
|
|
* Posição na timeline;
|
|
* Duração;
|
|
* Faixa;
|
|
* Caminho informado;
|
|
* Estado offline.
|
|
|
|
A análise do arquivo físico poderá ser realizada posteriormente pelo módulo de descoberta de arquivos.
|
|
|
|
---
|
|
|
|
# 33. Separação entre posição na timeline e posição na origem
|
|
|
|
Esse é um ponto fundamental.
|
|
|
|
Um clipe possui pelo menos dois intervalos:
|
|
|
|
## Intervalo na timeline
|
|
|
|
Onde o clipe está colocado na sequência.
|
|
|
|
```text
|
|
Início: 30 segundos
|
|
Fim: 45 segundos
|
|
```
|
|
|
|
## Intervalo na mídia original
|
|
|
|
Qual trecho do arquivo de origem está sendo utilizado.
|
|
|
|
```text
|
|
Início: 120 segundos
|
|
Fim: 135 segundos
|
|
```
|
|
|
|
Esses intervalos não devem ser misturados.
|
|
|
|
O modelo deverá representar ambos:
|
|
|
|
```python
|
|
clipe.intervalo_na_timeline
|
|
clipe.intervalo_na_origem
|
|
```
|
|
|
|
Essa distinção será essencial para:
|
|
|
|
* Detectar retakes;
|
|
* Encontrar repetições;
|
|
* Comparar trechos;
|
|
* Reconstruir a origem;
|
|
* Criar cortes;
|
|
* Validar operações;
|
|
* Relacionar clipes com arquivos originais.
|
|
|
|
---
|
|
|
|
# 34. Identificadores
|
|
|
|
O sistema deverá preservar os identificadores externos, mas também poderá criar identificadores internos.
|
|
|
|
Exemplo:
|
|
|
|
```python
|
|
clipe.identificador_externo
|
|
clipe.identificador_interno
|
|
```
|
|
|
|
O identificador externo será usado para conversar novamente com o Premiere.
|
|
|
|
O identificador interno será usado pelo domínio e pelos módulos internos.
|
|
|
|
Não se deve presumir que o nome do clipe seja único.
|
|
|
|
O nome:
|
|
|
|
```text
|
|
Camera A
|
|
```
|
|
|
|
pode aparecer várias vezes.
|
|
|
|
A identificação deverá utilizar IDs sempre que possível.
|
|
|
|
---
|
|
|
|
# 35. Registro de logs
|
|
|
|
O módulo deverá registrar logs em pontos importantes:
|
|
|
|
## Conexão
|
|
|
|
```text
|
|
Conectando ao MCP do Premiere
|
|
Conexão estabelecida
|
|
Conexão encerrada
|
|
```
|
|
|
|
## Leitura
|
|
|
|
```text
|
|
Consultando sequência ativa
|
|
Consultando faixas
|
|
Consultando clipes
|
|
```
|
|
|
|
## Conversão
|
|
|
|
```text
|
|
Convertendo timeline
|
|
Convertendo faixa video_1
|
|
Convertendo clipe clip_001
|
|
```
|
|
|
|
## Erros
|
|
|
|
```text
|
|
Falha ao consultar clipes
|
|
Resposta MCP inválida
|
|
Campo obrigatório ausente
|
|
```
|
|
|
|
Os logs não devem registrar informações sensíveis desnecessárias.
|
|
|
|
---
|
|
|
|
# 36. Testes necessários
|
|
|
|
## Testes do `ClienteMCP`
|
|
|
|
* Conecta corretamente;
|
|
* Desconecta corretamente;
|
|
* Executa uma chamada;
|
|
* Trata timeout;
|
|
* Trata ferramenta inexistente;
|
|
* Trata resposta inválida;
|
|
* Trata conexão indisponível.
|
|
|
|
## Testes do `AcessoATimeline`
|
|
|
|
* Obtém sequência ativa;
|
|
* Obtém faixas;
|
|
* Obtém timeline vazia;
|
|
* Trata ausência de sequência;
|
|
* Encaminha corretamente a chamada ao cliente MCP.
|
|
|
|
## Testes dos conversores
|
|
|
|
* Converte timeline válida;
|
|
* Converte faixa válida;
|
|
* Converte clipe válido;
|
|
* Trata campo ausente;
|
|
* Trata intervalo inválido;
|
|
* Trata tipo desconhecido;
|
|
* Trata lista vazia;
|
|
* Trata campos adicionais.
|
|
|
|
## Testes do domínio
|
|
|
|
* Cria intervalo válido;
|
|
* Rejeita intervalo inválido;
|
|
* Calcula duração;
|
|
* Cria clipe;
|
|
* Cria faixa;
|
|
* Cria timeline.
|
|
|
|
## Testes do scanner
|
|
|
|
* Executa a descoberta;
|
|
* Armazena a timeline no contexto;
|
|
* Propaga erros;
|
|
* Retorna contexto atualizado;
|
|
* Funciona com integração simulada.
|
|
|
|
---
|
|
|
|
# 37. Integração simulada para testes
|
|
|
|
Deverá existir uma implementação simulada do acesso ao editor.
|
|
|
|
Arquivo sugerido:
|
|
|
|
```text
|
|
testes/fakes/acesso_ao_editor_simulado.py
|
|
```
|
|
|
|
Exemplo:
|
|
|
|
```python
|
|
class AcessoAoEditorSimulado:
|
|
"""Fornece dados fictícios de uma timeline para testes."""
|
|
|
|
def __init__(self, dados_da_timeline):
|
|
self.dados_da_timeline = dados_da_timeline
|
|
|
|
def obter_timeline_ativa(self):
|
|
"""Retorna uma timeline simulada."""
|
|
|
|
return self.dados_da_timeline
|
|
```
|
|
|
|
Isso permite testar:
|
|
|
|
```text
|
|
Scanner
|
|
↓
|
|
Acesso simulado
|
|
↓
|
|
Dados JSON
|
|
```
|
|
|
|
sem depender do Premiere.
|
|
|
|
---
|
|
|
|
# 38. Critérios de conclusão da primeira versão
|
|
|
|
O módulo será considerado concluído quando conseguir:
|
|
|
|
* Conectar ao MCP real;
|
|
* Identificar as ferramentas disponíveis;
|
|
* Consultar a sequência ativa;
|
|
* Consultar as faixas;
|
|
* Consultar os clipes;
|
|
* Retornar dados sem depender do formato bruto do MCP;
|
|
* Converter os dados para objetos de domínio;
|
|
* Identificar clipes offline;
|
|
* Diferenciar intervalo da timeline e intervalo da origem;
|
|
* Tratar timeline vazia;
|
|
* Tratar erros de conexão;
|
|
* Tratar respostas incompletas;
|
|
* Executar testes automatizados;
|
|
* Produzir logs;
|
|
* Ser utilizado pelo `Scanner`;
|
|
* Não executar nenhuma alteração na timeline.
|
|
|
|
---
|
|
|
|
# 39. Ordem recomendada de implementação
|
|
|
|
A implementação deverá ocorrer nesta ordem:
|
|
|
|
## Fase 1 — Estrutura
|
|
|
|
Criar:
|
|
|
|
```text
|
|
integracoes/premiere/
|
|
dominio/
|
|
scanner/
|
|
testes/
|
|
```
|
|
|
|
## Fase 2 — Cliente MCP
|
|
|
|
Implementar:
|
|
|
|
```text
|
|
ClienteMCP
|
|
SessaoMCP
|
|
ErrosMCP
|
|
```
|
|
|
|
## Fase 3 — Descoberta da API
|
|
|
|
* Listar ferramentas;
|
|
* Identificar nomes;
|
|
* Identificar argumentos;
|
|
* Capturar respostas reais.
|
|
|
|
## Fase 4 — Leitura técnica
|
|
|
|
Implementar:
|
|
|
|
```text
|
|
AcessoATimeline
|
|
AcessoAClipes
|
|
AcessoAoEditor
|
|
```
|
|
|
|
## Fase 5 — Modelos de domínio
|
|
|
|
Implementar:
|
|
|
|
```text
|
|
Projeto
|
|
Sequencia
|
|
Timeline
|
|
Faixa
|
|
Clipe
|
|
IntervaloDeTempo
|
|
```
|
|
|
|
## Fase 6 — Conversores
|
|
|
|
Implementar:
|
|
|
|
```text
|
|
ConversorDeTimeline
|
|
ConversorDeFaixas
|
|
ConversorDeClipes
|
|
```
|
|
|
|
## Fase 7 — Scanner
|
|
|
|
Implementar:
|
|
|
|
```text
|
|
ContextoDeAnalise
|
|
DescobertaDaTimeline
|
|
PipelineDoScanner
|
|
AnalisadorDeTimeline
|
|
```
|
|
|
|
## Fase 8 — Testes
|
|
|
|
Criar fixtures com respostas reais e testes simulados.
|
|
|
|
## Fase 9 — Integração
|
|
|
|
Executar o fluxo completo:
|
|
|
|
```text
|
|
Premiere
|
|
↓
|
|
MCP
|
|
↓
|
|
ClienteMCP
|
|
↓
|
|
AcessoAoEditor
|
|
↓
|
|
Conversores
|
|
↓
|
|
Domínio
|
|
↓
|
|
Scanner
|
|
```
|
|
|
|
---
|
|
|
|
# 40. Resultado esperado
|
|
|
|
Ao final da primeira versão, deverá ser possível executar algo conceitualmente semelhante a:
|
|
|
|
```python
|
|
resultado = analisador_de_timeline.analisar()
|
|
```
|
|
|
|
E obter uma estrutura como:
|
|
|
|
```python
|
|
resultado.timeline
|
|
resultado.timeline.nome
|
|
resultado.timeline.duracao
|
|
resultado.timeline.faixas
|
|
resultado.timeline.clipes
|
|
```
|
|
|
|
Por exemplo:
|
|
|
|
```python
|
|
for faixa in resultado.timeline.faixas:
|
|
print(faixa.nome)
|
|
|
|
for clipe in faixa.clipes:
|
|
print(
|
|
clipe.nome,
|
|
clipe.intervalo_na_timeline.inicio,
|
|
clipe.intervalo_na_timeline.fim,
|
|
)
|
|
```
|
|
|
|
O resultado não será ainda um plano de edição.
|
|
|
|
Será a **representação estruturada e confiável da timeline atual**.
|
|
|
|
Essa representação será a base para todos os próximos módulos:
|
|
|
|
```text
|
|
Leitura da timeline
|
|
↓
|
|
Descoberta de arquivos
|
|
↓
|
|
Metadados
|
|
↓
|
|
Áudio
|
|
↓
|
|
Transcrição
|
|
↓
|
|
Análise visual
|
|
↓
|
|
Detecção de cenas
|
|
↓
|
|
Detecção de retakes
|
|
↓
|
|
Motor de decisão
|
|
↓
|
|
Plano JSON
|
|
↓
|
|
Aplicação no Premiere
|
|
```
|
|
|
|
# 41. Regra final de arquitetura
|
|
|
|
O primeiro módulo deverá respeitar esta regra:
|
|
|
|
> O MCP não é o scanner. O MCP é apenas o mecanismo de comunicação com o editor.
|
|
|
|
A divisão correta é:
|
|
|
|
```text
|
|
ClienteMCP
|
|
comunica
|
|
|
|
AcessoAoEditor
|
|
organiza as consultas
|
|
|
|
Conversores
|
|
transformam respostas
|
|
|
|
Domínio
|
|
representa os dados
|
|
|
|
DescobertaDaTimeline
|
|
executa a descoberta
|
|
|
|
PipelineDoScanner
|
|
coordena as etapas
|
|
|
|
AnalisadorDeTimeline
|
|
inicia o processo
|
|
```
|
|
|
|
Essa separação permitirá que o sistema cresça sem transformar o código em uma única classe gigante e difícil de manter.
|
|
|
|
A próxima etapa prática deve ser **inspecionar as ferramentas reais disponíveis no MCP do Premiere**, porque os nomes das chamadas, os argumentos e o formato das respostas precisam ser confirmados antes de implementar definitivamente o `ClienteMCP` e os conversores.
|