From 29ffe0be7a1c427f9704d763ce44a2373de845b9 Mon Sep 17 00:00:00 2001 From: pax Date: Sun, 5 Apr 2026 16:46:48 -0500 Subject: [PATCH] Store tag categories in library metadata, unsave from bookmarks - tag_categories stored as JSON in library_meta table - Library and Bookmarks info panels show categorized tags - Bookmarks falls back to library_meta for categories - Added Unsave from Library to bookmarks right-click menu --- booru_viewer/core/db.py | 38 +++++++++++++++++++++++------------ booru_viewer/gui/app.py | 15 +++++++++----- booru_viewer/gui/bookmarks.py | 5 +++++ 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/booru_viewer/core/db.py b/booru_viewer/core/db.py index e456862..42b7254 100644 --- a/booru_viewer/core/db.py +++ b/booru_viewer/core/db.py @@ -60,13 +60,14 @@ CREATE TABLE IF NOT EXISTS blacklisted_posts ( ); CREATE TABLE IF NOT EXISTS library_meta ( - post_id INTEGER PRIMARY KEY, - tags TEXT NOT NULL DEFAULT '', - score INTEGER DEFAULT 0, - rating TEXT, - source TEXT, - file_url TEXT, - saved_at TEXT + post_id INTEGER PRIMARY KEY, + tags TEXT NOT NULL DEFAULT '', + tag_categories TEXT DEFAULT '', + score INTEGER DEFAULT 0, + rating TEXT, + source TEXT, + file_url TEXT, + saved_at TEXT ); CREATE TABLE IF NOT EXISTS settings ( @@ -451,19 +452,30 @@ class Database: # -- Library Metadata -- - def save_library_meta(self, post_id: int, tags: str = "", score: int = 0, - rating: str = None, source: str = None, file_url: str = None) -> None: + def save_library_meta(self, post_id: int, tags: str = "", tag_categories: dict = None, + score: int = 0, rating: str = None, source: str = None, + file_url: str = None) -> None: + import json from datetime import datetime, timezone + cats_json = json.dumps(tag_categories) if tag_categories else "" self.conn.execute( - "INSERT OR REPLACE INTO library_meta (post_id, tags, score, rating, source, file_url, saved_at) " - "VALUES (?, ?, ?, ?, ?, ?, ?)", - (post_id, tags, score, rating, source, file_url, datetime.now(timezone.utc).isoformat()), + "INSERT OR REPLACE INTO library_meta " + "(post_id, tags, tag_categories, score, rating, source, file_url, saved_at) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + (post_id, tags, cats_json, score, rating, source, file_url, + datetime.now(timezone.utc).isoformat()), ) self.conn.commit() def get_library_meta(self, post_id: int) -> dict | None: + import json row = self.conn.execute("SELECT * FROM library_meta WHERE post_id = ?", (post_id,)).fetchone() - return dict(row) if row else None + if not row: + return None + d = dict(row) + cats = d.get("tag_categories", "") + d["tag_categories"] = json.loads(cats) if cats else {} + return d def search_library_meta(self, query: str) -> set[int]: """Search library metadata by tags. Returns matching post IDs.""" diff --git a/booru_viewer/gui/app.py b/booru_viewer/gui/app.py index 469db4d..bd0882b 100644 --- a/booru_viewer/gui/app.py +++ b/booru_viewer/gui/app.py @@ -1127,7 +1127,7 @@ class BooruApp(QMainWindow): id=int(stem), file_url=meta.get("file_url", ""), preview_url=None, tags=meta.get("tags", ""), score=meta.get("score", 0), rating=meta.get("rating"), - source=meta.get("source"), tag_categories={}, + source=meta.get("source"), tag_categories=meta.get("tag_categories", {}), ) self._info_panel.set_post(p) @@ -1143,7 +1143,7 @@ class BooruApp(QMainWindow): id=int(stem), file_url=meta.get("file_url", ""), preview_url=None, tags=meta.get("tags", ""), score=meta.get("score", 0), rating=meta.get("rating"), - source=meta.get("source"), tag_categories={}, + source=meta.get("source"), tag_categories=meta.get("tag_categories", {}), ) self._info_panel.set_post(p) @@ -1152,11 +1152,14 @@ class BooruApp(QMainWindow): # Show bookmark tags in info panel if self._info_panel.isVisible(): from ..core.api.base import Post + # Try library metadata for categories + meta = self._db.get_library_meta(fav.post_id) + cats = meta.get("tag_categories", {}) if meta else {} p = Post( id=fav.post_id, file_url=fav.file_url or "", preview_url=fav.preview_url, tags=fav.tags or "", score=fav.score or 0, rating=fav.rating, - source=fav.source, tag_categories={}, + source=fav.source, tag_categories=cats, ) self._info_panel.set_post(p) self._on_bookmark_activated(fav) @@ -1818,8 +1821,10 @@ class BooruApp(QMainWindow): # Store metadata for library search self._db.save_library_meta( - post_id=post.id, tags=post.tags, score=post.score, - rating=post.rating, source=post.source, file_url=post.file_url, + post_id=post.id, tags=post.tags, + tag_categories=post.tag_categories, + score=post.score, rating=post.rating, + source=post.source, file_url=post.file_url, ) where = folder or "Unsorted" diff --git a/booru_viewer/gui/bookmarks.py b/booru_viewer/gui/bookmarks.py index d861fe8..1ac9c64 100644 --- a/booru_viewer/gui/bookmarks.py +++ b/booru_viewer/gui/bookmarks.py @@ -230,6 +230,7 @@ class BookmarksView(QWidget): save_lib_menu.addSeparator() save_lib_new = save_lib_menu.addAction("+ New Folder...") + unsave_lib = menu.addAction("Unsave from Library") copy_file = menu.addAction("Copy File to Clipboard") copy_url = menu.addAction("Copy Image URL") copy_tags = menu.addAction("Copy Tags") @@ -277,6 +278,10 @@ class BookmarksView(QWidget): if dest: import shutil shutil.copy2(src, dest) + elif action == unsave_lib: + from ..core.cache import delete_from_library + if delete_from_library(fav.post_id, fav.folder): + self.refresh() elif action == copy_file: path = fav.cached_path if path and Path(path).exists():