Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 40 additions & 45 deletions faststack/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -1040,13 +1040,9 @@ def _apply_filter_to_cached_list(self):
# Apply flag-based filtering (AND logic: image must have ALL checked flags)
if self._filter_enabled and self._filter_flags:
flags = self._filter_flags
# Optimize: access sidecar entries directly to avoid get_metadata overhead
entries = self.sidecar.data.entries
result = []
for img in filtered:
# Direct dict lookup is faster than get_metadata() which might create objects
stem = img.path.stem
meta = entries.get(stem)
meta = self.sidecar.get_metadata(img.path, create=False)
if not meta:
continue

Expand Down Expand Up @@ -1810,7 +1806,7 @@ def jump_to_last_uploaded(self):
for idx in range(len(self.image_files) - 1, -1, -1):
img = self.image_files[idx]
# Dynamic look-up of self.sidecar as requested (important for mocks in tests)
meta = self.sidecar.get_metadata(img.path.stem, create=False)
meta = self.sidecar.get_metadata(img.path, create=False)

uploaded = meta.uploaded if meta else False

Expand Down Expand Up @@ -2126,10 +2122,10 @@ def _on_thumbnail_ready_gui(self, thumbnail_id: str):
if self._thumbnail_model:
self._thumbnail_model.thumbnailReady.emit(thumbnail_id)

def _get_metadata_dict(self, stem: str) -> dict:
"""Get metadata for a file stem as a dict for thumbnail model."""
def _get_metadata_dict(self, image_path: Path | str) -> dict:
"""Get metadata for an image path as a dict for thumbnail model."""
try:
meta = self.sidecar.get_metadata(stem, create=False)
meta = self.sidecar.get_metadata(image_path, create=False)
if meta is None:
return {
"stacked": False,
Expand All @@ -2148,7 +2144,7 @@ def _get_metadata_dict(self, stem: str) -> dict:
"todo": meta.todo,
}
except Exception as e: # Broad catch for UI plumbing - don't crash grid view
log.debug("Failed to get metadata for %s: %s", stem, e)
log.debug("Failed to get metadata for %s: %s", image_path, e)
return {
"stacked": False,
"uploaded": False,
Expand All @@ -2162,9 +2158,11 @@ def _get_bulk_metadata_map(self) -> Dict[str, dict]:
"""Get flattened metadata map for all images (for efficient grid refresh)."""
bulk_map = {}
try:
# sidecar.data.entries is a dict of stem -> EntryMetadata
for stem, meta in self.sidecar.data.entries.items():
bulk_map[stem] = {
for img in self.image_files:
meta = self.sidecar.get_metadata(img.path, create=False)
if meta is None:
continue
bulk_map[normalize_path_key(img.path)] = {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"stacked": getattr(meta, "stacked", False),
"uploaded": getattr(meta, "uploaded", False),
"edited": getattr(meta, "edited", False),
Expand Down Expand Up @@ -2214,8 +2212,8 @@ def toggle_uploaded(self):
return

today = datetime.now().strftime("%Y-%m-%d")
stem = self.image_files[self.current_index].path.stem
meta = self.sidecar.get_metadata(stem)
image_path = self.image_files[self.current_index].path
meta = self.sidecar.get_metadata(image_path)

meta.uploaded = not meta.uploaded
if meta.uploaded:
Expand All @@ -2229,16 +2227,16 @@ def toggle_uploaded(self):
self.sync_ui_state()
status = "uploaded" if meta.uploaded else "not uploaded"
self.update_status_message(f"Marked as {status}")
log.info("Toggled uploaded flag to %s for %s", meta.uploaded, stem)
log.info("Toggled uploaded flag to %s for %s", meta.uploaded, image_path)

def toggle_todo(self):
"""Toggle todo flag for current image."""
if not self.image_files or self.current_index >= len(self.image_files):
return

today = datetime.now().strftime("%Y-%m-%d")
stem = self.image_files[self.current_index].path.stem
meta = self.sidecar.get_metadata(stem)
image_path = self.image_files[self.current_index].path
meta = self.sidecar.get_metadata(image_path)

meta.todo = not getattr(meta, "todo", False)
if meta.todo:
Expand All @@ -2252,16 +2250,16 @@ def toggle_todo(self):
self.sync_ui_state()
status = "todo" if meta.todo else "not todo"
self.update_status_message(f"Marked as {status}")
log.info("Toggled todo flag to %s for %s", meta.todo, stem)
log.info("Toggled todo flag to %s for %s", meta.todo, image_path)

def toggle_edited(self):
"""Toggle edited flag for current image."""
if not self.image_files or self.current_index >= len(self.image_files):
return

today = datetime.now().strftime("%Y-%m-%d")
stem = self.image_files[self.current_index].path.stem
meta = self.sidecar.get_metadata(stem)
image_path = self.image_files[self.current_index].path
meta = self.sidecar.get_metadata(image_path)

meta.edited = not meta.edited
if meta.edited:
Expand All @@ -2275,16 +2273,16 @@ def toggle_edited(self):
self.sync_ui_state()
status = "edited" if meta.edited else "not edited"
self.update_status_message(f"Marked as {status}")
log.info("Toggled edited flag to %s for %s", meta.edited, stem)
log.info("Toggled edited flag to %s for %s", meta.edited, image_path)

def toggle_restacked(self):
"""Toggle restacked flag for current image."""
if not self.image_files or self.current_index >= len(self.image_files):
return

today = datetime.now().strftime("%Y-%m-%d")
stem = self.image_files[self.current_index].path.stem
meta = self.sidecar.get_metadata(stem)
image_path = self.image_files[self.current_index].path
meta = self.sidecar.get_metadata(image_path)

meta.restacked = not meta.restacked
if meta.restacked:
Expand All @@ -2298,15 +2296,15 @@ def toggle_restacked(self):
self.sync_ui_state()
status = "restacked" if meta.restacked else "not restacked"
self.update_status_message(f"Marked as {status}")
log.info("Toggled restacked flag to %s for %s", meta.restacked, stem)
log.info("Toggled restacked flag to %s for %s", meta.restacked, image_path)

def toggle_favorite(self):
"""Toggle favorite flag for current image."""
if not self.image_files or self.current_index >= len(self.image_files):
return

stem = self.image_files[self.current_index].path.stem
meta = self.sidecar.get_metadata(stem)
image_path = self.image_files[self.current_index].path
meta = self.sidecar.get_metadata(image_path)

meta.favorite = not meta.favorite

Expand All @@ -2316,16 +2314,16 @@ def toggle_favorite(self):
self.sync_ui_state()
status = "Favorited" if meta.favorite else "Unfavorited"
self.update_status_message(status)
log.info("Toggled favorite flag to %s for %s", meta.favorite, stem)
log.info("Toggled favorite flag to %s for %s", meta.favorite, image_path)

def toggle_stacked(self):
"""Toggle stacked flag for current image."""
if not self.image_files or self.current_index >= len(self.image_files):
return

today = datetime.now().strftime("%Y-%m-%d")
stem = self.image_files[self.current_index].path.stem
meta = self.sidecar.get_metadata(stem)
image_path = self.image_files[self.current_index].path
meta = self.sidecar.get_metadata(image_path)

meta.stacked = not meta.stacked
if meta.stacked:
Expand All @@ -2339,7 +2337,7 @@ def toggle_stacked(self):
self.sync_ui_state()
status = "stacked" if meta.stacked else "not stacked"
self.update_status_message(f"Marked as {status}")
log.info("Toggled stacked flag to %s for %s", meta.stacked, stem)
log.info("Toggled stacked flag to %s for %s", meta.stacked, image_path)

def get_current_metadata(self) -> Dict:
if not self.image_files or self.current_index >= len(self.image_files):
Expand All @@ -2357,8 +2355,8 @@ def get_current_metadata(self) -> Dict:
return self._metadata_cache

# Compute and cache
stem = self.image_files[self.current_index].path.stem
meta = self.sidecar.get_metadata(stem, create=False)
image_path = self.image_files[self.current_index].path
meta = self.sidecar.get_metadata(image_path, create=False)
stack_info = self._get_stack_info(self.current_index)
batch_info = self._get_batch_info(self.current_index)

Expand Down Expand Up @@ -2619,7 +2617,7 @@ def add_favorites_to_batch(self):
# Find indices of all favorited images
indices_to_add = []
for i, img in enumerate(self.image_files):
meta = self.sidecar.get_metadata(img.path.stem, create=False)
meta = self.sidecar.get_metadata(img.path, create=False)
if meta and meta.favorite:
indices_to_add.append(i)

Expand Down Expand Up @@ -2674,7 +2672,7 @@ def add_uploaded_to_batch(self):
# Find indices of all uploaded images
indices_to_add = []
for i, img in enumerate(self.image_files):
meta = self.sidecar.get_metadata(img.path.stem, create=False)
meta = self.sidecar.get_metadata(img.path, create=False)
if meta and meta.uploaded:
indices_to_add.append(i)

Expand Down Expand Up @@ -3099,8 +3097,7 @@ def _launch_helicon_with_files(self, files: List[Path]) -> bool:
for img_file in self.image_files:
# Match by either RAW pair or JPG path
if img_file.raw_pair == file_path or img_file.path == file_path:
stem = img_file.path.stem
meta = self.sidecar.get_metadata(stem)
meta = self.sidecar.get_metadata(img_file.path)
meta.stacked = True
meta.stacked_date = today
break
Expand Down Expand Up @@ -5448,8 +5445,7 @@ def edit_in_photoshop(self):

# Mark as edited on successful launch
today = datetime.now().strftime("%Y-%m-%d")
stem = image_file.path.stem
meta = self.sidecar.get_metadata(stem)
meta = self.sidecar.get_metadata(image_file.path)
meta.edited = True
meta.edited_date = today
self.sidecar.save()
Expand Down Expand Up @@ -5583,8 +5579,7 @@ def start_drag_current_image(self):
today = datetime.now().strftime("%Y-%m-%d")

for idx in existing_indices:
stem = self.image_files[idx].path.stem
meta = self.sidecar.get_metadata(stem)
meta = self.sidecar.get_metadata(self.image_files[idx].path)
meta.uploaded = True
meta.uploaded_date = today

Expand Down Expand Up @@ -6456,8 +6451,7 @@ def stack_source_raws(self):
if success:
# Mark as restacked on success
today = datetime.now().strftime("%Y-%m-%d")
stem = self.image_files[self.current_index].path.stem
meta = self.sidecar.get_metadata(stem)
meta = self.sidecar.get_metadata(self.image_files[self.current_index].path)
meta.restacked = True
meta.restacked_date = today
self.sidecar.save()
Expand Down Expand Up @@ -7363,8 +7357,9 @@ def get_stack_summary(self) -> str:
def is_stacked(self) -> bool:
if not self.image_files or self.current_index >= len(self.image_files):
return False
stem = self.image_files[self.current_index].path.stem
meta = self.sidecar.get_metadata(stem, create=False)
meta = self.sidecar.get_metadata(
self.image_files[self.current_index].path, create=False
)
return meta.stacked if meta else False

def _update_cache_stats(self):
Expand Down
Loading