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,130 @@
|
||||
"""
|
||||
FCPXML Writer — Generate and modify Final Cut Pro XML files.
|
||||
|
||||
This package provides two complementary workflows for working with FCPXML:
|
||||
|
||||
**Generation** (``FCPXMLWriter``, in :mod:`.generator`):
|
||||
Build a new FCPXML document from Python dataclass objects (``Project``,
|
||||
``Timeline``, ``Clip``, ``Marker``). Useful for creating rough cuts,
|
||||
montage exports, and template-based projects.
|
||||
|
||||
**Modification** (``FCPXMLModifier``, in :mod:`.modifier`):
|
||||
Load an existing FCPXML file, apply surgical edits (markers, trims,
|
||||
reorders, transitions, speed changes, silence removal, etc.), and save.
|
||||
This is the primary API used by the MCP server's tool handlers.
|
||||
|
||||
Layout
|
||||
------
|
||||
This was one 4.200-line module. It is now one module per subject, because the
|
||||
subjects barely touch each other: whoever is fixing a zoom ramp has no reason
|
||||
to scroll past subtitle layout to find it.
|
||||
|
||||
helpers sanitising, scales, shared element builders
|
||||
document asset creation, timebases, serialisation (``write_fcpxml``)
|
||||
validation structural checks (``validate_fcpxml``)
|
||||
core ``ModifierCore``: load, indices, spine navigation, ``save``
|
||||
<subject> one mixin per editing subject (markers, trim, speed, …)
|
||||
modifier ``FCPXMLModifier`` = core + every mixin
|
||||
generator ``FCPXMLWriter``
|
||||
api one-line convenience wrappers
|
||||
|
||||
Everything the rest of the project imported from the old module is re-exported
|
||||
here, so ``from fcpxml.writer import FCPXMLModifier`` keeps working unchanged —
|
||||
including the underscore-prefixed helpers the test suite reaches for.
|
||||
|
||||
Architecture notes
|
||||
------------------
|
||||
- All time arithmetic uses ``TimeValue`` (rational fractions) — never floats —
|
||||
to match FCPXML's native ``"600/2400s"`` format and avoid rounding drift.
|
||||
- The ``FCPXMLModifier`` builds three in-memory indices at init
|
||||
(``clips``, ``resources``, ``formats``) so lookups are O(1) by ID/name.
|
||||
- Spine-based editing: clips live inside a ``<spine>`` element (the primary
|
||||
storyline). Connected clips attach via ``lane`` attributes on spine clips.
|
||||
Most editing methods find the target clip in the spine, mutate it, then
|
||||
ripple offsets on subsequent siblings.
|
||||
- ``write_fcpxml()`` handles DTD-compliant serialisation and optional
|
||||
timebase enforcement for all output paths.
|
||||
"""
|
||||
|
||||
from ..models import TimeValue
|
||||
from .api import add_marker_to_file, modify_fcpxml, trim_clip_in_file
|
||||
from .core import ModifierCore
|
||||
from .document import (
|
||||
_STILL_IMAGE_EXTENSIONS,
|
||||
_enforce_standard_timebases,
|
||||
_ensure_video_asset,
|
||||
write_fcpxml,
|
||||
)
|
||||
from .generator import FCPXMLWriter
|
||||
from .helpers import (
|
||||
_ASSET_CLIP_CHILD_ORDER,
|
||||
_CHILD_ORDER_INDEX,
|
||||
_MAX_MARKER_NAME_LENGTH,
|
||||
_MAX_NOTE_LENGTH,
|
||||
CLIP_AND_AUDIO_TAGS,
|
||||
CLIP_TAGS,
|
||||
FCP_EFFECTS,
|
||||
HOLD_AT_CUT_THRESHOLD,
|
||||
SPINE_ELEMENT_TAGS,
|
||||
START_AT_CUT_THRESHOLD,
|
||||
_create_asset_element,
|
||||
_dtd_insert,
|
||||
_fmt_scale,
|
||||
_probe_audio_info,
|
||||
_sanitize_xml_value,
|
||||
build_marker_element,
|
||||
list_effects,
|
||||
)
|
||||
from .modifier import FCPXMLModifier
|
||||
from .validation import (
|
||||
_check_asset_sources,
|
||||
_check_child_order,
|
||||
_check_effect_refs,
|
||||
_check_frame_alignment,
|
||||
_check_required_attributes,
|
||||
_check_timebases,
|
||||
_document_frame_duration,
|
||||
validate_fcpxml,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"FCPXMLModifier",
|
||||
"FCPXMLWriter",
|
||||
"ModifierCore",
|
||||
"TimeValue",
|
||||
"FCP_EFFECTS",
|
||||
"CLIP_TAGS",
|
||||
"CLIP_AND_AUDIO_TAGS",
|
||||
"SPINE_ELEMENT_TAGS",
|
||||
"HOLD_AT_CUT_THRESHOLD",
|
||||
"START_AT_CUT_THRESHOLD",
|
||||
"add_marker_to_file",
|
||||
"build_marker_element",
|
||||
"list_effects",
|
||||
"modify_fcpxml",
|
||||
"trim_clip_in_file",
|
||||
"validate_fcpxml",
|
||||
"write_fcpxml",
|
||||
# Internos que o resto do projeto (e a suíte) já importava deste módulo
|
||||
# quando ele era um arquivo só. Ficam aqui para a divisão não virar uma
|
||||
# quebra de API disfarçada de reorganização.
|
||||
"_ASSET_CLIP_CHILD_ORDER",
|
||||
"_CHILD_ORDER_INDEX",
|
||||
"_MAX_MARKER_NAME_LENGTH",
|
||||
"_MAX_NOTE_LENGTH",
|
||||
"_STILL_IMAGE_EXTENSIONS",
|
||||
"_check_asset_sources",
|
||||
"_check_child_order",
|
||||
"_check_effect_refs",
|
||||
"_check_frame_alignment",
|
||||
"_check_required_attributes",
|
||||
"_check_timebases",
|
||||
"_create_asset_element",
|
||||
"_document_frame_duration",
|
||||
"_dtd_insert",
|
||||
"_enforce_standard_timebases",
|
||||
"_ensure_video_asset",
|
||||
"_fmt_scale",
|
||||
"_probe_audio_info",
|
||||
"_sanitize_xml_value",
|
||||
]
|
||||
Reference in New Issue
Block a user