From 6f59de0c64b12b59f40875d94833563ca8f2a562 Mon Sep 17 00:00:00 2001 From: pax Date: Thu, 9 Apr 2026 17:29:42 -0500 Subject: [PATCH] config: find_library_files now matches templated filenames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When given an optional db handle, find_library_files queries library_meta for templated filenames belonging to the post and matches them alongside the legacy digit-stem stem == str(post_id) heuristic. Without db it degrades to the legacy-only behavior, so existing callers don't break — but every caller in the gui layer has a Database instance and will be updated to pass it. This is the foundation for the bookmark/browse saved-dot indicator fix and the delete_from_library fix in the next three commits. --- booru_viewer/core/config.py | 49 ++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/booru_viewer/core/config.py b/booru_viewer/core/config.py index 430e4e4..7f6e840 100644 --- a/booru_viewer/core/config.py +++ b/booru_viewer/core/config.py @@ -128,28 +128,59 @@ def library_folders() -> list[str]: return sorted(d.name for d in root.iterdir() if d.is_dir()) -def find_library_files(post_id: int) -> list[Path]: +def find_library_files(post_id: int, db=None) -> list[Path]: """Return all library files matching `post_id` across every folder. The library has a flat shape: root + one level of subdirectories. - We walk it shallowly (one iterdir of root + one iterdir per subdir) - looking for any media file whose stem equals str(post_id). Used by: - - "is this post saved?" badges (any match → yes) - - delete_from_library (delete every match — handles duplicates left - by the old save-to-folder copy bug in a single click) - - the move-aware _save_to_library / library "Move to Folder" actions + Walks shallowly (one iterdir of root + one iterdir per subdir) + and matches files in two ways: + 1. Legacy v0.2.3 layout: stem equals str(post_id) (e.g. 12345.jpg). + 2. Templated layout (post-refactor): basename appears in + `library_meta.filename` for this post_id. + + The templated match requires `db` — when None, only the legacy + digit-stem path runs. Pass `db=self._db` from any caller that + has a Database instance handy (essentially every gui caller). + Used by: + - delete_from_library (delete every copy on disk) + - main_window's bookmark→library preview lookup + - the unified save flow's pre-existing-copy detection (now + handled inside save_post_file via _same_post_on_disk) """ matches: list[Path] = [] root = saved_dir() if not root.is_dir(): return matches + stem = str(post_id) + + # Templated filenames stored for this post, if a db handle was passed. + templated: set[str] = set() + if db is not None: + try: + rows = db.conn.execute( + "SELECT filename FROM library_meta WHERE post_id = ? AND filename != ''", + (post_id,), + ).fetchall() + templated = {r["filename"] for r in rows} + except Exception: + pass # DB issue → degrade to digit-stem-only matching + + def _matches(p: Path) -> bool: + if p.suffix.lower() not in MEDIA_EXTENSIONS: + return False + if p.stem == stem: + return True + if p.name in templated: + return True + return False + for entry in root.iterdir(): - if entry.is_file() and entry.stem == stem and entry.suffix.lower() in MEDIA_EXTENSIONS: + if entry.is_file() and _matches(entry): matches.append(entry) elif entry.is_dir(): for sub in entry.iterdir(): - if sub.is_file() and sub.stem == stem and sub.suffix.lower() in MEDIA_EXTENSIONS: + if sub.is_file() and _matches(sub): matches.append(sub) return matches