musicbrainz-provider #2
@@ -49,10 +49,10 @@
|
|||||||
- [x] run project tests - must pass before next task
|
- [x] run project tests - must pass before next task
|
||||||
|
|
||||||
### Task 2: Update Filtering Core Logic
|
### Task 2: Update Filtering Core Logic
|
||||||
- [ ] Update `FilterOptions` struct in `internal/musicbrainz/filter.go` to include `IgnoreLive` and `IgnoreRemix`
|
- [x] 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
|
- [x] 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)
|
- [x] write unit tests for `ApplyTypeToggles` covering all four toggle types (Single, Compilation, Live, Remix)
|
||||||
- [ ] run project tests - must pass before next task
|
- [x] run project tests - must pass before next task
|
||||||
|
|
||||||
### Task 3: Update Web UI and Handlers
|
### Task 3: Update Web UI and Handlers
|
||||||
- [ ] Update `ArtistData` or similar view models to include the new filter booleans
|
- [ ] Update `ArtistData` or similar view models to include the new filter booleans
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
type FilterOptions struct {
|
type FilterOptions struct {
|
||||||
IgnoreSingles bool
|
IgnoreSingles bool
|
||||||
IgnoreCompilations bool
|
IgnoreCompilations bool
|
||||||
|
IgnoreLive bool
|
||||||
|
IgnoreRemix bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// hasSliceType reports whether the slice contains any of the wanted values.
|
// 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.
|
// ApplyTypeToggles filters releases based on the IgnoreSingles and IgnoreCompilations flags.
|
||||||
// Implements canonical filtering logic:
|
// 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 {
|
func ApplyTypeToggles(releases []database.ExternalRelease, opts FilterOptions) []database.ExternalRelease {
|
||||||
var result []database.ExternalRelease
|
var result []database.ExternalRelease
|
||||||
for _, release := range releases {
|
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)
|
result = append(result, release)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
@@ -67,6 +86,20 @@ 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)
|
result = append(result, rg)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -15,37 +15,73 @@ func TestApplyTypeToggles(t *testing.T) {
|
|||||||
{RGID: "r4", Type: "Album", SecondaryTypes: []string{"Compilation"}},
|
{RGID: "r4", Type: "Album", SecondaryTypes: []string{"Compilation"}},
|
||||||
{RGID: "r5", Type: "EP", SecondaryTypes: []string{}},
|
{RGID: "r5", Type: "EP", SecondaryTypes: []string{}},
|
||||||
{RGID: "r6", Type: "Album", SecondaryTypes: []string{"EP"}},
|
{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 {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
opts musicbrainz.FilterOptions
|
opts musicbrainz.FilterOptions
|
||||||
expectedCounts int
|
expectedCounts int
|
||||||
expectedRGIDs []string
|
expectedRGIDs []string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "No filters",
|
name: "No filters",
|
||||||
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: false},
|
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: false, IgnoreLive: false, IgnoreRemix: false},
|
||||||
expectedCounts: 6,
|
expectedCounts: 10,
|
||||||
expectedRGIDs: []string{"r1", "r2", "r3", "r4", "r5", "r6"},
|
expectedRGIDs: []string{"r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Ignore singles only",
|
name: "Ignore singles only",
|
||||||
opts: musicbrainz.FilterOptions{IgnoreSingles: true, IgnoreCompilations: false},
|
opts: musicbrainz.FilterOptions{IgnoreSingles: true, IgnoreCompilations: false, IgnoreLive: false, IgnoreRemix: false},
|
||||||
expectedCounts: 2, // r3, r4
|
// Actually: r1(Single), r2(Album+Single), r5(EP), r6(Album+EP) should be filtered out
|
||||||
expectedRGIDs: []string{"r3", "r4"},
|
// 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",
|
name: "Ignore compilations only",
|
||||||
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: true},
|
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: true, IgnoreLive: false, IgnoreRemix: false},
|
||||||
expectedCounts: 4, // r1, r2, r5, r6
|
// r1, r2, r5, r6, r7, r8, r9, r10 (r3 and r4 filtered out)
|
||||||
expectedRGIDs: []string{"r1", "r2", "r5", "r6"},
|
expectedCounts: 8,
|
||||||
|
expectedRGIDs: []string{"r1", "r2", "r5", "r6", "r7", "r8", "r9", "r10"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Ignore both",
|
name: "Ignore live only",
|
||||||
opts: musicbrainz.FilterOptions{IgnoreSingles: true, IgnoreCompilations: true},
|
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,
|
expectedCounts: 0,
|
||||||
expectedRGIDs: []string{},
|
expectedRGIDs: []string{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,35 +108,63 @@ func TestApplyTypeTogglesToReleaseGroups(t *testing.T) {
|
|||||||
{ID: "g4", Type: "Album", SecondaryTypes: []string{"Compilation"}},
|
{ID: "g4", Type: "Album", SecondaryTypes: []string{"Compilation"}},
|
||||||
{ID: "g5", Type: "EP", SecondaryTypes: []string{}},
|
{ID: "g5", Type: "EP", SecondaryTypes: []string{}},
|
||||||
{ID: "g6", Type: "Album", SecondaryTypes: []string{"EP"}},
|
{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 {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
opts musicbrainz.FilterOptions
|
opts musicbrainz.FilterOptions
|
||||||
expectedCounts int
|
expectedCounts int
|
||||||
expectedIDs []string
|
expectedIDs []string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "No filters",
|
name: "No filters",
|
||||||
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: false},
|
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: false, IgnoreLive: false, IgnoreRemix: false},
|
||||||
expectedCounts: 6,
|
expectedCounts: 10,
|
||||||
expectedIDs: []string{"g1", "g2", "g3", "g4", "g5", "g6"},
|
expectedIDs: []string{"g1", "g2", "g3", "g4", "g5", "g6", "g7", "g8", "g9", "g10"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Ignore singles only",
|
name: "Ignore singles only",
|
||||||
opts: musicbrainz.FilterOptions{IgnoreSingles: true, IgnoreCompilations: false},
|
opts: musicbrainz.FilterOptions{IgnoreSingles: true, IgnoreCompilations: false, IgnoreLive: false, IgnoreRemix: false},
|
||||||
expectedCounts: 2, // g3, g4
|
expectedCounts: 6,
|
||||||
expectedIDs: []string{"g3", "g4"},
|
expectedIDs: []string{"g3", "g4", "g7", "g8", "g9", "g10"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Ignore compilations only",
|
name: "Ignore compilations only",
|
||||||
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: true},
|
opts: musicbrainz.FilterOptions{IgnoreSingles: false, IgnoreCompilations: true, IgnoreLive: false, IgnoreRemix: false},
|
||||||
expectedCounts: 4, // g1, g2, g5, g6
|
expectedCounts: 8, // g1, g2, g5, g6, g7, g8, g9, g10 (g3 and g4 filtered out)
|
||||||
expectedIDs: []string{"g1", "g2", "g5", "g6"},
|
expectedIDs: []string{"g1", "g2", "g5", "g6", "g7", "g8", "g9", "g10"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Ignore both",
|
name: "Ignore live only",
|
||||||
opts: musicbrainz.FilterOptions{IgnoreSingles: true, IgnoreCompilations: true},
|
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,
|
expectedCounts: 0,
|
||||||
expectedIDs: []string{},
|
expectedIDs: []string{},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user