chore(fase0): higiene do repositório + corrige gitignore que escondia fcpxml/models/
Fase 0 do roteiro de reestruturação (Engine/docs/10_MAPA_REESTRUTURACAO.md): move code/WHISPERX (2,6 GB de backups órfãos, sem uso ativo, sem .gitmodules) para ~/Archives/G-ART-WHISPERX-backup fora do workspace git; traz admin/ para o gate de lint de run_after_fix.sh; corrige fcpxml/writer/adjustment.py, que gerava um wrapper <adjustment> inexistente no DTD 1.13 (filtros agora vão direto no <clip>, na ordem exigida), com teste de regressão novo. Achado à parte: .gitignore tinha uma regra solta "models/" (pensada só para o cache do Whisper em code/models/) que também escondia do git todo o pacote fcpxml/models/ — nunca commitado, sem proteção nenhuma. Corrigida para /code/models/, ancorada na raiz. Docs atualizados no mesmo commit (02_MODULES, 09_MANUTENCAO, 10_MAPA_REESTRUTURACAO, 05_EXPERIENCIAS #34 e #36), conforme a regra do CLAUDE.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
0fdfe33613
commit
d13f643ebc
@@ -0,0 +1,183 @@
|
||||
"""Enumerações do domínio: tipos e cores de marcador, transições, ritmo.
|
||||
|
||||
Extraído de models.py — ver fcpxml/models/__init__.py.
|
||||
"""
|
||||
|
||||
from enum import Enum
|
||||
|
||||
# Maximum length for marker type strings to prevent memory abuse
|
||||
_MAX_MARKER_TYPE_LENGTH = 64
|
||||
|
||||
class MarkerType(Enum):
|
||||
"""Types of markers in Final Cut Pro.
|
||||
|
||||
Members:
|
||||
STANDARD — Default marker with no completion state.
|
||||
INCOMPLETE — Task marker (completed="0" in FCPXML). ← canonical name
|
||||
TODO — Alias for INCOMPLETE. Kept for backward compatibility;
|
||||
resolves to the same object (``MarkerType.TODO is
|
||||
MarkerType.INCOMPLETE``). Python enums treat the first
|
||||
member with a given value as canonical; all subsequent
|
||||
members sharing that value become aliases.
|
||||
CHAPTER — Chapter marker (``<chapter-marker>`` element).
|
||||
COMPLETED — Task marker with completed="1".
|
||||
|
||||
Serialization helpers:
|
||||
``from_string()`` — Accepts values, names, and legacy aliases
|
||||
(e.g. ``"todo-marker"``). Always returns the
|
||||
canonical member.
|
||||
``from_xml_element()`` — Reads an ``lxml``/``ElementTree`` element and
|
||||
returns the appropriate type based on the tag
|
||||
name and ``completed`` attribute.
|
||||
``xml_tag`` — The FCPXML element tag to emit when writing.
|
||||
``xml_attrs`` — Extra attributes required when writing (e.g.
|
||||
``completed="0"`` for INCOMPLETE).
|
||||
"""
|
||||
STANDARD = "standard"
|
||||
INCOMPLETE = "todo"
|
||||
TODO = "todo" # Backward-compat alias — resolves to INCOMPLETE at runtime
|
||||
CHAPTER = "chapter"
|
||||
COMPLETED = "completed"
|
||||
|
||||
@classmethod
|
||||
def from_string(cls, value: str) -> 'MarkerType':
|
||||
"""Convert a string to MarkerType, accepting both enum names and values.
|
||||
|
||||
Includes input validation: rejects null bytes, control characters,
|
||||
and excessively long strings to prevent injection and memory abuse.
|
||||
|
||||
Examples:
|
||||
MarkerType.from_string("todo") -> MarkerType.INCOMPLETE
|
||||
MarkerType.from_string("TODO") -> MarkerType.INCOMPLETE
|
||||
MarkerType.from_string("completed") -> MarkerType.COMPLETED
|
||||
"""
|
||||
if not isinstance(value, str):
|
||||
raise TypeError(f"Expected str, got {type(value).__name__}")
|
||||
if '\x00' in value or any(ord(c) < 32 and c not in ('\n', '\r', '\t') for c in value):
|
||||
raise ValueError("Marker type contains invalid control characters")
|
||||
if len(value) > _MAX_MARKER_TYPE_LENGTH:
|
||||
raise ValueError(
|
||||
f"Marker type exceeds maximum length ({_MAX_MARKER_TYPE_LENGTH} chars)"
|
||||
)
|
||||
lowered = value.strip().lower()
|
||||
if not lowered:
|
||||
raise ValueError("Marker type cannot be empty")
|
||||
# Accept legacy aliases from older specs (e.g. "todo-marker" → INCOMPLETE)
|
||||
aliases = {
|
||||
"todo-marker": "todo",
|
||||
"completed-marker": "completed",
|
||||
"chapter-marker": "chapter",
|
||||
}
|
||||
lowered = aliases.get(lowered, lowered)
|
||||
try:
|
||||
return cls(lowered)
|
||||
except ValueError:
|
||||
raise ValueError(
|
||||
f"Invalid marker type: '{value}'. "
|
||||
f"Valid types: {', '.join(m.value for m in cls)}"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_xml_element(cls, elem) -> 'MarkerType':
|
||||
"""Determine MarkerType from an XML element's tag and attributes.
|
||||
|
||||
Centralises the parse-side mapping so the parser doesn't need to
|
||||
know about completed-attribute semantics.
|
||||
|
||||
Rules (in priority order):
|
||||
1. <chapter-marker> tag → CHAPTER (completed attr ignored)
|
||||
2. completed='0' (exact) → INCOMPLETE
|
||||
3. completed='1' (exact) → COMPLETED
|
||||
4. Everything else → STANDARD (including whitespace-padded,
|
||||
absent, empty, or non-boolean completed values)
|
||||
|
||||
Matching is intentionally strict — no .strip(), no case folding.
|
||||
This prevents whitespace-injected attributes like ' 0 ' from
|
||||
being misclassified.
|
||||
"""
|
||||
if elem.tag == 'chapter-marker':
|
||||
return cls.CHAPTER
|
||||
completed = elem.get('completed')
|
||||
if completed == '0':
|
||||
return cls.INCOMPLETE
|
||||
if completed == '1':
|
||||
return cls.COMPLETED
|
||||
return cls.STANDARD
|
||||
|
||||
@property
|
||||
def xml_tag(self) -> str:
|
||||
"""Return the FCPXML element tag for this marker type."""
|
||||
return 'chapter-marker' if self == MarkerType.CHAPTER else 'marker'
|
||||
|
||||
@property
|
||||
def xml_attrs(self) -> dict:
|
||||
"""Return extra XML attributes this marker type requires when writing.
|
||||
|
||||
Centralises the write-side mapping so both FCPXMLModifier and
|
||||
FCPXMLWriter use a single source of truth.
|
||||
"""
|
||||
if self == MarkerType.CHAPTER:
|
||||
return {'posterOffset': '0s'}
|
||||
if self == MarkerType.INCOMPLETE:
|
||||
return {'completed': '0'}
|
||||
if self == MarkerType.COMPLETED:
|
||||
return {'completed': '1'}
|
||||
return {}
|
||||
|
||||
# Recognised marker XML tags — used by the parser for single-pass collection
|
||||
# and by the writer to validate element creation.
|
||||
MARKER_XML_TAGS = ('marker', 'chapter-marker')
|
||||
|
||||
class MarkerColor(Enum):
|
||||
"""Marker color options (FCP internal values)."""
|
||||
BLUE = 0
|
||||
CYAN = 1
|
||||
GREEN = 2
|
||||
YELLOW = 3
|
||||
ORANGE = 4
|
||||
RED = 5
|
||||
PINK = 6
|
||||
PURPLE = 7
|
||||
|
||||
class TransitionType(Enum):
|
||||
"""Built-in transition types."""
|
||||
CROSS_DISSOLVE = "Cross Dissolve"
|
||||
FADE_TO_BLACK = "Fade to Color"
|
||||
FADE_FROM_BLACK = "Fade from Color"
|
||||
DIP_TO_COLOR = "Dip to Color"
|
||||
WIPE = "Wipe"
|
||||
SLIDE = "Slide"
|
||||
|
||||
class PacingStyle(Enum):
|
||||
"""Pacing presets for rough cut generation."""
|
||||
SLOW = "slow" # 5-10 second cuts
|
||||
MEDIUM = "medium" # 2-5 second cuts
|
||||
FAST = "fast" # 0.5-2 second cuts
|
||||
DYNAMIC = "dynamic" # Varies throughout
|
||||
|
||||
class FlashFrameSeverity(Enum):
|
||||
"""Severity levels for flash frame detection."""
|
||||
CRITICAL = "critical" # < 2 frames, almost certainly an error
|
||||
WARNING = "warning" # < 6 frames, potentially intentional but suspicious
|
||||
|
||||
class PacingCurve(Enum):
|
||||
"""Pacing curves for montage generation."""
|
||||
CONSTANT = "constant" # Same clip duration throughout
|
||||
ACCELERATING = "accelerating" # Starts slow, gets faster
|
||||
DECELERATING = "decelerating" # Starts fast, gets slower
|
||||
PYRAMID = "pyramid" # Slow → fast → slow
|
||||
|
||||
class ValidationIssueType(Enum):
|
||||
"""Types of timeline validation issues."""
|
||||
FLASH_FRAME = "flash_frame"
|
||||
GAP = "gap"
|
||||
DUPLICATE = "duplicate"
|
||||
ORPHAN_REF = "orphan_ref"
|
||||
INVALID_OFFSET = "invalid_offset"
|
||||
# DTD validation types (v0.6.0)
|
||||
ELEMENT_ORDER = "element_order"
|
||||
MISSING_ATTRIBUTE = "missing_attribute"
|
||||
INVALID_TIMEBASE = "invalid_timebase"
|
||||
FRAME_MISALIGNMENT = "frame_misalignment"
|
||||
MISSING_EFFECT_REF = "missing_effect_ref"
|
||||
MISSING_MEDIA_REP = "missing_media_rep"
|
||||
Reference in New Issue
Block a user