Flag slave-only songs whose album or artist the master has

Scans now mark slave-only songs as missing from the master when the master
has their album folder or at least their artist folder. A new Missing from
master filter in Review lists them, split by album and artist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cdnutterandClaude Opus 5.5 committed 2026-10-01 12:31:39 -07:00
1 parent 206b2ab5db
commit 4bae6742a4
9 files changed
+281 -15

No files matched your search

+9
View File
@@ -105,6 +105,8 @@ type masterIndex struct {
byDir map[string][]string // lower(dir) -> rels
byTitle map[string][]string // lower(top folder)|normTitle -> rels
folders masterFolders // artist and album folders, for songs missing from the master
approx *approxIndex // nil unless the pair enables approximate matching
threshold float64
verify VerifyFunc // confirms library-wide approximate matches; nil disables that scope
@@ -113,6 +115,7 @@ type masterIndex struct {
func buildIndex(files map[string]fsops.Info, p store.Pair) *masterIndex {
ix := &masterIndex{files: files, lower: map[string]string{}, byDir: map[string][]string{}, byTitle: map[string][]string{}}
rels := sortedKeys(files)
ix.folders = buildMasterFolders(rels)
if p.ApproxMatching {
ix.approx = buildApproxIndex(rels)
ix.threshold = float64(p.ApproxThreshold) / 100
@@ -327,6 +330,9 @@ func (e *Engine) scan(ctx context.Context, j *Job, pairID int64, trigger string)
pm = &p
}
e.classify(ctx, l, &m, masterFiles[m.RelMaster], si, pm)
if m.Status == store.StatusUnmatched {
m.Missing, m.Reason = ix.folders.missing(rel)
}
if err := e.st.UpsertMatch(ctx, &m); err != nil {
return err
}
@@ -483,6 +489,9 @@ func (e *Engine) refresh(ctx context.Context, l *libs, relSlave string, hint ...
m.Kind = store.KindNone
}
e.classify(ctx, l, &m, mi, si, pm)
if m.Status == store.StatusUnmatched && pm != nil && pm.Status == store.StatusUnmatched {
m.Missing, m.Reason = pm.Missing, pm.Reason // the next scan re-checks the master's folders
}
_ = e.st.UpsertMatch(ctx, &m)
}