From 98cdc981ad674fe34a417a20c8893844701ad638 Mon Sep 17 00:00:00 2001 From: Katt <238968166+KattKnight@users.noreply.github.com> Date: Sat, 10 Oct 2026 18:21:21 +0530 Subject: [PATCH] Footage: a file that can't be read is tried again once it changes, not on every look A footage file the automatic reload couldn't read (still being written, or one the importer doesn't read) kept its old stamp, so every two-second look saw it as changed and probed it again. It now keeps its new stamp and is tried again once it changes again (when the other app finishes writing it). Co-Authored-By: Claude Opus 5.5 --- crates/engine/src/footage_reload.rs | 9 ++++----- docs/preferences.md | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/crates/engine/src/footage_reload.rs b/crates/engine/src/footage_reload.rs index 0d26a45c..3a7f0719 100644 --- a/crates/engine/src/footage_reload.rs +++ b/crates/engine/src/footage_reload.rs @@ -184,8 +184,8 @@ fn forget(s: &mut Session, paths: &BTreeSet) { /// time is only remembered; one whose stamp moved is reloaded: the items reading it get their /// size and duration from it again and its pixels are read again. A file that can't be stamped /// right now (an app saving by delete and rename) keeps its last stamp, and one that can't be -/// read yet (still being written) keeps its old stamp so the next scan tries again; missing -/// files are left to the footage check. Returns `{files, reloaded}`. +/// read (still being written) is tried again once it changes again; missing files are left to +/// the footage check. Returns `{files, reloaded}`. pub fn apply_stamps(s: &mut Session, now: Vec<(String, Option)>) -> crate::Result { let before = std::mem::take(&mut s.footage_stamps); let mut changed = BTreeSet::new(); @@ -209,10 +209,9 @@ pub fn apply_stamps(s: &mut Session, now: Vec<(String, Option)>) -> crate } let ids: Vec = s.project.items.values().filter(|i| matches!(&i.kind, ItemKind::Footage(f) if changed.contains(&f.path))).map(|i| i.id).collect(); let (reloaded, failed) = if ids.is_empty() { (0, BTreeSet::new()) } else { reload(s, &ids, false)? }; + // Not readable (still being written, or not a file the importer reads): its new stamp is kept, + // so it is tried again once it changes again, not on every look. for p in &failed { - if let Some(old) = before.get(p) { - s.footage_stamps.insert(p.clone(), *old); - } changed.remove(p); } if changed.is_empty() { diff --git a/docs/preferences.md b/docs/preferences.md index 75c606b7..f6909cef 100644 --- a/docs/preferences.md +++ b/docs/preferences.md @@ -114,7 +114,7 @@ Commands (CLI, MCP, control channel): size and modification time with what they were, and reloads what another app saved: a Photoshop file edited in PhotoCraft or Photoshop shows its new pixels without File ▸ Reload Footage. It is not an undo step and doesn't modify the project; a layer item stays on its layer - (found again by name), and a file still being written is tried again on the next check. + (found again by name), and a file that can't be read yet (still being written) is tried again once it changes again. `footage.reloadChanged` runs the same check once (CLI, agents) - `import.unlabeledAlpha`: alpha of TGA / TIFF / movie footage (Ask opens Interpret Footage; Guess takes premultiplied for movies, straight for stills)