diff --git a/packages/app-lib/src/state/instances/commands/sync_content_files.rs b/packages/app-lib/src/state/instances/commands/sync_content_files.rs index 742135828e..bc92d5042c 100644 --- a/packages/app-lib/src/state/instances/commands/sync_content_files.rs +++ b/packages/app-lib/src/state/instances/commands/sync_content_files.rs @@ -153,6 +153,10 @@ pub(crate) async fn sync_instance_content_files( .iter() .map(|file| (file.relative_path.as_str(), file)) .collect::>(); + let existing_by_id = existing + .iter() + .map(|file| (file.id.as_str(), file)) + .collect::>(); let managed_by_path = existing .iter() .filter(|file| bindings.contains_key(&file.id)) @@ -265,6 +269,9 @@ pub(crate) async fn sync_instance_content_files( if let Some(previous) = previous { file.relative_path.clone_from(&previous.relative_path); file.file_name.clone_from(&previous.file_name); + if is_content_unchanged(&file, previous) { + file.modified_at = previous.modified_at; + } } else if !duplicate_paths.contains(canonical_path) { file.relative_path = canonical_path.to_string(); file.file_name = @@ -302,7 +309,15 @@ pub(crate) async fn sync_instance_content_files( } let mut stored = Vec::new(); for file in files { - if saved_files.contains(&file.id) { + if saved_files.contains(&file.id) + || existing_by_id + .get(file.id.as_str()) + .is_some_and(|previous| { + is_content_unchanged(&file, previous) + && file.modified_at.timestamp() + == previous.modified_at.timestamp() + }) + { stored.push(file); } else { stored.push( @@ -319,6 +334,21 @@ pub(crate) async fn sync_instance_content_files( Ok(stored) } +/// Whether a rescanned file matches what is already stored, ignoring +/// `modified_at` — which records when the file last actually changed, not when +/// it was last looked at. +fn is_content_unchanged( + candidate: &InstanceFile, + previous: &InstanceFile, +) -> bool { + candidate.relative_path == previous.relative_path + && candidate.file_name == previous.file_name + && candidate.enabled == previous.enabled + && candidate.sha1 == previous.sha1 + && candidate.size == previous.size + && candidate.missing == previous.missing +} + pub(super) async fn normalize_legacy_content_files( instance: &Instance, existing: &[InstanceFile],