Library metadata: store tags on save, search by tag in Library
- library_meta table stores tags, score, rating, source per post - Metadata saved automatically when saving from Browse - Search box in Library tab filters by tags via DB lookup - Works with all file types
This commit is contained in:
parent
ea089075e6
commit
337d5d8087
@ -59,6 +59,16 @@ CREATE TABLE IF NOT EXISTS blacklisted_posts (
|
|||||||
url TEXT NOT NULL UNIQUE
|
url TEXT NOT NULL UNIQUE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS settings (
|
CREATE TABLE IF NOT EXISTS settings (
|
||||||
key TEXT PRIMARY KEY,
|
key TEXT PRIMARY KEY,
|
||||||
value TEXT NOT NULL
|
value TEXT NOT NULL
|
||||||
@ -439,6 +449,34 @@ class Database:
|
|||||||
rows = self.conn.execute("SELECT url FROM blacklisted_posts").fetchall()
|
rows = self.conn.execute("SELECT url FROM blacklisted_posts").fetchall()
|
||||||
return {r["url"] for r in rows}
|
return {r["url"] for r in rows}
|
||||||
|
|
||||||
|
# -- 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:
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
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()),
|
||||||
|
)
|
||||||
|
self.conn.commit()
|
||||||
|
|
||||||
|
def get_library_meta(self, post_id: int) -> dict | None:
|
||||||
|
row = self.conn.execute("SELECT * FROM library_meta WHERE post_id = ?", (post_id,)).fetchone()
|
||||||
|
return dict(row) if row else None
|
||||||
|
|
||||||
|
def search_library_meta(self, query: str) -> set[int]:
|
||||||
|
"""Search library metadata by tags. Returns matching post IDs."""
|
||||||
|
rows = self.conn.execute(
|
||||||
|
"SELECT post_id FROM library_meta WHERE tags LIKE ?",
|
||||||
|
(f"%{query}%",),
|
||||||
|
).fetchall()
|
||||||
|
return {r["post_id"] for r in rows}
|
||||||
|
|
||||||
|
def remove_library_meta(self, post_id: int) -> None:
|
||||||
|
self.conn.execute("DELETE FROM library_meta WHERE post_id = ?", (post_id,))
|
||||||
|
self.conn.commit()
|
||||||
|
|
||||||
# -- Settings --
|
# -- Settings --
|
||||||
|
|
||||||
def get_setting(self, key: str) -> str:
|
def get_setting(self, key: str) -> str:
|
||||||
|
|||||||
@ -360,7 +360,7 @@ class BooruApp(QMainWindow):
|
|||||||
self._bookmarks_view.bookmark_activated.connect(self._on_bookmark_activated)
|
self._bookmarks_view.bookmark_activated.connect(self._on_bookmark_activated)
|
||||||
self._stack.addWidget(self._bookmarks_view)
|
self._stack.addWidget(self._bookmarks_view)
|
||||||
|
|
||||||
self._library_view = LibraryView()
|
self._library_view = LibraryView(db=self._db)
|
||||||
self._library_view.file_selected.connect(self._on_library_selected)
|
self._library_view.file_selected.connect(self._on_library_selected)
|
||||||
self._library_view.file_activated.connect(self._on_library_activated)
|
self._library_view.file_activated.connect(self._on_library_activated)
|
||||||
self._stack.addWidget(self._library_view)
|
self._stack.addWidget(self._library_view)
|
||||||
@ -1781,6 +1781,12 @@ class BooruApp(QMainWindow):
|
|||||||
import shutil as _sh
|
import shutil as _sh
|
||||||
_sh.copy2(thumb_src, lib_thumb)
|
_sh.copy2(thumb_src, lib_thumb)
|
||||||
|
|
||||||
|
# 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,
|
||||||
|
)
|
||||||
|
|
||||||
where = folder or "Unsorted"
|
where = folder or "Unsorted"
|
||||||
self._signals.bookmark_done.emit(
|
self._signals.bookmark_done.emit(
|
||||||
self._grid.selected_index,
|
self._grid.selected_index,
|
||||||
|
|||||||
@ -15,6 +15,7 @@ from PySide6.QtWidgets import (
|
|||||||
QHBoxLayout,
|
QHBoxLayout,
|
||||||
QPushButton,
|
QPushButton,
|
||||||
QLabel,
|
QLabel,
|
||||||
|
QLineEdit,
|
||||||
QComboBox,
|
QComboBox,
|
||||||
QMenu,
|
QMenu,
|
||||||
QMessageBox,
|
QMessageBox,
|
||||||
@ -75,7 +76,11 @@ class LibraryView(QWidget):
|
|||||||
refresh_btn.clicked.connect(self.refresh)
|
refresh_btn.clicked.connect(self.refresh)
|
||||||
top.addWidget(refresh_btn)
|
top.addWidget(refresh_btn)
|
||||||
|
|
||||||
top.addStretch(1)
|
self._search_input = QLineEdit()
|
||||||
|
self._search_input.setPlaceholderText("Search tags...")
|
||||||
|
self._search_input.returnPressed.connect(self.refresh)
|
||||||
|
top.addWidget(self._search_input, stretch=1)
|
||||||
|
|
||||||
layout.addLayout(top)
|
layout.addLayout(top)
|
||||||
|
|
||||||
# --- Count label ---
|
# --- Count label ---
|
||||||
@ -107,6 +112,15 @@ class LibraryView(QWidget):
|
|||||||
self._files = self._scan_files()
|
self._files = self._scan_files()
|
||||||
self._sort_files()
|
self._sort_files()
|
||||||
|
|
||||||
|
# Filter by tag search if query entered
|
||||||
|
query = self._search_input.text().strip()
|
||||||
|
if query and self._db:
|
||||||
|
matching_ids = self._db.search_library_meta(query)
|
||||||
|
if matching_ids:
|
||||||
|
self._files = [f for f in self._files if f.stem.isdigit() and int(f.stem) in matching_ids]
|
||||||
|
else:
|
||||||
|
self._files = []
|
||||||
|
|
||||||
if self._files:
|
if self._files:
|
||||||
self._count_label.setText(f"{len(self._files)} files")
|
self._count_label.setText(f"{len(self._files)} files")
|
||||||
self._count_label.setStyleSheet("")
|
self._count_label.setStyleSheet("")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user