Stop warning about slave-only content in layout checks
A singles library naturally has artists and songs the albums library lacks, so "only N of M top-level folders exist in the master" and "N of M slave files have no counterpart" were false alarms. Layout warnings now only flag real layout problems: - Folders that are the same but named differently (case, punctuation, accents, "&"/"and", leading/trailing "The"), at the top level and one level down inside shared folders, with examples. - Songs found in both libraries that mostly live in a different folder in the master (e.g. Artist/Song vs Artist/Album/Song). Slave-only songs are ignored, as are singles/EPs/compilations matched to their album version. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e8c534a3ae
commit
0ae4e85bd2
4 files changed
+269
-37
No files matched your search
@@ -0,0 +1,104 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func scanWarnings(t *testing.T, ev *env) []string {
|
||||
t.Helper()
|
||||
ev.scan()
|
||||
p, err := ev.st.Pair(ctx, ev.pair.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var out []string
|
||||
for _, w := range p.LastScanWarnings {
|
||||
if !strings.Contains(w, "ffprobe") {
|
||||
out = append(out, w)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// The user's situation: a singles library with far more artists and songs
|
||||
// than the albums library. Slave-only content must not trigger warnings.
|
||||
func TestSlaveOnlyContentIsNotALayoutProblem(t *testing.T) {
|
||||
ev := setup(t, false)
|
||||
for i := 0; i < 40; i++ {
|
||||
ev.write(ev.slave, fmt.Sprintf("Singles Artist %02d/Some Single/Song.mp3", i), "s")
|
||||
}
|
||||
for i := 0; i < 10; i++ {
|
||||
rel := fmt.Sprintf("Shared Artist/Album/%02d Track.flac", i)
|
||||
ev.write(ev.master, rel, "same")
|
||||
ev.write(ev.slave, rel, "same")
|
||||
}
|
||||
ev.write(ev.master, "Master Only/Album/01 X.flac", "m")
|
||||
if w := scanWarnings(t, ev); len(w) != 0 {
|
||||
t.Fatalf("slave-only content should not produce warnings, got %q", w)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenamedFoldersAreReported(t *testing.T) {
|
||||
ev := setup(t, false)
|
||||
ev.write(ev.master, "AC_DC/Back in Black/01 Hells Bells.flac", "a")
|
||||
ev.write(ev.slave, "AC-DC/Back in Black/01 Hells Bells.mp3", "b")
|
||||
ev.write(ev.master, "The Beatles/Abbey Road/01 Come Together.flac", "a")
|
||||
ev.write(ev.slave, "Beatles, The/Abbey Road/01 Come Together.mp3", "b")
|
||||
ev.write(ev.master, "Avenged Sevenfold/City of Evil/03 Bat Country.flac", "a")
|
||||
ev.write(ev.slave, "Avenged Sevenfold/City Of Evil/03 Bat Country.mp3", "b")
|
||||
ev.write(ev.slave, "Beyoncé/Lemonade/Formation.mp3", "b")
|
||||
ev.write(ev.master, "Beyonce/Lemonade/Formation.flac", "a")
|
||||
w := scanWarnings(t, ev)
|
||||
if len(w) != 1 {
|
||||
t.Fatalf("want one renamed-folders warning, got %q", w)
|
||||
}
|
||||
for _, want := range []string{`"AC-DC" (slave) vs "AC_DC" (master)`, `"Avenged Sevenfold/City Of Evil" (slave) vs "Avenged Sevenfold/City of Evil" (master)`, "4 folders", "1 more"} {
|
||||
if !strings.Contains(w[0], want) {
|
||||
t.Errorf("warning %q should contain %q", w[0], want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A slave library without album folders is a genuine layout difference.
|
||||
func TestDifferentLayoutIsReported(t *testing.T) {
|
||||
ev := setup(t, false)
|
||||
for i := 0; i < 24; i++ {
|
||||
ev.write(ev.master, fmt.Sprintf("Band/Album/%02d Song Number %d.flac", i+1, i), "m")
|
||||
ev.write(ev.slave, fmt.Sprintf("Band/Song Number %d.mp3", i), "s")
|
||||
}
|
||||
w := scanWarnings(t, ev)
|
||||
if len(w) != 1 || !strings.Contains(w[0], "Of 24 songs found in both libraries, 24 are in a different folder") {
|
||||
t.Fatalf("want a different-layout warning, got %q", w)
|
||||
}
|
||||
}
|
||||
|
||||
// Singles matched to their album version are intended, not a layout problem.
|
||||
func TestSinglesMatchedToAlbumsAreNotALayoutProblem(t *testing.T) {
|
||||
ev := setup(t, false)
|
||||
enableApprox(t, ev)
|
||||
for i := 0; i < 24; i++ {
|
||||
ev.write(ev.master, fmt.Sprintf("Band/Album/%02d Song Number %d.flac", i+1, i), "m")
|
||||
ev.write(ev.slave, fmt.Sprintf("Band/Song Number %d - Single/Song Number %d.mp3", i, i), "s")
|
||||
}
|
||||
if w := scanWarnings(t, ev); len(w) != 0 {
|
||||
t.Fatalf("singles matched to album versions should not warn, got %q", w)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFolderKey(t *testing.T) {
|
||||
same := [][2]string{{"AC/DC", "AC-DC"}, {"The Beatles", "Beatles, The"}, {"Simon & Garfunkel", "Simon and Garfunkel"},
|
||||
{"Beyoncé", "Beyonce"}, {"City Of Evil", "City of Evil"}, {"Sigur Rós", "Sigur Ros"}}
|
||||
for _, p := range same {
|
||||
if folderKey(p[0]) != folderKey(p[1]) {
|
||||
t.Errorf("%q and %q should share a key (%q vs %q)", p[0], p[1], folderKey(p[0]), folderKey(p[1]))
|
||||
}
|
||||
}
|
||||
if folderKey("Theory of a Deadman") == folderKey("ory of a Deadman") {
|
||||
t.Error(`"The" must only be stripped as a whole word`)
|
||||
}
|
||||
if folderKey("Nightmare") == folderKey("Nightmare (Deluxe)") {
|
||||
t.Error("different folders must keep different keys")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user