Add finding and removing folders without music

The new Cleanup tab lists the top-most folders in either library that
contain no music file (per the pair's extensions). Removing them needs
confirmation, plus an explicit acknowledgement when they still hold
files; each folder is re-checked for music and moved into the
quarantine (undoable from History, purged after the retention period).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cdnutterandClaude Opus 5.5 committed 2026-09-30 12:24:47 -07:00
1 parent e0617047f7
commit 30fab3a208
11 files changed
+760 -8

No files matched your search

+12 -1
View File
@@ -622,7 +622,7 @@ func (e *Engine) Undo(ctx context.Context, opID int64) error {
return errors.New("the quarantined original was already purged")
}
switch o.Action {
case store.ActLink, store.ActPromote, store.ActBuild, store.ActRemove, store.ActRename:
case store.ActLink, store.ActPromote, store.ActBuild, store.ActRemove, store.ActRename, store.ActRemoveFolder:
default:
// History can hold operations of features that were removed (tag
// edits, file moves); undoing them as a link would be wrong.
@@ -632,6 +632,17 @@ func (e *Engine) Undo(ctx context.Context, opID int64) error {
if err != nil {
return err
}
if o.Action == store.ActRemoveFolder {
if err := undoRemoveFolder(l, o); err != nil {
return err
}
if err := e.st.MarkUndone(ctx, o.ID); err != nil {
return err
}
e.log.Info("folder restored from quarantine", "op", o.ID)
pruneEmpty(filepath.Dir(o.QuarantinePath), l.quarantine)
return nil
}
if o.Action == store.ActRename {
if err := undoRename(l, o); err != nil {
return err