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
This commit is contained in:
pax 2026-04-10 16:23:54 -05:00
parent 9cc294a16a
commit 94588e324c
3 changed files with 41 additions and 0 deletions

View File

@ -152,6 +152,7 @@ _DEFAULTS = {
"library_dir": "", "library_dir": "",
"infinite_scroll": "0", "infinite_scroll": "0",
"library_filename_template": "", "library_filename_template": "",
"unbookmark_on_save": "0",
} }

View File

@ -39,6 +39,36 @@ class PostActionsController:
def is_post_saved(self, post_id: int) -> bool: def is_post_saved(self, post_id: int) -> bool:
return self._app._db.is_post_in_library(post_id) 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): def get_preview_post(self):
idx = self._app._grid.selected_index idx = self._app._grid.selected_index
if 0 <= idx < len(self._app._posts): 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) await save_post_file(src, post, dest_dir, self._app._db, in_flight, category_fetcher=fetcher)
self.copy_library_thumb(post) self.copy_library_thumb(post)
self._app._signals.bookmark_done.emit(idx, f"Saved {i+1}/{len(posts)} to {where}") self._app._signals.bookmark_done.emit(idx, f"Saved {i+1}/{len(posts)} to {where}")
self._maybe_unbookmark(post)
except Exception as e: except Exception as e:
log.warning(f"Bulk save #{post.id} failed: {e}") log.warning(f"Bulk save #{post.id} failed: {e}")
self._app._signals.batch_done.emit(f"Saved {len(posts)} to {where}") 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)) src = Path(await download_image(post.file_url))
await save_post_file(src, post, dest_dir, self._app._db, in_flight, category_fetcher=fetcher) 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._app._signals.batch_progress.emit(i + 1, len(posts), post.id)
self._maybe_unbookmark(post)
except Exception as e: except Exception as e:
log.warning(f"Batch #{post.id} failed: {e}") log.warning(f"Batch #{post.id} failed: {e}")
self._app._signals.batch_done.emit(f"Downloaded {len(posts)} images to {dest_dir}") 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, self._app._grid.selected_index,
f"Saved #{post.id} to {where}", f"Saved #{post.id} to {where}",
) )
self._maybe_unbookmark(post)
except Exception as e: except Exception as e:
self._app._signals.bookmark_error.emit(str(e)) self._app._signals.bookmark_error.emit(str(e))
@ -487,6 +520,7 @@ class PostActionsController:
self._app._grid.selected_index, self._app._grid.selected_index,
f"Saved to {actual}", f"Saved to {actual}",
) )
self._maybe_unbookmark(post)
except Exception as e: except Exception as e:
self._app._signals.bookmark_error.emit(f"Save failed: {e}") self._app._signals.bookmark_error.emit(f"Save failed: {e}")

View File

@ -187,6 +187,11 @@ class SettingsDialog(QDialog):
self._infinite_scroll.setChecked(self._db.get_setting_bool("infinite_scroll")) self._infinite_scroll.setChecked(self._db.get_setting_bool("infinite_scroll"))
form.addRow("", self._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 # Slideshow monitor
from PySide6.QtWidgets import QApplication from PySide6.QtWidgets import QApplication
self._monitor_combo = QComboBox() 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("preload_thumbnails", "1" if self._preload.isChecked() else "0")
self._db.set_setting("prefetch_mode", self._prefetch_combo.currentText()) 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("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("slideshow_monitor", self._monitor_combo.currentText())
self._db.set_setting("library_dir", self._library_dir.text().strip()) self._db.set_setting("library_dir", self._library_dir.text().strip())
self._db.set_setting("library_filename_template", self._library_filename_template.text().strip()) self._db.set_setting("library_filename_template", self._library_filename_template.text().strip())