Image Ledger · Import Video History
Retro-fit the tracking onto videos you already made
- report
Here's the annoying bit about installing a no-repeat queue after you've already rendered four hundred clips: as far as the ledger knows, every source image is still pending, so it queues them all again. Image Ledger · Import Video History reads the ComfyUI metadata already embedded in your finished MP4s, works out which source each one came from, and marks those sources done.
What it's for
This is the pack's migration node, and it leans on something the ecosystem does that most software doesn't: ComfyUI writes the prompt graph into what it produces, so a finished video is a receipt for the image that made it. Video files carry that in container metadata rather than PNG text chunks, but the principle is the one the KB's image/metadata doc states - the metadata is the payload, not a footnote to it.
Run this once, as a dry run, before you trust a batch queue against an existing library.
How it works
Two phases, in this order.
First it indexes the campaign: it scans the source folder you give it (with or without subfolders, filtered by the extensions list - .png,.jpg,.jpeg,.webp,.bmp,.tif,.tiff,.avif by default), hashes what it finds, and registers it as pending. That's the same sync a loader does, so the ledger now knows what "everything" is.
Then it walks the output folder for videos matching your glob, and for each one runs FFmpeg to dump the container's ffmetadata and reads the comment field. If there's no comment field, or it isn't a JSON object, that file counts as unresolved. If there is one, it parses the prompt graph and looks for the source node - specifically a node titled First-Frame-Image, falling back to node id 23 if that node is a LoadImage. It takes the filename from that node's image input, pulls the SHA-256 the workflow recorded in is_changed, verifies it against the file on disk, and marks the matching ledger item done.
The report string is the whole point of the node. It reads something like:
Scanned 412; metadata 401; hash verified 384; newly done 350; duplicate videos 22; unresolved 11; errors 2; cached 128; mode dry run
unresolved is the number to look at. Those are videos whose source it couldn't pin down - usually because the metadata was already gone, or the source moved.
Inputs and outputs
- campaign - the ledger to write into. Default
image-ledger-default, matching the loaders. - source_subfolder - the image library under
ComfyUI/input, e.g.AI. Empty means the input root. - source_recursive - whether the source scan descends into category folders. Off by default; turn it on if your library is
AI/portraits/,AI/illustrations/. - output_subfolder - where the videos live under
output/. Defaultvideo, which is where nativeSaveVideoand the usual VHS prefixes put them. - filename_glob -
*.mp4by default. It takes a comma- or semicolon-separated list, matched case-insensitively, so*.mp4,*.webmis the way to catch other containers you've written. - dry_run - on by default, and you should leave it on the first time. Dry run scans and reports without writing a single completion.
- extensions - what counts as a source image when indexing.
- report (output) - the string above, also pushed to the node's text panel.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/Rona1do/ComfyUI-Image-Ledger.git
No new Python packages - the pack's requirements.txt is literally a comment saying none are required. But this node needs FFmpeg, which it borrows from VideoHelperSuite or imageio-ffmpeg, or falls back to whatever's on your PATH. Since you're importing video history, you almost certainly already have VHS installed.
Common issues
"FFmpeg was not found." Install VideoHelperSuite (it bundles/pulls imageio-ffmpeg), or point the pack at a binary explicitly:
export COMFYUI_IMAGE_LEDGER_FFMPEG=/usr/bin/ffmpeg # or wherever yours lives
Resist the urge to pip install imageio-ffmpeg into a portable ComfyUI build as a first move - that's the classic way to drag a dependency update into your torch/torchvision stack and break unrelated things.
unresolved is high. Usually the metadata was stripped. Re-encoding, remuxing, or round-tripping the file through a converter that rewrites the container drops the comment field; so does saving from an instance started with --disable-metadata. There's no recovery from pixels alone - the graph was text, and the text is gone. Cut those clips loose or re-render them.
unresolved is high and your videos are fine. Your source node probably isn't titled First-Frame-Image and isn't node 23. The importer is looking for exactly that title. This is the same title heuristic the global panel uses to decide which LoadImage is the source one, so it's worth setting properly in general.
Selection stops dead with a "some legacy videos could not be resolved" error. The Tracked Image Loader auto-imports legacy metadata once per session (sync_legacy_history, on by default) and refuses to pick anything if any video is unresolved, precisely so it never repeats an image it can't account for. Run this node with dry_run off to clear the backlog, or turn that toggle off on the loader.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| campaign | STRING | image-ledger-default | — |
| source_subfolder | STRING | — | |
| source_recursive | BOOLEAN | false | — |
| output_subfolder | STRING | video | — |
| filename_glob | STRING | *.mp4 | — |
| dry_run | BOOLEAN | true | — |
| extensions | STRING | .png,.jpg,.jpeg,.webp,.bmp,.tif,.tiff,.avif | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| report | STRING | — |