From 3ef1a0bbd3d31026bd01e8822a3a870a8c9597c3 Mon Sep 17 00:00:00 2001 From: pax Date: Thu, 9 Apr 2026 17:33:39 -0500 Subject: [PATCH] bookmarks: fix saved-dot indicator for templated/folder library saves MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dot on bookmark thumbnails uses set_saved_locally(...) and was driven by find_library_files(post_id) — a digit-stem filesystem walk that silently failed for any save with a templated filename (e.g. 12345_hatsune_miku.jpg). The user reported it broken right after templating landed. Switch to db.get_saved_post_ids() for the grid refresh: one indexed SELECT, set membership in O(1) per thumb. Format-agnostic, sees both digit-stem and templated saves. The "Unsave from Library" context menu used the same broken find_library_files check for visibility. Switched to db.is_post_in_library(post_id), which is the same idea via a single-row SELECT 1. Both delete_from_library call sites (single + bulk Unsave All) now pass db so templated filenames are matched and the meta row gets cleaned up. Refresh always runs after Unsave so the dot clears whether the file was on disk or just an orphan meta row. --- booru_viewer/gui/bookmarks.py | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/booru_viewer/gui/bookmarks.py b/booru_viewer/gui/bookmarks.py index 3a98fbd..6a90cde 100644 --- a/booru_viewer/gui/bookmarks.py +++ b/booru_viewer/gui/bookmarks.py @@ -195,12 +195,16 @@ class BookmarksView(QWidget): self._count_label.setText(f"{len(self._bookmarks)} bookmarks") thumbs = self._grid.set_posts(len(self._bookmarks)) - from ..core.config import find_library_files + # Batch the "is this saved?" check via library_meta. One indexed + # query gives us a set of every saved post_id, then per-thumb + # membership is O(1). Format-agnostic — works for digit-stem + # legacy files AND templated post-refactor saves, where the + # old find_library_files(post_id)+digit-stem check silently + # failed because the on-disk basename no longer matches the id. + saved_ids = self._db.get_saved_post_ids() for i, (fav, thumb) in enumerate(zip(self._bookmarks, thumbs)): thumb.set_bookmarked(True) - # Library state is filesystem-truth and folder-agnostic now — - # walk the library by post id, ignore the bookmark's folder. - thumb.set_saved_locally(bool(find_library_files(fav.post_id))) + thumb.set_saved_locally(fav.post_id in saved_ids) # Set cached path for drag-and-drop and copy if fav.cached_path and Path(fav.cached_path).exists(): thumb._cached_path = fav.cached_path @@ -323,7 +327,7 @@ class BookmarksView(QWidget): # Save to Library submenu — folders come from the library # filesystem, not the bookmark folder DB. - from ..core.config import library_folders, find_library_files + from ..core.config import library_folders save_lib_menu = menu.addMenu("Save to Library") save_lib_unsorted = save_lib_menu.addAction("Unfiled") save_lib_menu.addSeparator() @@ -335,8 +339,10 @@ class BookmarksView(QWidget): save_lib_new = save_lib_menu.addAction("+ New Folder...") unsave_lib = None - # Only show unsave if the post is actually on disk somewhere. - if find_library_files(fav.post_id): + # Only show unsave if the post is actually saved. is_post_in_library + # is the format-agnostic DB check — works for digit-stem and + # templated filenames alike. + if self._db.is_post_in_library(fav.post_id): unsave_lib = menu.addAction("Unsave from Library") copy_file = menu.addAction("Copy File to Clipboard") copy_url = menu.addAction("Copy Image URL") @@ -407,12 +413,13 @@ class BookmarksView(QWidget): log.warning(f"Bookmark Save As #{fav.post_id} failed: {e}") elif action == unsave_lib: from ..core.cache import delete_from_library - # delete_from_library walks every library folder by post id - # now — no folder hint needed (and fav.folder wouldn't be - # accurate anyway after the bookmark/library separation). - if delete_from_library(fav.post_id): - self.refresh() - self.bookmarks_changed.emit() + # Pass db so templated filenames are matched and the meta + # row gets cleaned up. Refresh on success OR on a meta-only + # cleanup (orphan row, no on-disk file) — either way the + # saved-dot indicator state has changed. + delete_from_library(fav.post_id, db=self._db) + self.refresh() + self.bookmarks_changed.emit() elif action == copy_file: path = fav.cached_path if path and Path(path).exists(): @@ -520,7 +527,7 @@ class BookmarksView(QWidget): elif action == unsave_all: from ..core.cache import delete_from_library for fav in favs: - delete_from_library(fav.post_id) + delete_from_library(fav.post_id, db=self._db) self.refresh() self.bookmarks_changed.emit() elif action == move_none: