From ed0b08967e2ee27f49f77fb1ff246f1641cfd7af Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 9 Jul 2026 11:23:10 -0600 Subject: [PATCH] Fall back to rm when a fuzzy-dedup delete target isn't tracked in beets A handful of confirmed candidates reference files that are no longer in the beets DB (removed by some other pass, or never re-imported after a move) but are still sitting on disk -- beet remove can't match them by id or path either way, so they failed forever. If the file still exists after a "No matching items found" error, remove it directly instead of counting it as a failure. Applies to both --apply and --apply-pairs. --- pipeline/lib/find-fuzzy-dupes.py | 33 +++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/pipeline/lib/find-fuzzy-dupes.py b/pipeline/lib/find-fuzzy-dupes.py index 256559a..f4a2fed 100755 --- a/pipeline/lib/find-fuzzy-dupes.py +++ b/pipeline/lib/find-fuzzy-dupes.py @@ -180,9 +180,22 @@ def _apply_pairs(pairs_file: str, emit_json: bool) -> int: capture_output=True, text=True, ) if result.returncode != 0: - print(f" FAILED: {delete_path} — {result.stderr.strip()}", file=sys.stderr) - failed += 1 - continue + if "No matching items found" in result.stderr and os.path.exists(delete_path): + # Not tracked in beets at all (e.g. it was already removed + # from the DB by some other pass, or never re-imported after + # a move) but the duplicate file itself is still sitting on + # disk -- `beet remove` can never match it by id or path + # either way, so just remove the file directly. + try: + os.remove(delete_path) + except OSError as exc: + print(f" FAILED: {delete_path} — not in beets, then rm failed: {exc}", file=sys.stderr) + failed += 1 + continue + else: + print(f" FAILED: {delete_path} — {result.stderr.strip()}", file=sys.stderr) + failed += 1 + continue print(f" DELETE {delete_path}") deleted += 1 if emit_json: @@ -372,8 +385,18 @@ def main() -> int: capture_output=True, text=True, ) if result.returncode != 0: - print(f" FAILED: {path} — {result.stderr.strip()}", file=sys.stderr) - failed += 1 + if "No matching items found" in result.stderr and os.path.exists(path): + # Item was already gone from beets by the time we got here + # (e.g. removed by an earlier pass) but the file is still on + # disk -- remove it directly instead of counting it failed. + try: + os.remove(path) + except OSError as exc: + print(f" FAILED: {path} — not in beets, then rm failed: {exc}", file=sys.stderr) + failed += 1 + else: + print(f" FAILED: {path} — {result.stderr.strip()}", file=sys.stderr) + failed += 1 deleted = len(delete_targets) - failed - skipped_unconfirmed print(f"[fuzzy-dupes] done. {deleted} deleted, {failed} failed, {skipped_unconfirmed} skipped (unconfirmed).") return 1 if failed else 0