Derived clips: link MP4 versions, list them apart, video Enhance output #209

Merged
cameron merged 1 commits from feat/animate-video-versions into master 2026-11-02 00:39:38 +00:00
Owner

Part of #208 (Animate a photo, built to support video Enhance next). Pairs with comfyui-imageapi-versions #5 / #6 (Save Video Version node).

What changes

  • Linking: version links are read from MP4 / MOV as well as PNG.
    • The XMP packet is in a top-level uuid box with the XMP UUID.
    • It's read by hand, like the PNG chunks: the walker reads only the box headers and seeks over mdat.
    • Covers ingest and the Enhance approve ingest.
  • Derived clips (kind animated, CLIP_KINDS): a video made from a photo. Linked, hidden and lifecycled exactly like a version, but:
    • not counted in photo_version_counts / version_count (one change in photo_summaries covers /photos, memories, search and /photos/exif);
    • never a display choice: PUT /image/versions/display answers 400 clip_not_displayable, and the display join ignores clips;
    • listed apart: GET /image/versions gains clips: [...], the same shape as versions. That's additive, and older apps simply don't see clips.
  • Enhance:
    • /enhance/templates gains output: "image" | "video", inferred from the template's imageapi:save class (ImageApiSaveVideoVersion = video), so there's no new enhance.toml key.
    • Approve returns the clip's entry.
    • The preview relay already passes ComfyUI's content type through (video/mp4).
  • Docs: CLAUDE.md, under Photo versions, Enhance, and the endpoint shapes.

Testing

  • cargo test --lib (DATABASE_URL=:memory:): 1063 pass.
  • New tests:
    • The MP4 XMP reader: a clip, .mov, a non-XMP extension, no XMP, junk bytes, and 64-bit box sizes.
    • The template output kind.
    • End to end: an .animated.mp4 linked by XMP is hidden from /photos, isn't counted, is listed under clips (from the photo's path and the clip's own), and is refused as the display version.
  • fmt and clippy are clean.
  • Node side: the Python node's box layout was checked against exiftool on a real ffmpeg clip (node pack #5).

🤖 Generated with Claude Code

Part of #208 (Animate a photo, built to support video Enhance next). Pairs with comfyui-imageapi-versions #5 / #6 (Save Video Version node). ## What changes - **Linking:** version links are read from MP4 / MOV as well as PNG. - The XMP packet is in a top-level `uuid` box with the XMP UUID. - It's read by hand, like the PNG chunks: the walker reads only the box headers and seeks over `mdat`. - Covers ingest and the Enhance approve ingest. - **Derived clips (kind `animated`, `CLIP_KINDS`):** a video made from a photo. Linked, hidden and lifecycled exactly like a version, but: - not counted in `photo_version_counts` / `version_count` (one change in `photo_summaries` covers `/photos`, memories, search and `/photos/exif`); - never a display choice: `PUT /image/versions/display` answers 400 `clip_not_displayable`, and the display join ignores clips; - listed apart: `GET /image/versions` gains `clips: [...]`, the same shape as `versions`. That's additive, and older apps simply don't see clips. - **Enhance:** - `/enhance/templates` gains `output: "image" | "video"`, inferred from the template's `imageapi:save` class (`ImageApiSaveVideoVersion` = video), so there's no new `enhance.toml` key. - Approve returns the clip's entry. - The preview relay already passes ComfyUI's content type through (`video/mp4`). - **Docs:** CLAUDE.md, under Photo versions, Enhance, and the endpoint shapes. ## Testing - **`cargo test --lib`** (`DATABASE_URL=:memory:`): 1063 pass. - **New tests:** - The MP4 XMP reader: a clip, `.mov`, a non-XMP extension, no XMP, junk bytes, and 64-bit box sizes. - The template output kind. - End to end: an `.animated.mp4` linked by XMP is hidden from `/photos`, isn't counted, is listed under `clips` (from the photo's path and the clip's own), and is refused as the display version. - **fmt and clippy** are clean. - **Node side:** the Python node's box layout was checked against exiftool on a real ffmpeg clip (node pack #5). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
cameron added 1 commit 2026-11-02 00:39:01 +00:00
Groundwork for Enhance "Animate" (#208): a video made from a photo.

- Version linking reads the XMP link from MP4 / MOV too (top-level uuid box
  with the XMP UUID, mdat seeked over), at ingest and on Enhance approve.
- New kind `animated`, a derived clip (CLIP_KINDS): hidden behind the photo
  like a version, but not counted in photo_version_counts / version_count,
  never a display choice (400 clip_not_displayable), and listed as `clips`
  in GET /image/versions. Approve returns the clip entry.
- Templates whose imageapi:save is ImageApiSaveVideoVersion report
  output "video" in /enhance/templates (no enhance.toml change). Previews
  already relay ComfyUI's content type (video/mp4).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cameron merged commit 19cbc9d59c into master 2026-11-02 00:39:38 +00:00
cameron deleted branch feat/animate-video-versions 2026-11-02 00:39:38 +00:00
Sign in to join this conversation.