feat: Alinhado o aplicador Python de plano de edição (aplicador_de
- Alinhado o aplicador Python de plano de edição (aplicador_de_plano_de_edicao.py) com o script apply-editorial-actions.mjs de referência: no-op de split restrito aos padrões reais do bridge, pausa entre chamadas ao MCP, tolerância de borda de corte usa a posição real em vez de rejeitar desvio; adicionado backup automático da sequência (duplicate_sequence) e documentado o comando python code/engine/aplicar_plano_de_edicao.py como via alternativa ao painel CEP. Resumo: - 18 arquivos alterados - 5 novos - 13 modificados - 0 removidos 13 files changed, 704 insertions(+), 133 deletions(-) Arquivos: - .jhonny/analises.db - CLAUDE.md - code/engine/aplicar_plano_de_edicao.py - code/engine/editor/__init__.py - code/engine/editor/aplicador_de_plano_de_edicao.py - code/engine/editor/escrita/escrita_no_editor.py - code/engine/integracoes/premiere/__init__.py - code/engine/integracoes/premiere/cliente_mcp.py - code/engine/testes/duplos_de_premiere.py - code/engine/testes/test_aplicador_de_plano_de_edicao.py - code/scripts/apply-editorial-actions.mjs - code/src/tools/discovery.ts - code/src/tools/timeline.ts - code/engine/editor/backup_de_sequencia.py - code/engine/integracoes/premiere/cliente_mcp_com_pausa.py - code/engine/testes/test_backup_de_sequencia.py - code/engine/testes/test_cliente_mcp_com_pausa.py - code/engine/testes/test_escrita_no_editor.py
This commit is contained in:
@@ -9,10 +9,33 @@ nomes de ferramenta ou ticks do Premiere.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
from ...integracoes.premiere.cliente_mcp import ClienteMCP
|
||||
from ...integracoes.premiere.erros_mcp import ErroDeFerramentaMCP
|
||||
from ..erros import ErroDeEscritaNoEditor
|
||||
|
||||
# O bridge recusa a divisão de duas formas diferentes quando o ponto pedido
|
||||
# JÁ é uma borda de clipe. Ambas são no-op, não falha:
|
||||
# 1. nenhum clipe atravessa estritamente o instante ("strictly spans");
|
||||
# 2. o razor roda mas a contagem de clipes da faixa não muda, porque o ponto
|
||||
# coincide por arredondamento de quadro com uma borda existente.
|
||||
# Os mesmos dois padrões são reconhecidos por scripts/apply-editorial-actions.mjs,
|
||||
# que aplica planos por este mesmo bridge.
|
||||
_RECUSA_POR_NENHUM_CLIPE_ATRAVESSANDO = re.compile(r"strictly spans", re.IGNORECASE)
|
||||
_RECUSA_COM_CONTAGEM_DE_CLIPES = re.compile(
|
||||
r"changed the track clip count from (\d+) to (\d+)", re.IGNORECASE
|
||||
)
|
||||
|
||||
|
||||
def _e_divisao_ja_existente(mensagem_de_erro: str) -> bool:
|
||||
"""``True`` se a recusa do bridge significa "esse ponto já era uma borda"."""
|
||||
if _RECUSA_POR_NENHUM_CLIPE_ATRAVESSANDO.search(mensagem_de_erro):
|
||||
return True
|
||||
contagem = _RECUSA_COM_CONTAGEM_DE_CLIPES.search(mensagem_de_erro)
|
||||
return contagem is not None and contagem.group(1) == contagem.group(2)
|
||||
|
||||
|
||||
_CORES_POR_NOME = {
|
||||
"revisar": 3, # laranja: chama atenção sem parecer um erro (vermelho)
|
||||
"informar": 5, # branco: marcador neutro
|
||||
@@ -29,10 +52,17 @@ class EscritaNoEditor:
|
||||
"""Corta, na timeline, o clipe que cobrir ``instante_da_timeline``.
|
||||
|
||||
Devolve ``True`` se um corte novo foi criado e ``False`` quando o
|
||||
instante já era uma borda de clipe (o Premiere recusa dividir onde
|
||||
não há clipe atravessando o ponto) — esse segundo caso não é um erro,
|
||||
instante já era uma borda de clipe — esse segundo caso não é um erro,
|
||||
é o resultado esperado quando o corte pedido coincide com um corte já
|
||||
existente da análise de cenas.
|
||||
existente da análise de cenas, ou quando um plano parcialmente
|
||||
aplicado é reexecutado.
|
||||
|
||||
Só as recusas reconhecidas por :func:`_e_divisao_ja_existente` contam
|
||||
como no-op. Qualquer outra recusa vira
|
||||
:class:`ErroDeEscritaNoEditor`: antes, um ``except`` largo tratava
|
||||
toda :class:`ErroDeFerramentaMCP` como "já era borda", então uma
|
||||
faixa bloqueada ou uma queda de bridge passava por corte
|
||||
bem-sucedido e o trecho seguia inteiro na timeline, sem aviso.
|
||||
"""
|
||||
try:
|
||||
self.cliente_mcp.chamar(
|
||||
@@ -40,17 +70,29 @@ class EscritaNoEditor:
|
||||
{"time_seconds": instante_da_timeline, "track_index": indice_da_faixa, "track_type": tipo_da_faixa},
|
||||
)
|
||||
return True
|
||||
except ErroDeFerramentaMCP:
|
||||
return False
|
||||
except ErroDeFerramentaMCP as erro:
|
||||
if _e_divisao_ja_existente(str(erro)):
|
||||
return False
|
||||
raise ErroDeEscritaNoEditor(
|
||||
f"Não foi possível dividir a faixa {tipo_da_faixa}_{indice_da_faixa} "
|
||||
f"em {instante_da_timeline:.3f}s: {erro}"
|
||||
) from erro
|
||||
|
||||
def remover_trecho(self, identificador_do_clipe: str) -> None:
|
||||
"""Remove o clipe da timeline, fechando o espaço deixado (ripple).
|
||||
"""Remove o clipe da timeline fechando o espaço que ele ocupava.
|
||||
|
||||
Usa ``ripple_delete`` (QE ``rippleDelete``), não
|
||||
``remove_from_timeline``: numa sequência real com outras faixas
|
||||
ocupadas, o ``remove_from_timeline`` com ``ripple`` apagou o clipe
|
||||
mas deixou o buraco aberto, e um buraco no meio do corte é um corte
|
||||
errado. O ``ripple_delete`` confere, do lado do Premiere, que o
|
||||
clipe realmente sumiu.
|
||||
|
||||
Levanta :class:`ErroDeEscritaNoEditor` se o Premiere recusar a
|
||||
remoção.
|
||||
"""
|
||||
try:
|
||||
self.cliente_mcp.chamar("remove_from_timeline", {"node_id": identificador_do_clipe, "ripple": True})
|
||||
self.cliente_mcp.chamar("ripple_delete", {"node_id": identificador_do_clipe})
|
||||
except ErroDeFerramentaMCP as erro:
|
||||
raise ErroDeEscritaNoEditor(f"Não foi possível remover o clipe {identificador_do_clipe!r}: {erro}") from erro
|
||||
|
||||
|
||||
Reference in New Issue
Block a user