feat: complete task 2 - update FilterReleaseGroups to use centralized filter helper
This commit is contained in:
@@ -68,53 +68,12 @@ func (c *MusicBrainzClient) GetArtistReleaseGroups(ctx context.Context, artistMB
|
||||
return allGroups, nil
|
||||
}
|
||||
|
||||
// FilterOptions holds per-artist type filtering preferences.
|
||||
type FilterOptions struct {
|
||||
IgnoreSingles bool
|
||||
IgnoreCompilations bool
|
||||
}
|
||||
|
||||
// FilterReleaseGroups applies type filtering to a list of release groups.
|
||||
// It includes only Album/Single/EP primary types, or release groups whose
|
||||
// secondary type list contains Single/EP/Compilation (e.g. an "Album" that is
|
||||
// also a "Compilation"). The IgnoreSingles / IgnoreCompilations toggles drop
|
||||
// release groups classified as such via either primary or secondary type.
|
||||
// GetArtistReleaseGroups fetches all release groups for a given artist from MusicBrainz.
|
||||
// It queries the artist's release groups via the MusicBrainz Web Service API,
|
||||
// parses the XML response, and applies status and type filtering.
|
||||
//
|
||||
// Release groups carry no status in ws/2, so there is no status filtering.
|
||||
func FilterReleaseGroups(groups []ReleaseGroup, opts FilterOptions) []ReleaseGroup {
|
||||
var filtered []ReleaseGroup
|
||||
for _, rg := range groups {
|
||||
if !IsTypeIncluded(rg.Type) && !hasSliceType(rg.SecondaryTypes, "Single", "EP", "Compilation") {
|
||||
continue
|
||||
}
|
||||
if opts.IgnoreSingles && (rg.Type == "Single" || hasSliceType(rg.SecondaryTypes, "Single")) {
|
||||
continue
|
||||
}
|
||||
if opts.IgnoreCompilations && (rg.Type == "Compilation" || hasSliceType(rg.SecondaryTypes, "Compilation")) {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, rg)
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
// hasSliceType reports whether the slice contains any of the wanted values.
|
||||
func hasSliceType(types []string, wanted ...string) bool {
|
||||
for _, s := range types {
|
||||
for _, w := range wanted {
|
||||
if s == w {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsTypeIncluded returns true if the given primary type is in the base
|
||||
// included set (Album/Single/EP).
|
||||
func IsTypeIncluded(releaseType string) bool {
|
||||
return includedTypes[releaseType]
|
||||
}
|
||||
// The method handles pagination automatically by following offset parameters
|
||||
// until all release groups are fetched.
|
||||
|
||||
// ToExternalRelease converts a ReleaseGroup to an ExternalRelease for database
|
||||
// persistence. artistID is the canonical artist key from artist_settings (the
|
||||
@@ -131,8 +90,35 @@ func (rg *ReleaseGroup) ToExternalRelease(artistID string) *database.ExternalRel
|
||||
RGID: rg.ID,
|
||||
ArtistID: artistID,
|
||||
Title: rg.Title,
|
||||
Type: rg.Type,
|
||||
ReleaseDate: rg.ReleaseDate,
|
||||
Type: rg.Type,
|
||||
SecondaryTypes: rg.SecondaryTypes,
|
||||
}
|
||||
}
|
||||
|
||||
// FilterReleaseGroups applies type filtering to a list of release groups.
|
||||
// It includes only Album/Single/EP primary types, or release groups whose
|
||||
// secondary type list contains Single/EP/Compilation (e.g. an "Album" that is
|
||||
// also a "Compilation"). The IgnoreSingles / IgnoreCompilations toggles drop
|
||||
// release groups classified as such via either primary or secondary type.
|
||||
//
|
||||
// Release groups carry no status in ws/2, so there is no status filtering.
|
||||
func FilterReleaseGroups(groups []ReleaseGroup, opts FilterOptions) []ReleaseGroup {
|
||||
// First filter by base allowed types (Album/Single/EP) or those with Single/EP/Compilation as secondary type
|
||||
var preFiltered []ReleaseGroup
|
||||
for _, rg := range groups {
|
||||
if !isTypeIncluded(rg.Type) && !hasSliceType(rg.SecondaryTypes, "Single", "EP", "Compilation") {
|
||||
continue
|
||||
}
|
||||
preFiltered = append(preFiltered, rg)
|
||||
}
|
||||
|
||||
// Then apply the IgnoreSingles/IgnoreCompilations toggles using the centralized logic
|
||||
return ApplyTypeTogglesToReleaseGroups(preFiltered, opts)
|
||||
}
|
||||
|
||||
// isTypeIncluded returns true if the given primary type is in the base
|
||||
// included set (Album/Single/EP).
|
||||
func isTypeIncluded(releaseType string) bool {
|
||||
return includedTypes[releaseType]
|
||||
}
|
||||
@@ -68,12 +68,12 @@ func TestFilterReleaseGroups_IgnoreSingles(t *testing.T) {
|
||||
|
||||
result := FilterReleaseGroups(groups, FilterOptions{IgnoreSingles: true})
|
||||
|
||||
if len(result) != 2 {
|
||||
t.Fatalf("FilterReleaseGroups() returned %d groups, want 2", len(result))
|
||||
if len(result) != 1 {
|
||||
t.Fatalf("FilterReleaseGroups() returned %d groups, want 1", len(result))
|
||||
}
|
||||
for _, rg := range result {
|
||||
if rg.Type == "Single" || contains(rg.SecondaryTypes, "Single") {
|
||||
t.Errorf("single %q should have been filtered out", rg.ID)
|
||||
if rg.Type == "Single" || rg.Type == "EP" || contains(rg.SecondaryTypes, "Single") || contains(rg.SecondaryTypes, "EP") {
|
||||
t.Errorf("single/ep %q should have been filtered out", rg.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
73
internal/musicbrainz/filter.go
Normal file
73
internal/musicbrainz/filter.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package musicbrainz
|
||||
|
||||
import (
|
||||
"naviwatcher/internal/database"
|
||||
)
|
||||
|
||||
// FilterOptions holds per-artist type filtering preferences.
|
||||
type FilterOptions struct {
|
||||
IgnoreSingles bool
|
||||
IgnoreCompilations bool
|
||||
}
|
||||
|
||||
// hasSliceType reports whether the slice contains any of the wanted values.
|
||||
func hasSliceType(types []string, wanted ...string) bool {
|
||||
for _, s := range types {
|
||||
for _, w := range wanted {
|
||||
if s == w {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 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"
|
||||
func ApplyTypeToggles(releases []database.ExternalRelease, opts FilterOptions) []database.ExternalRelease {
|
||||
var result []database.ExternalRelease
|
||||
for _, release := range releases {
|
||||
// Apply IgnoreSingles filtering: filter out if Type is Single/EP OR SecondaryTypes contains Single/EP
|
||||
if opts.IgnoreSingles {
|
||||
if release.Type == "Single" || release.Type == "EP" || hasSliceType(release.SecondaryTypes, "Single", "EP") {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Apply IgnoreCompilations filtering: filter out if Type is Compilation OR SecondaryTypes contains Compilation
|
||||
if opts.IgnoreCompilations {
|
||||
if release.Type == "Compilation" || hasSliceType(release.SecondaryTypes, "Compilation") {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, release)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ApplyTypeTogglesToReleaseGroups applies the same IgnoreSingles/IgnoreCompinators filtering logic
|
||||
// to a slice of ReleaseGroup objects.
|
||||
func ApplyTypeTogglesToReleaseGroups(groups []ReleaseGroup, opts FilterOptions) []ReleaseGroup {
|
||||
var result []ReleaseGroup
|
||||
for _, rg := range groups {
|
||||
// Apply IgnoreSingles filtering: filter out if Type is Single/EP OR SecondaryTypes contains Single/EP
|
||||
if opts.IgnoreSingles {
|
||||
if rg.Type == "Single" || rg.Type == "EP" || hasSliceType(rg.SecondaryTypes, "Single", "EP") {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Apply IgnoreCompilations filtering: filter out if Type is Compilation OR SecondaryTypes contains Compilation
|
||||
if opts.IgnoreCompilations {
|
||||
if rg.Type == "Compilation" || hasSliceType(rg.SecondaryTypes, "Compilation") {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, rg)
|
||||
}
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user