d5a8d38c9c
A code-first, declarative video editing system that compiles text documents into rendered video via FFmpeg. Uses a compiler-style ETL pipeline: Extract (parse inputs) → Validate → Transform (build timeline) → Render (FFmpeg). Features: - Text-based project definition (manuscript, transcript, JSON configs) - Slide markers [S1], [S2] in transcript map to timed overlays - Strict validation with fail-fast error reporting - FFmpeg filter_complex generation with time-based enables - CLI with validate/render/dry-run modes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
60 lines
1.8 KiB
Python
60 lines
1.8 KiB
Python
"""Structured error types for GnommoEditor pipeline."""
|
|
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
|
|
class GnommoError(Exception):
|
|
"""Base exception for all GnommoEditor errors."""
|
|
pass
|
|
|
|
|
|
@dataclass
|
|
class ValidationIssue:
|
|
"""A single validation issue with location context."""
|
|
message: str
|
|
file: Optional[Path] = None
|
|
line: Optional[int] = None
|
|
|
|
def __str__(self) -> str:
|
|
parts = []
|
|
if self.file:
|
|
parts.append(str(self.file))
|
|
if self.line is not None:
|
|
parts.append(f"line {self.line}")
|
|
location = ":".join(parts) if parts else "project"
|
|
return f"[{location}] {self.message}"
|
|
|
|
|
|
class ParseError(GnommoError):
|
|
"""Error during parsing of input files."""
|
|
|
|
def __init__(self, message: str, file: Optional[Path] = None, line: Optional[int] = None):
|
|
self.issue = ValidationIssue(message, file, line)
|
|
super().__init__(str(self.issue))
|
|
|
|
|
|
class ValidationError(GnommoError):
|
|
"""Error during validation stage. Can contain multiple issues."""
|
|
|
|
def __init__(self, issues: list[ValidationIssue]):
|
|
self.issues = issues
|
|
message = f"Validation failed with {len(issues)} error(s):\n"
|
|
message += "\n".join(f" - {issue}" for issue in issues)
|
|
super().__init__(message)
|
|
|
|
|
|
class RenderError(GnommoError):
|
|
"""Error during rendering stage."""
|
|
|
|
def __init__(self, message: str, command: Optional[str] = None, stderr: Optional[str] = None):
|
|
self.command = command
|
|
self.stderr = stderr
|
|
full_message = message
|
|
if command:
|
|
full_message += f"\nCommand: {command}"
|
|
if stderr:
|
|
full_message += f"\nFFmpeg output:\n{stderr}"
|
|
super().__init__(full_message)
|