feat(legendas): sub-frases por vírgula e empacotamento em compound clip
split_into_subphrases divide a frase na vírgula — onde a fala respira —
mas funde de volta o pedaço curto ("né?", "Então..."), que lê como parte
da frase anterior e não como bloco próprio.
wrap_titles_in_compound empacota os títulos de uma sub-frase num compound
clip, replicando a estrutura que o próprio Final Cut produz: o primeiro
título vira âncora do spine em offset 0, os demais penduram nele por lane,
e um ref-clip toma o lugar deles na lane original. Os offsets dos filhos
são rebaseados para o espaço de tempo da âncora, senão cada palavra
escorregaria pela diferença entre os dois start.
Junto: _filter_children_for_segment passa a filtrar também o <video> do
Clipe de Ajuste. Sem isso, cada corte subsequente duplicava o zoom em
todos os pedaços resultantes com o offset original intacto, e as cópias
desenhavam empilhadas na mesma posição da timeline.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
635d1bb553
commit
688bdeddb6
@@ -41,6 +41,15 @@ class CutMixin:
|
||||
cut (silence removal, filler removal) duplicates it into every
|
||||
resulting piece, so the same word shows up several times across the
|
||||
edited timeline instead of once where it was placed.
|
||||
|
||||
A lane-nested ``<video>`` zoom (the "Clipe de Ajuste" adjustment
|
||||
layer ``add_zoom`` creates, ``role`` starting with ``"adjustments."``)
|
||||
is the exact same phantom-duplicate case, keyed on ``offset``+
|
||||
``duration`` like a keyword. Left unfiltered, every further cut
|
||||
duplicates the zoom into every resulting piece with its original
|
||||
offset untouched — each copy then draws at the same absolute
|
||||
position, so two "Clipe de Ajuste" bars appear stacked on top of
|
||||
each other in the timeline instead of the one real zoom window.
|
||||
"""
|
||||
seg_end = seg_start + seg_duration
|
||||
to_remove = []
|
||||
@@ -54,6 +63,12 @@ class CutMixin:
|
||||
title_offset = TimeValue.from_timecode(child.get('offset', '0s'))
|
||||
if title_offset < seg_start or title_offset >= seg_end:
|
||||
to_remove.append(child)
|
||||
elif tag == 'video' and (child.get('role') or '').startswith('adjustments.'):
|
||||
v_offset = TimeValue.from_timecode(child.get('offset', '0s'))
|
||||
v_dur = TimeValue.from_timecode(child.get('duration', '0s'))
|
||||
v_end = v_offset + v_dur
|
||||
if v_end <= seg_start or v_offset >= seg_end:
|
||||
to_remove.append(child)
|
||||
elif tag == 'keyword':
|
||||
kw_start = TimeValue.from_timecode(child.get('start', '0s'))
|
||||
kw_dur = TimeValue.from_timecode(child.get('duration', '0s'))
|
||||
|
||||
Reference in New Issue
Block a user