"""Abrir um projeto e preparar modifier/generator para editá-lo. Extraído de _shared.py — ver server_tools/_shared/__init__.py. """ from __future__ import annotations from mcp.types import TextContent from fcpxml.parser import FCPXMLParser from fcpxml.rough_cut import RoughCutGenerator from fcpxml.writer import FCPXMLModifier from .paths import _resolve_io_paths, _validate_filepath def _parse_project(filepath: str): """Parse an FCPXML file and return the project with its primary timeline.""" filepath = _validate_filepath(filepath, ('.fcpxml', '.fcpxmld')) project = FCPXMLParser().parse_file(filepath) if not project.timelines: return None, None return project, project.primary_timeline def _text_result(text: str) -> list[TextContent]: """Wrap a string in the MCP TextContent list that every tool handler returns.""" return [TextContent(type="text", text=text)] def _no_timeline(): """Standard response when no timelines are found.""" return _text_result("No timelines found") def _require_timeline(filepath: str): """Parse FCPXML and return (project, timeline), raising if no timeline exists. Centralises the repeated _parse_project + _no_timeline guard that appears in every read-only timeline handler. Returns a tuple so callers can destructure directly:: project, tl = _require_timeline(arguments["filepath"]) """ project, tl = _parse_project(filepath) if not tl: raise _NoTimelineError() return project, tl class _NoTimelineError(Exception): """Sentinel raised by _require_timeline when no timelines exist.""" def _setup_modifier( arguments: dict, suffix: str = "_modified", ) -> tuple[str, str, "FCPXMLModifier"]: """Common setup for write handlers: validate paths and create modifier. Consolidates the repeated validate-filepath → resolve-output-path → create-modifier boilerplate shared by 18+ write handlers. Args: arguments: Tool arguments dict (must contain ``filepath``; may contain ``output_path``). suffix: Default output filename suffix when ``output_path`` is not provided (e.g. ``"_modified"``, ``"_flash_fixed"``). Returns: ``(filepath, output_path, modifier)`` tuple ready for the handler's domain-specific operation. """ filepath, output_path = _resolve_io_paths(arguments, suffix) modifier = FCPXMLModifier(filepath) return filepath, output_path, modifier def _setup_generator( arguments: dict, suffix: str = "_roughcut", ) -> tuple[str, str, "RoughCutGenerator"]: """Common setup for generation handlers: validate paths and create generator. Args: arguments: Tool arguments dict (must contain ``filepath`` and ``output_path``). suffix: Default output filename suffix. Returns: ``(filepath, output_path, generator)`` tuple. """ filepath, output_path = _resolve_io_paths(arguments, suffix) generator = RoughCutGenerator(filepath) return filepath, output_path, generator