Files
olivv-cs-ComfyUI-FunPack/movie_editor/backend/projects.py
T
digital-garbageandClaude Opus 4.8 d133fde995 Movie Editor V1: standalone web-app scaffold for timeline montage
Editable scene timeline + transition library feeding the existing Studio ->
Chain Sampler chain. Light FastAPI sidecar (no torch/comfy) that drives a
running ComfyUI over its API and reuses /funpack/* routes for parsing.

- backend: project store (JSON), timeline model + Studio-format prompt
  assembly, ComfyUI client, graph-agnostic workflow injector, routes
  (projects/timeline preview/generate/library), FastAPI app
- frontend: vanilla-JS editable timeline (scene cards, transitions, exclude,
  generate-only, source type), live split preview, result player
- forward-compat data model: scene source (empty/image/generated_frame),
  per-scene excluded flag, intro_transition for the anchor boundary
- tests: 8 passing (prompt assembly, project CRUD, workflow injection)

V1 drives the uniform chain in one pass; per-scene length/FPS, Empty/Image
latent building, media browser, frame->scene anchors, selective regen and
cuts/trims are scaffolded (UI/model) but deferred to later phases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 13:33:16 +03:00

63 lines
1.6 KiB
Python

"""On-disk JSON project store. One file per project, keyed by id.
Deliberately simple and synchronous — projects are small. This is the persistence
seam that Phase 2+ extends with cached per-scene latents/assets.
"""
from __future__ import annotations
import json
import time
from typing import Optional
from . import config
from .timeline import Project
def _path(project_id: str):
return config.PROJECTS_DIR / f"{project_id}.json"
def list_projects() -> list[dict]:
config.ensure_dirs()
out: list[dict] = []
for p in sorted(config.PROJECTS_DIR.glob("*.json")):
try:
d = json.loads(p.read_text())
except (json.JSONDecodeError, OSError):
continue
out.append({
"id": d.get("id", p.stem),
"name": d.get("name", p.stem),
"scene_count": len(d.get("scenes", [])),
"updated_at": d.get("updated_at", 0),
})
out.sort(key=lambda x: x.get("updated_at", 0), reverse=True)
return out
def get(project_id: str) -> Optional[Project]:
p = _path(project_id)
if not p.exists():
return None
return Project.from_dict(json.loads(p.read_text()))
def save(project: Project) -> Project:
config.ensure_dirs()
project.updated_at = time.time()
_path(project.id).write_text(json.dumps(project.to_dict(), indent=2))
return project
def create(name: str = "Untitled") -> Project:
project = Project(name=name)
return save(project)
def delete(project_id: str) -> bool:
p = _path(project_id)
if p.exists():
p.unlink()
return True
return False