"""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 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 # ========================================================================