cache: delete_from_library cleans up library_meta + matches templated names

Two related fixes that the old delete flow was missing:

1. delete_from_library now accepts an optional `db` parameter which
   it forwards to find_library_files. Without `db`, only digit-stem
   files match (the old behavior — preserved as a fallback). With
   `db`, templated filenames stored in library_meta also match,
   so post-refactor saves like 12345_hatsune_miku.jpg get unlinked
   too. Without this fix, "Unsave from Library" on a templated
   save was a silent no-op.

2. Always cleans up the library_meta row when called with `db`, not
   just when files were unlinked. Two cases this matters for:
     a. Files were on disk and unlinked → meta is now stale.
     b. Files were already gone but the meta lingered (orphan from
        a previous broken delete) → user asked to "unsave," meta
        should reflect that.
   This is the missing half of the cleanup that left some libraries
   with pathologically more meta rows than actual files.
This commit is contained in:
pax 2026-04-09 17:32:28 -05:00
parent 5976a81bb6
commit 150970b56f

View File

@ -434,7 +434,7 @@ def is_cached(url: str, dest_dir: Path | None = None) -> bool:
return cached_path_for(url, dest_dir).exists()
def delete_from_library(post_id: int, folder: str | None = None) -> bool:
def delete_from_library(post_id: int, folder: str | None = None, db=None) -> bool:
"""Delete every saved copy of `post_id` from the library.
Returns True if at least one file was deleted.
@ -445,9 +445,16 @@ def delete_from_library(post_id: int, folder: str | None = None) -> bool:
separation work: a bookmark no longer needs to know which folder its
library file lives in. It also cleans up duplicates left by the old
pre-fix "save to folder = copy" bug in a single Unsave action.
Pass `db` to also match templated filenames (post-refactor saves
that aren't named {post_id}.{ext}) and to clean up the library_meta
row in the same call. Without `db`, only digit-stem files are
found and the meta row stays that's the old broken behavior,
preserved as a fallback for callers that don't have a Database
handle.
"""
from .config import find_library_files
matches = find_library_files(post_id)
matches = find_library_files(post_id, db=db)
deleted = False
for path in matches:
try:
@ -455,6 +462,22 @@ def delete_from_library(post_id: int, folder: str | None = None) -> bool:
deleted = True
except OSError:
pass
# Always drop the meta row, even when no files were unlinked.
# Two cases this matters for:
# 1. Files were on disk and unlinked — meta row is now stale.
# 2. Files were already gone (orphan meta row from a previous
# delete that didn't clean up). The user asked to "unsave"
# this post and the meta should reflect that, even if
# there's nothing left on disk.
# Without this cleanup the post stays "saved" in the DB and
# is_post_in_library lies forever. The lookup is keyed by
# post_id so this is one cheap DELETE regardless of how many
# copies were on disk.
if db is not None:
try:
db.remove_library_meta(post_id)
except Exception:
pass
return deleted