musicbrainz-provider #2

Merged
Mrixs merged 72 commits from musicbrainz-provider into master 2026-08-05 20:19:16 +00:00
3 changed files with 133 additions and 36 deletions
Showing only changes of commit a3b8aa8a74 - Show all commits

View File

@@ -49,10 +49,10 @@
- [x] run project tests - must pass before next task
### Task 2: Update Filtering Core Logic
- [ ] Update `FilterOptions` struct in `internal/musicbrainz/filter.go` to include `IgnoreLive` and `IgnoreRemix`
- [ ] Update `ApplyTypeToggles` in `internal/musicbrainz/filter.go` to include logic for "Live" and "Remix" types
- [ ] write unit tests for `ApplyTypeToggles` covering all four toggle types (Single, Compilation, Live, Remix)
- [ ] run project tests - must pass before next task
- [x] Update `FilterOptions` struct in `internal/musicbrainz/filter.go` to include `IgnoreLive` and `IgnoreRemix`
- [x] Update `ApplyTypeToggles` in `internal/musicbrainz/filter.go` to include logic for "Live" and "Remix" types
- [x] write unit tests for `ApplyTypeToggles` covering all four toggle types (Single, Compilation, Live, Remix)
- [x] run project tests - must pass before next task
### Task 3: Update Web UI and Handlers
- [ ] Update `ArtistData` or similar view models to include the new filter booleans

View File

@@ -8,6 +8,8 @@ import (
type FilterOptions struct {
IgnoreSingles bool
IgnoreCompilations bool
IgnoreLive bool
IgnoreRemix bool
}
// hasSliceType reports whether the slice contains any of the wanted values.
@@ -24,8 +26,11 @@ func hasSliceType(types []string, wanted ...string) bool {
// ApplyTypeToggles filters releases based on the IgnoreSingles and IgnoreCompilations flags.
// Implements canonical filtering logic:
// IgnoreSingles filters: Type == "Single" OR Type == "EP" OR SecondaryTypes contains "Single" OR "EP"
// IgnoreCompilations filters: Type == "Compilation" OR SecondaryTypes contains "Compilation"
//
// IgnoreSingles filters: Type == "Single" OR Type == "EP" OR SecondaryTypes contains "Single" OR "EP"
// IgnoreCompilations filters: Type == "Compilation" OR SecondaryTypes contains "Compilation"
// IgnoreLive filters: Type == "Live" OR SecondaryTypes contains "Live"
// IgnoreRemix filters: Type == "Remix" OR SecondaryTypes contains "Remix"
func ApplyTypeToggles(releases []database.ExternalRelease, opts FilterOptions) []database.ExternalRelease {
var result []database.ExternalRelease
for _, release := range releases {
@@ -43,6 +48,20 @@ func ApplyTypeToggles(releases []database.ExternalRelease, opts FilterOptions) [
}
}
// Apply IgnoreLive filtering: filter out if Type is Live OR SecondaryTypes contains Live
if opts.IgnoreLive {
if release.Type == "Live" || hasSliceType(release.SecondaryTypes, "Live") {
continue
}
}
// Apply IgnoreRemix filtering: filter out if Type is Remix OR SecondaryTypes contains Remix
if opts.IgnoreRemix {
if release.Type == "Remix" || hasSliceType(release.SecondaryTypes, "Remix") {
continue
}
}
result = append(result, release)
}
return result
@@ -67,7 +86,21 @@ func ApplyTypeTogglesToReleaseGroups(groups []ReleaseGroup, opts FilterOptions)
}
}
// Apply IgnoreLive filtering: filter out if Type is Live OR SecondaryTypes contains Live
if opts.IgnoreLive {
if rg.Type == "Live" || hasSliceType(rg.SecondaryTypes, "Live") {
continue
}
}
// Apply IgnoreRemix filtering: filter out if Type is Remix OR SecondaryTypes contains Remix
if opts.IgnoreRemix {
if rg.Type == "Remix" || hasSliceType(rg.SecondaryTypes, "Remix") {
continue
}
}
result = append(result, rg)
}
return result
}
}

View File

@@ -15,37 +15,73 @@ func TestApplyTypeToggles(t *testing.T) {
{RGID: "r4", Type: "Album", SecondaryTypes: []string{"Compilation"}},
{RGID: "r5", Type: "EP", SecondaryTypes: []string{}},
{RGID: "r6", Type: "Album", SecondaryTypes: []string{"EP"}},
{RGID: "r7", Type: "Live", SecondaryTypes: []string{}},
{RGID: "r8", Type: "Album", SecondaryTypes: []string{"Live"}},
{RGID: "r9", Type: "Remix", SecondaryTypes: []string{}},
{RGID: "r10", Type: "Album", SecondaryTypes: []string{"Remix"}},
}
tests := []struct {
name string
opts musicbrainz.FilterOptions
expectedCounts int
expectedRGIDs []string
opts musicbrainz.FilterOptions
expectedCounts int
expectedRGIDs []string
}{
{
name: "No filters",
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: false},
expectedCounts: 6,
expectedRGIDs: []string{"r1", "r2", "r3", "r4", "r5", "r6"},
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: false, IgnoreLive: false, IgnoreRemix: false},
expectedCounts: 10,
expectedRGIDs: []string{"r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10"},
},
{
name: "Ignore singles only",
opts: musicbrainz.FilterOptions{IgnoreSingles: true, IgnoreCompilations: false},
expectedCounts: 2, // r3, r4
expectedRGIDs: []string{"r3", "r4"},
opts: musicbrainz.FilterOptions{IgnoreSingles: true, IgnoreCompilations: false, IgnoreLive: false, IgnoreRemix: false},
// Actually: r1(Single), r2(Album+Single), r5(EP), r6(Album+EP) should be filtered out
// Leaving: r3(Compilation), r4(Album+Compilation), r7(Live), r8(Album+Live), r9(Remix), r10(Album+Remix)
expectedCounts: 6,
expectedRGIDs: []string{"r3", "r4", "r7", "r8", "r9", "r10"},
},
{
name: "Ignore compilations only",
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: true},
expectedCounts: 4, // r1, r2, r5, r6
expectedRGIDs: []string{"r1", "r2", "r5", "r6"},
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: true, IgnoreLive: false, IgnoreRemix: false},
// r1, r2, r5, r6, r7, r8, r9, r10 (r3 and r4 filtered out)
expectedCounts: 8,
expectedRGIDs: []string{"r1", "r2", "r5", "r6", "r7", "r8", "r9", "r10"},
},
{
name: "Ignore both",
opts: musicbrainz.FilterOptions{IgnoreSingles: true, IgnoreCompilations: true},
name: "Ignore live only",
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: false, IgnoreLive: true, IgnoreRemix: false},
// r1, r2, r3, r4, r5, r6, r9, r10 (r7 and r8 filtered out)
expectedCounts: 8,
expectedRGIDs: []string{"r1", "r2", "r3", "r4", "r5", "r6", "r9", "r10"},
},
{
name: "Ignore remix only",
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: false, IgnoreLive: false, IgnoreRemix: true},
// r1, r2, r3, r4, r5, r6, r7, r8 (r9 and r10 filtered out)
expectedCounts: 8,
expectedRGIDs: []string{"r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8"},
},
{
name: "Ignore both singles and compilations",
opts: musicbrainz.FilterOptions{IgnoreSingles: true, IgnoreCompilations: true, IgnoreLive: false, IgnoreRemix: false},
// Actually: r1, r2, r5, r6 filtered (singles) and r3, r4 filtered (compilations)
// Leaving: r7(Live), r8(Album+Live), r9(Remix), r10(Album+Remix)
expectedCounts: 4,
expectedRGIDs: []string{"r7", "r8", "r9", "r10"},
},
{
name: "Ignore live and remix",
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: false, IgnoreLive: true, IgnoreRemix: true},
// r1, r2, r3, r4, r5, r6 (r7, r8, r9, r10 filtered out)
expectedCounts: 6,
expectedRGIDs: []string{"r1", "r2", "r3", "r4", "r5", "r6"},
},
{
name: "Ignore all four types",
opts: musicbrainz.FilterOptions{IgnoreSingles: true, IgnoreCompilations: true, IgnoreLive: true, IgnoreRemix: true},
expectedCounts: 0,
expectedRGIDs: []string{},
expectedRGIDs: []string{},
},
}
@@ -72,35 +108,63 @@ func TestApplyTypeTogglesToReleaseGroups(t *testing.T) {
{ID: "g4", Type: "Album", SecondaryTypes: []string{"Compilation"}},
{ID: "g5", Type: "EP", SecondaryTypes: []string{}},
{ID: "g6", Type: "Album", SecondaryTypes: []string{"EP"}},
{ID: "g7", Type: "Live", SecondaryTypes: []string{}},
{ID: "g8", Type: "Album", SecondaryTypes: []string{"Live"}},
{ID: "g9", Type: "Remix", SecondaryTypes: []string{}},
{ID: "g10", Type: "Album", SecondaryTypes: []string{"Remix"}},
}
tests := []struct {
name string
opts musicbrainz.FilterOptions
expectedCounts int
expectedIDs []string
opts musicbrainz.FilterOptions
expectedCounts int
expectedIDs []string
}{
{
name: "No filters",
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: false},
expectedCounts: 6,
expectedIDs: []string{"g1", "g2", "g3", "g4", "g5", "g6"},
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: false, IgnoreLive: false, IgnoreRemix: false},
expectedCounts: 10,
expectedIDs: []string{"g1", "g2", "g3", "g4", "g5", "g6", "g7", "g8", "g9", "g10"},
},
{
name: "Ignore singles only",
opts: musicbrainz.FilterOptions{IgnoreSingles: true, IgnoreCompilations: false},
expectedCounts: 2, // g3, g4
expectedIDs: []string{"g3", "g4"},
opts: musicbrainz.FilterOptions{IgnoreSingles: true, IgnoreCompilations: false, IgnoreLive: false, IgnoreRemix: false},
expectedCounts: 6,
expectedIDs: []string{"g3", "g4", "g7", "g8", "g9", "g10"},
},
{
name: "Ignore compilations only",
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: true},
expectedCounts: 4, // g1, g2, g5, g6
expectedIDs: []string{"g1", "g2", "g5", "g6"},
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: true, IgnoreLive: false, IgnoreRemix: false},
expectedCounts: 8, // g1, g2, g5, g6, g7, g8, g9, g10 (g3 and g4 filtered out)
expectedIDs: []string{"g1", "g2", "g5", "g6", "g7", "g8", "g9", "g10"},
},
{
name: "Ignore both",
opts: musicbrainz.FilterOptions{IgnoreSingles: true, IgnoreCompilations: true},
name: "Ignore live only",
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: false, IgnoreLive: true, IgnoreRemix: false},
expectedCounts: 8, // g1, g2, g3, g4, g5, g6, g9, g10 (g7 and g8 filtered out)
expectedIDs: []string{"g1", "g2", "g3", "g4", "g5", "g6", "g9", "g10"},
},
{
name: "Ignore remix only",
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: false, IgnoreLive: false, IgnoreRemix: true},
expectedCounts: 8, // g1, g2, g3, g4, g5, g6, g7, g8 (g9 and g10 filtered out)
expectedIDs: []string{"g1", "g2", "g3", "g4", "g5", "g6", "g7", "g8"},
},
{
name: "Ignore both singles and compilations",
opts: musicbrainz.FilterOptions{IgnoreSingles: true, IgnoreCompilations: true, IgnoreLive: false, IgnoreRemix: false},
expectedCounts: 4,
expectedIDs: []string{"g7", "g8", "g9", "g10"},
},
{
name: "Ignore live and remix",
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: false, IgnoreLive: true, IgnoreRemix: true},
expectedCounts: 6, // g1, g2, g3, g4, g5, g6 (g7, g8, g9, g10 filtered out)
expectedIDs: []string{"g1", "g2", "g3", "g4", "g5", "g6"},
},
{
name: "Ignore all four types",
opts: musicbrainz.FilterOptions{IgnoreSingles: true, IgnoreCompilations: true, IgnoreLive: true, IgnoreRemix: true},
expectedCounts: 0,
expectedIDs: []string{},
},