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>
65 lines
2.7 KiB
Go
65 lines
2.7 KiB
Go
package engine
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/cdnutter/playlink/internal/store"
|
|
)
|
|
|
|
func TestMissingFromMaster(t *testing.T) {
|
|
ev := setup(t, false)
|
|
m, s := ev.master, ev.slave
|
|
ev.write(m, "Caravan Palace/Robot Face/01 Lone Digger.flac", "a")
|
|
ev.write(m, "Caravan Palace/Chronologic/Disc 1/01 Miracle.flac", "b")
|
|
ev.write(s, "Caravan Palace/Robot Face/01 Lone Digger.flac", "a")
|
|
ev.write(s, "Caravan Palace/Robot Face/05 Waterguns.mp3", "song") // album in master
|
|
ev.write(s, "Caravan Palace/robot face (Deluxe Edition)/12 Bonus.mp3", "song") // same album, other spelling
|
|
ev.write(s, "Caravan Palace/Chronologic/Disc 2/03 Plume.mp3", "song") // disc folders ignored
|
|
ev.write(s, "Caravan Palace/Panic/01 Dragons.mp3", "song") // only the artist
|
|
ev.write(s, "Caravan Palace/Loose.mp3", "song") // only the artist
|
|
ev.write(s, "Unknown Artist/Album/Song.mp3", "song") // neither
|
|
ev.scan()
|
|
|
|
want := map[string]string{
|
|
"Caravan Palace/Robot Face/05 Waterguns.mp3": "album",
|
|
"Caravan Palace/robot face (Deluxe Edition)/12 Bonus.mp3": "album",
|
|
"Caravan Palace/Chronologic/Disc 2/03 Plume.mp3": "album",
|
|
"Caravan Palace/Panic/01 Dragons.mp3": "artist",
|
|
"Caravan Palace/Loose.mp3": "artist",
|
|
"Unknown Artist/Album/Song.mp3": "",
|
|
"Caravan Palace/Robot Face/01 Lone Digger.flac": "",
|
|
}
|
|
for rel, level := range want {
|
|
mt, err := ev.st.MatchBySlave(ctx, ev.pair.ID, rel)
|
|
if err != nil {
|
|
t.Fatal(rel, err)
|
|
}
|
|
if mt.Missing != level {
|
|
t.Errorf("%s: missing %q, want %q", rel, mt.Missing, level)
|
|
}
|
|
}
|
|
mt, _ := ev.st.MatchBySlave(ctx, ev.pair.ID, "Caravan Palace/Chronologic/Disc 2/03 Plume.mp3")
|
|
if !strings.Contains(mt.Reason, `"Caravan Palace/Chronologic"`) {
|
|
t.Errorf("reason should name the master's album folder: %q", mt.Reason)
|
|
}
|
|
|
|
sum, err := ev.st.Summary(ctx, ev.pair.ID)
|
|
if err != nil || sum.Missing["album"] != 3 || sum.Missing["artist"] != 2 {
|
|
t.Fatalf("summary %+v %v", sum.Missing, err)
|
|
}
|
|
if _, n, _ := ev.st.Matches(ctx, ev.pair.ID, store.MatchFilter{Status: "missing"}); n != 5 {
|
|
t.Fatalf("missing filter: %d", n)
|
|
}
|
|
if _, n, _ := ev.st.Matches(ctx, ev.pair.ID, store.MatchFilter{Status: "missing_album"}); n != 3 {
|
|
t.Fatalf("missing_album filter: %d", n)
|
|
}
|
|
|
|
// Once the master gets the song, it is no longer missing.
|
|
ev.write(m, "Caravan Palace/Robot Face/05 Waterguns.mp3", "song")
|
|
ev.scan()
|
|
if mt, _ := ev.st.MatchBySlave(ctx, ev.pair.ID, "Caravan Palace/Robot Face/05 Waterguns.mp3"); mt.Missing != "" || mt.Status == store.StatusUnmatched {
|
|
t.Fatalf("now in master: %+v", mt)
|
|
}
|
|
}
|