Files
jhonny-editor/code/engine/arquitetura/leitura-da-timeline-via-mcp.md
T
João Henrique b541f502ba feat: initial commit - Jhonny Editor
- Adicionado estrutura completa do projeto
- Configurado MCP server para Premiere Pro
- Adicionado documentação e skills
- Configurado Gitignore para o projeto
2026-09-08 09:59:31 -04:00

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.