Fixed thumbnail reload on metadata change

This commit is contained in:
Ignacio Serantes
2026-04-06 22:09:13 +02:00
parent a717acef87
commit 45c95c1bb1
4 changed files with 108 additions and 36 deletions

View File

@@ -1037,6 +1037,7 @@ class MainWindow(QMainWindow):
self._group_info_cache = {}
self._visible_paths_cache = None # Cache for visible image paths
self._path_to_model_index = {}
self._paths_being_modified_by_app = set() # For ignoring FS events
# Keep references to open viewers to manage their lifecycle
self.viewers = []
@@ -1349,6 +1350,10 @@ class MainWindow(QMainWindow):
self.fs_watcher.monitoring_status_changed.connect(
self.on_fs_watcher_status_changed)
# Set up callback for metadata managers
from metadatamanager import set_app_modified_callback
set_app_modified_callback(self._mark_path_as_app_modified)
# Batching for file creation events
self._fs_created_queue = set()
self._fs_created_timer = QTimer(self)
@@ -4863,22 +4868,52 @@ class MainWindow(QMainWindow):
if path not in self._known_paths:
return # Not a file we're tracking
# Invalidate cache and trigger a refresh of its metadata and thumbnail
self.cache.invalidate_path(path)
# If this modification was initiated by the app, ignore it
if path in self._paths_being_modified_by_app:
return
# Re-read metadata and thumbnail
res = load_common_metadata(path)
mtime = os.path.getmtime(path)
stat_res = os.stat(path)
inode = stat_res.st_ino
dev = stat_res.st_dev
# External modification: check if it's metadata-only or content change
try:
new_stat = os.stat(path)
new_mtime = new_stat.st_mtime
new_size = new_stat.st_size
# Update internal data and model
self._update_internal_data(path, mtime=mtime, tags=res.tags, rating=res.rating,
inode=inode, dev=dev)
self.proxy_model.add_to_cache(path, res.tags)
self.rebuild_view()
self.status_lbl.setText(f"File modified: {os.path.basename(path)}")
# Find old data from internal list
old_item_data = next((item for item in self.found_items_data if item[0] == path), None)
old_mtime = old_item_data[2] if old_item_data else 0
old_size = os.path.getsize(path) if old_item_data else 0 # Re-read size from disk for comparison
if new_size == old_size and new_mtime != old_mtime:
# Likely metadata-only change (size unchanged, mtime changed)
res = load_common_metadata(path)
self._update_internal_data(path, mtime=new_mtime, tags=res.tags, rating=res.rating,
inode=new_stat.st_ino, dev=new_stat.st_dev)
self.proxy_model.add_to_cache(path, res.tags)
self.thumbnail_view.viewport().update() # Force repaint
self.status_lbl.setText(f"Metadata updated: {os.path.basename(path)}")
else:
# Content or size changed, invalidate thumbnail and rebuild view
self.cache.invalidate_path(path)
res = load_common_metadata(path) # Re-read metadata as well
self._update_internal_data(path, mtime=new_mtime, tags=res.tags, rating=res.rating,
inode=new_stat.st_ino, dev=new_stat.st_dev)
self.proxy_model.add_to_cache(path, res.tags)
self.rebuild_view()
self.status_lbl.setText(f"File modified: {os.path.basename(path)}")
except Exception:
# Fallback to full refresh if error occurs
self.refresh_content()
def _mark_path_as_app_modified(self, path):
"""Marks a path as being modified by the application to ignore FS events."""
abs_path = os.path.abspath(path)
parent_path = os.path.dirname(abs_path)
self._paths_being_modified_by_app.add(abs_path)
self._paths_being_modified_by_app.add(parent_path)
# Schedule removal after a delay to allow all FS events to propagate
QTimer.singleShot(1000, lambda: self._paths_being_modified_by_app.discard(abs_path))
QTimer.singleShot(1000, lambda: self._paths_being_modified_by_app.discard(parent_path))
def on_fs_watcher_status_changed(self, is_monitoring):
"""Updates the UI indicator for the FileSystemWatcher."""
@@ -4893,6 +4928,9 @@ class MainWindow(QMainWindow):
"""Handles a directory being modified (e.g., new subfolder, mass changes)."""
path = os.path.abspath(path)
if path in self._paths_being_modified_by_app:
return
# Trigger a debounced full refresh. This is useful for syncing large
# external changes (bulk operations, directory deletions) that are
# more robustly handled by a full scan than incremental updates.