* fix(ltx): scrub base64 posters from persisted Director timelines
The vendored upstream 2.0.2 timeline editor stamps a base64 poster JPEG
onto every video segment (canvas.toDataURL) and kept it across serialize
round-trips, so timeline_data - and with it the workflow draft ComfyUI
1.44+ writes to localStorage ~512ms after every edit - grew by ~50-150k
chars per video segment. Large timelines then exceeded the origin quota
no matter how many old drafts koolook_draft_guard.js evicted, and the
frontend latched its session-wide storage-unavailable flag: every edit
toasted "Failed to save workflow draft" until reload.
Reinstate a minimal media scrub as a third documented Koolook delta,
applied at all six persist/restore maps (commitChanges + parseInitial):
- video / motion_video posters with a backing file (imageFile on the
main track, videoFile on the motion track) are dropped; the seeked
handler re-derives them from the video element on load
- legacy pre-2.0.2 image segments carrying full inline data-URLs are
rewritten to the /view URL form 2.0.2 itself writes (loadMedia renders
image previews from imageB64 only - deleting would blank them)
- legacy inline audioB64 (raw base64) is dropped when audioFile exists;
playback only falls back to it when no file resolves
- blobs with no backing file are left untouched
Disk Save / Save As payloads stay unscrubbed on purpose: exported .json
keeps upstream's format and meets the restore scrub on load. On-screen
previews are unaffected - only persisted copies are scrubbed.
Covered by Node behavior tests that evaluate the delta block against a
stubbed api, plus a source contract that all six maps route through the
scrub.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(ltx): persist the scrubbed timeline on restore; review follow-ups
Addresses the verified findings on #277.
The restore-time scrub only updated the editor's in-memory timeline. The
node's timeline_data widget kept the original payload, and that is what
onSerialize and LiteGraph's widgets_values read - so an already-fat saved
workflow still fed the draft autosave that fires on load, before any edit
triggers commitChanges. Both restore paths (the onConfigure sync block and
the editor constructor) now rewrite the widget from the scrubbed timeline.
The round-trip is lossless: parseInitial whitelists exactly the keys
commitChanges persists. Chose this over calling commitChanges during
configure, which would also recompute the prompt/length/strength widgets on
every node's configure - far wider blast radius than the defect warrants.
Also:
- keep the data-URL when a malformed imageFile yields no /view URL, instead
of blanking the preview with an empty string
- rewrite the stale provenance-header paragraph that still claimed the
base64-scrub deltas were obsolete (it now contradicted the third delta)
- update the v2.0.2 entry in forks/forks_manifest.yaml from "two retargeting
edits" to the three current Koolook edits, with the scrub's rationale
- note the audioB64 leg and the widget rewrite in the CHANGELOG entry
The bare catch in parseInitial is left alone: pre-existing upstream
behavior, and the scrub introduces no realistic new throw.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(ltx): trigger the widget rewrite on legacy raw-base64 audio too
The restore-time widget rewrite gated on the payload containing "data:",
which catches the poster/image blobs that caused the quota storms but not
the scrub's third removal: legacy audioB64, which is raw base64 with no
"data:" prefix. An audio-only fat timeline would have its memory scrubbed
while the widget stayed fat until the next commitChanges.
Gate on either token instead, so the trigger covers everything the scrub
actually removes. A false positive still costs only a lossless rewrite.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>