Pre-release fixes for v0.1.5

- Fix Library slideshow navigation (was falling through to Browse)
- Fix bookmarks import signal using wrong variable name
- Fix "Favoriting" status message → "Bookmarking"
- Rename FavThumbSignals → BookmarkThumbSignals
- Update README: all Favorite→Bookmark, add Library section
- Add Library tab to keybinds documentation
This commit is contained in:
pax 2026-04-05 03:13:00 -05:00
parent c26d9a64f9
commit 192397f1ec
3 changed files with 27 additions and 11 deletions

View File

@ -48,18 +48,26 @@ Supports custom styling via `custom.qss` — see [Theming](#theming).
- Right-click preview → "Slideshow Mode" for fullscreen viewing - Right-click preview → "Slideshow Mode" for fullscreen viewing
- Arrow keys / `h`/`j`/`k`/`l` navigate posts (including during video playback) - Arrow keys / `h`/`j`/`k`/`l` navigate posts (including during video playback)
- `,` / `.` seek 5 seconds in videos, `Space` toggles play/pause - `,` / `.` seek 5 seconds in videos, `Space` toggles play/pause
- Toolbar with Favorite and Save/Unsave toggle buttons showing current state - Toolbar with Bookmark and Save/Unsave toggle buttons showing current state
- `F11` toggles fullscreen/windowed, `Ctrl+H` hides all UI - `F11` toggles fullscreen/windowed, `Ctrl+H` hides all UI
- Bidirectional sync — clicking posts in the main grid updates the slideshow - Bidirectional sync — clicking posts in the main grid updates the slideshow
- Page boundary navigation — past the last/first post loads next/prev page - Page boundary navigation — past the last/first post loads next/prev page
### Favorites & Library ### Bookmarks & Library
- Favorite posts, organize into folders - Bookmark posts, organize into folders
- Three-tab layout: Browse, Bookmarks, and Library
- Save to library (unsorted or per-folder), drag-and-drop thumbnails as files - Save to library (unsorted or per-folder), drag-and-drop thumbnails as files
- Multi-select (Ctrl/Shift+Click, Ctrl+A) with bulk actions - Multi-select (Ctrl/Shift+Click, Ctrl+A) with bulk actions
- Bulk context menus in both Browse and Favorites tabs - Bulk context menus in both Browse and Bookmarks tabs
- Unsave from Library available in grid, preview, and slideshow - Unsave from Library available in grid, preview, and slideshow
- Import/export favorites as JSON - Import/export bookmarks as JSON
### Library
- Dedicated tab for browsing saved files on disk
- Folder sidebar with configurable library directory
- Sort by date, name, or size
- FFmpeg-based video thumbnail generation
- Missing file detection for removed or relocated media
### Search ### Search
- Inline history dropdown inside the search bar - Inline history dropdown inside the search bar
@ -115,7 +123,7 @@ Windows 10 dark mode is automatically detected and applied.
| Left / Right | Previous / next post | | Left / Right | Previous / next post |
| `,` / `.` | Seek 5s back / forward (video) | | `,` / `.` | Seek 5s back / forward (video) |
| `Space` | Play / pause (video) | | `Space` | Play / pause (video) |
| Right click | Context menu (favorite, save, slideshow) | | Right click | Context menu (bookmark, save, slideshow) |
### Slideshow ### Slideshow

View File

@ -1023,6 +1023,14 @@ class BooruApp(QMainWindow):
if 0 <= idx < len(favs): if 0 <= idx < len(favs):
grid._select(idx) grid._select(idx)
self._on_bookmark_activated(favs[idx]) self._on_bookmark_activated(favs[idx])
elif self._stack.currentIndex() == 2:
# Library view
grid = self._library_view._grid
files = self._library_view._files
idx = grid.selected_index + direction
if 0 <= idx < len(files):
grid._select(idx)
self._library_view.file_activated.emit(str(files[idx]))
else: else:
idx = self._grid.selected_index + direction idx = self._grid.selected_index + direction
log.info(f"Navigate: direction={direction} current={self._grid.selected_index} next={idx} total={len(self._posts)}") log.info(f"Navigate: direction={direction} current={self._grid.selected_index} next={idx} total={len(self._posts)}")
@ -1328,7 +1336,7 @@ class BooruApp(QMainWindow):
site_id = self._site_combo.currentData() site_id = self._site_combo.currentData()
if not site_id: if not site_id:
return return
self._status.showMessage(f"Favoriting {len(posts)}...") self._status.showMessage(f"Bookmarking {len(posts)}...")
async def _do(): async def _do():
for i, (idx, post) in enumerate(zip(indices, posts)): for i, (idx, post) in enumerate(zip(indices, posts)):
@ -1544,7 +1552,7 @@ class BooruApp(QMainWindow):
dlg = SettingsDialog(self._db, self) dlg = SettingsDialog(self._db, self)
dlg.settings_changed.connect(self._apply_settings) dlg.settings_changed.connect(self._apply_settings)
self._bookmarks_imported = False self._bookmarks_imported = False
dlg.bookmarks_imported.connect(lambda: setattr(self, '_favorites_imported', True)) dlg.bookmarks_imported.connect(lambda: setattr(self, '_bookmarks_imported', True))
dlg.exec() dlg.exec()
if self._bookmarks_imported: if self._bookmarks_imported:
self._switch_view(1) self._switch_view(1)

View File

@ -30,7 +30,7 @@ from .grid import ThumbnailGrid
log = logging.getLogger("booru") log = logging.getLogger("booru")
class FavThumbSignals(QObject): class BookmarkThumbSignals(QObject):
thumb_ready = Signal(int, str) thumb_ready = Signal(int, str)
@ -44,7 +44,7 @@ class BookmarksView(QWidget):
super().__init__(parent) super().__init__(parent)
self._db = db self._db = db
self._bookmarks: list[Bookmark] = [] self._bookmarks: list[Bookmark] = []
self._signals = FavThumbSignals() self._signals = BookmarkThumbSignals()
self._signals.thumb_ready.connect(self._on_thumb_ready, Qt.ConnectionType.QueuedConnection) self._signals.thumb_ready.connect(self._on_thumb_ready, Qt.ConnectionType.QueuedConnection)
layout = QVBoxLayout(self) layout = QVBoxLayout(self)
@ -156,7 +156,7 @@ class BookmarksView(QWidget):
path = await download_thumbnail(url) path = await download_thumbnail(url)
self._signals.thumb_ready.emit(index, str(path)) self._signals.thumb_ready.emit(index, str(path))
except Exception as e: except Exception as e:
log.warning(f"Fav thumb {index} failed: {e}") log.warning(f"Bookmark thumb {index} failed: {e}")
threading.Thread(target=lambda: asyncio.run(_dl()), daemon=True).start() threading.Thread(target=lambda: asyncio.run(_dl()), daemon=True).start()
def _on_thumb_ready(self, index: int, path: str) -> None: def _on_thumb_ready(self, index: int, path: str) -> None: