mirror of
https://github.com/affaan-m/ECC.git
synced 2026-09-18 15:50:25 +02:00
* feat: bundle standalone taste distillation and application workflows * docs: fix imported taste skill markdown lint * docs: align Turkish agent catalog with taste skills * refactor: make ECC the canonical reusable video engine * fix: preserve video duration when applying image overlays * fix: preserve background colors in image compositing * fix: report best-effort duration targets and shortfalls * feat: ship verified Fusion presets with compatibility provenance * feat(tasteforge): preserve native edits in application bundles * feat(tasteforge): compile local preservation without hosted input * fix: update js-yaml to patched 4.3.2 * test: report bounded Stop wrapper failure diagnostics * fix(tasteforge): fail closed on unsafe output names, missing overlays and cadence - cli: default report and spec paths are derived from pack name and profile genre; require the manifest's name pattern before using either as a filename part so a traversal string cannot write outside cwd/out. - apply_local: a pack without cadence.json, or with no measured shots and no explicit mean_shot, raises instead of silently planning 1.0s shots and reporting a measured cadence. - legacy apply: a missing overlay aborts before any paid upload; forge() would have rejected it after every take was generated. - requirements-live: pin fal-client>=0.13.0, the first release whose subscribe() accepts client_timeout. Addresses the five P1 findings from the independent review of #3033. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015fxHRsydPqEcYngGbqkgt1 --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
39 lines
1.3 KiB
Python
39 lines
1.3 KiB
Python
"""Validation and transactional output for local media tools."""
|
|
|
|
import math
|
|
import os
|
|
import tempfile
|
|
from contextlib import contextmanager
|
|
from pathlib import Path
|
|
|
|
|
|
def geometry(width, height, fps, duration=1):
|
|
for value in (width, height, fps, duration):
|
|
if isinstance(value, bool) or not math.isfinite(value) or value <= 0:
|
|
raise ValueError("Geometry, fps and duration must be finite and positive")
|
|
if width != int(width) or height != int(height) or width % 2 or height % 2:
|
|
raise ValueError("Width and height must be even integers")
|
|
|
|
|
|
@contextmanager
|
|
def output_file(destination, overwrite=False):
|
|
destination = Path(destination)
|
|
if os.path.lexists(destination) and not overwrite:
|
|
raise FileExistsError(destination)
|
|
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
fd, filename = tempfile.mkstemp(
|
|
prefix=".media-", suffix=destination.suffix, dir=destination.parent
|
|
)
|
|
os.close(fd)
|
|
temporary = Path(filename)
|
|
try:
|
|
yield temporary
|
|
if temporary.stat().st_size == 0:
|
|
raise RuntimeError("Media command produced an empty output")
|
|
if overwrite:
|
|
os.replace(temporary, destination)
|
|
else:
|
|
os.link(temporary, destination)
|
|
finally:
|
|
temporary.unlink(missing_ok=True)
|