refactor: writer.py vira pacote, um módulo por assunto
O writer tinha 4.199 linhas, das quais 3.300 numa única classe com dezoito
assuntos dentro. Achar o trecho de zoom exigia rolar por marcadores,
velocidade e legendas.
Agora é o pacote fcpxml/writer/, com um arquivo por assunto e o
FCPXMLModifier montado por composição de mixins. Mixins, e não objetos
separados, porque todas essas operações mexem no mesmo documento e nos
mesmos índices — separá-las em objetos independentes transformaria toda
chamada interna em travessia de fronteira sem nada em troca. A divisão que
importa aqui é de leitura, não de estado.
Nenhuma mudança de comportamento e nenhuma alteração nos ~50 pontos que
importam do writer: o __init__ re-exporta tudo, inclusive os nomes com
underscore que a suíte já usava.
core 723 carga, índices, navegação na spine, save
titles 600 títulos e legendas dinâmicas
cut 333 dividir, cortar faixas, apagar
speed 297 velocidade e zoom
(+ 20 módulos menores)
Único ajuste de chamada: quatro testes faziam patch em
fcpxml.writer.subprocess, que agora mora em writer.document (ver
Engine/docs/05_EXPERIENCIAS.md #23).
Lint zerado, 1441 testes passando.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1bebee4359
commit
4f5cf94443
@@ -0,0 +1,94 @@
|
||||
"""Transições entre clipes vizinhos.
|
||||
|
||||
Extraído de writer.py — ver fcpxml/writer/__init__.py para o conjunto.
|
||||
"""
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from ..models import (
|
||||
TimeValue,
|
||||
)
|
||||
from .helpers import FCP_EFFECTS
|
||||
|
||||
|
||||
class TransitionsMixin:
|
||||
"""Transições entre clipes vizinhos."""
|
||||
|
||||
# TRANSITION OPERATIONS
|
||||
# ========================================================================
|
||||
|
||||
def add_transition(
|
||||
self,
|
||||
clip_id: str,
|
||||
position: str = 'end',
|
||||
transition_type: str = 'cross-dissolve',
|
||||
duration: str = '00:00:00:15'
|
||||
) -> ET.Element:
|
||||
"""
|
||||
Add a transition to a clip.
|
||||
|
||||
Args:
|
||||
clip_id: Target clip
|
||||
position: 'start', 'end', or 'both'
|
||||
transition_type: Type of transition
|
||||
duration: Transition duration
|
||||
|
||||
Returns:
|
||||
Created transition element(s)
|
||||
"""
|
||||
spine, clip, clip_index = self._require_spine_clip(clip_id)
|
||||
|
||||
trans_duration = self._parse_time(duration)
|
||||
|
||||
# Effect name and FCP built-in effect UID lookup via registry
|
||||
effect_name, effect_uid = FCP_EFFECTS.get(
|
||||
transition_type,
|
||||
FCP_EFFECTS['cross-dissolve']
|
||||
)
|
||||
|
||||
# Ensure effect resource exists in <resources>
|
||||
effect_ref_id = None
|
||||
if effect_uid:
|
||||
root = self.tree.getroot()
|
||||
resources = root.find('.//resources')
|
||||
if resources is not None:
|
||||
for eff in resources.findall('effect'):
|
||||
if eff.get('uid') == effect_uid:
|
||||
effect_ref_id = eff.get('id')
|
||||
break
|
||||
if effect_ref_id is None:
|
||||
effect_ref_id = self._unique_resource_id(resources, 'r_dissolve')
|
||||
eff_el = ET.SubElement(resources, 'effect')
|
||||
eff_el.set('id', effect_ref_id)
|
||||
eff_el.set('name', effect_name)
|
||||
eff_el.set('uid', effect_uid)
|
||||
|
||||
transitions_added = []
|
||||
|
||||
_, clip_dur, clip_offset = self._get_clip_times(clip)
|
||||
half_dur = trans_duration * 0.5
|
||||
|
||||
if position in ('end', 'both'):
|
||||
end_offset = clip_offset + clip_dur - half_dur
|
||||
transition = self._make_transition_element(
|
||||
effect_name, end_offset, trans_duration, effect_ref_id
|
||||
)
|
||||
spine.insert(clip_index + 1, transition)
|
||||
transitions_added.append(transition)
|
||||
|
||||
if position in ('start', 'both'):
|
||||
start_offset = clip_offset - half_dur
|
||||
if start_offset < TimeValue.zero():
|
||||
raise ValueError(
|
||||
f"Transition at start would produce negative offset "
|
||||
f"({start_offset.to_seconds():.3f}s) for clip '{clip_id}'"
|
||||
)
|
||||
transition = self._make_transition_element(
|
||||
effect_name, start_offset, trans_duration, effect_ref_id
|
||||
)
|
||||
spine.insert(clip_index, transition)
|
||||
transitions_added.append(transition)
|
||||
|
||||
return transitions_added[0] if len(transitions_added) == 1 else transitions_added
|
||||
|
||||
# ========================================================================
|
||||
Reference in New Issue
Block a user