From 94588e324c29e173118a4d2aa7ebcb7b9563346c Mon Sep 17 00:00:00 2001 From: pax Date: Fri, 10 Apr 2026 16:23:54 -0500 Subject: [PATCH] add unbookmark-on-save setting New setting "Remove bookmark when saved to library" (off by default). When enabled, _maybe_unbookmark runs directly in each save callback after save_post_file succeeds -- handles DB removal, grid dot, preview state, popout sync, and bookmarks tab refresh. Wired into all 4 save paths: save_to_library, bulk_save, save_as, batch_download_to. behavior change: opt-in setting, off by default --- booru_viewer/core/db.py | 1 + booru_viewer/gui/post_actions.py | 34 ++++++++++++++++++++++++++++++++ booru_viewer/gui/settings.py | 6 ++++++ 3 files changed, 41 insertions(+) diff --git a/booru_viewer/core/db.py b/booru_viewer/core/db.py index c5c708e..8be4bbc 100644 --- a/booru_viewer/core/db.py +++ b/booru_viewer/core/db.py @@ -152,6 +152,7 @@ _DEFAULTS = { "library_dir": "", "infinite_scroll": "0", "library_filename_template": "", + "unbookmark_on_save": "0", } diff --git a/booru_viewer/gui/post_actions.py b/booru_viewer/gui/post_actions.py index 034a709..428041d 100644 --- a/booru_viewer/gui/post_actions.py +++ b/booru_viewer/gui/post_actions.py @@ -39,6 +39,36 @@ class PostActionsController: def is_post_saved(self, post_id: int) -> bool: return self._app._db.is_post_in_library(post_id) + def _maybe_unbookmark(self, post) -> None: + """Remove the bookmark for *post* if the unbookmark-on-save setting is on. + + Handles DB removal, grid thumbnail dot, preview state, bookmarks + tab refresh, and popout sync in one place so every save path + (single, bulk, Save As, batch download) can call it. + """ + if not self._app._db.get_setting_bool("unbookmark_on_save"): + return + site_id = ( + self._app._preview._current_site_id + or self._app._site_combo.currentData() + ) + if not site_id or not self._app._db.is_bookmarked(site_id, post.id): + return + self._app._db.remove_bookmark(site_id, post.id) + # Update grid thumbnail bookmark dot + for i, p in enumerate(self._app._posts): + if p.id == post.id and i < len(self._app._grid._thumbs): + self._app._grid._thumbs[i].set_bookmarked(False) + break + # Update preview and popout + if (self._app._preview._current_post + and self._app._preview._current_post.id == post.id): + self._app._preview.update_bookmark_state(False) + self._app._popout_ctrl.update_state() + # Refresh bookmarks tab if visible + if self._app._stack.currentIndex() == 1: + self._app._bookmarks_view.refresh() + def get_preview_post(self): idx = self._app._grid.selected_index if 0 <= idx < len(self._app._posts): @@ -289,6 +319,7 @@ class PostActionsController: await save_post_file(src, post, dest_dir, self._app._db, in_flight, category_fetcher=fetcher) self.copy_library_thumb(post) self._app._signals.bookmark_done.emit(idx, f"Saved {i+1}/{len(posts)} to {where}") + self._maybe_unbookmark(post) except Exception as e: log.warning(f"Bulk save #{post.id} failed: {e}") self._app._signals.batch_done.emit(f"Saved {len(posts)} to {where}") @@ -374,6 +405,7 @@ class PostActionsController: src = Path(await download_image(post.file_url)) await save_post_file(src, post, dest_dir, self._app._db, in_flight, category_fetcher=fetcher) self._app._signals.batch_progress.emit(i + 1, len(posts), post.id) + self._maybe_unbookmark(post) except Exception as e: log.warning(f"Batch #{post.id} failed: {e}") self._app._signals.batch_done.emit(f"Downloaded {len(posts)} images to {dest_dir}") @@ -444,6 +476,7 @@ class PostActionsController: self._app._grid.selected_index, f"Saved #{post.id} to {where}", ) + self._maybe_unbookmark(post) except Exception as e: self._app._signals.bookmark_error.emit(str(e)) @@ -487,6 +520,7 @@ class PostActionsController: self._app._grid.selected_index, f"Saved to {actual}", ) + self._maybe_unbookmark(post) except Exception as e: self._app._signals.bookmark_error.emit(f"Save failed: {e}") diff --git a/booru_viewer/gui/settings.py b/booru_viewer/gui/settings.py index 02c192d..74e9eee 100644 --- a/booru_viewer/gui/settings.py +++ b/booru_viewer/gui/settings.py @@ -187,6 +187,11 @@ class SettingsDialog(QDialog): self._infinite_scroll.setChecked(self._db.get_setting_bool("infinite_scroll")) form.addRow("", self._infinite_scroll) + # Unbookmark on save + self._unbookmark_on_save = QCheckBox("Remove bookmark when saved to library") + self._unbookmark_on_save.setChecked(self._db.get_setting_bool("unbookmark_on_save")) + form.addRow("", self._unbookmark_on_save) + # Slideshow monitor from PySide6.QtWidgets import QApplication self._monitor_combo = QComboBox() @@ -779,6 +784,7 @@ class SettingsDialog(QDialog): self._db.set_setting("preload_thumbnails", "1" if self._preload.isChecked() else "0") self._db.set_setting("prefetch_mode", self._prefetch_combo.currentText()) self._db.set_setting("infinite_scroll", "1" if self._infinite_scroll.isChecked() else "0") + self._db.set_setting("unbookmark_on_save", "1" if self._unbookmark_on_save.isChecked() else "0") self._db.set_setting("slideshow_monitor", self._monitor_combo.currentText()) self._db.set_setting("library_dir", self._library_dir.text().strip()) self._db.set_setting("library_filename_template", self._library_filename_template.text().strip())