feat: filter artist albums by type, default to album|ep|single

This commit is contained in:
Alexander
2026-05-07 17:22:59 +02:00
parent 80051396d8
commit 35ac167952
7 changed files with 79 additions and 19 deletions
+9
View File
@@ -137,12 +137,17 @@ func (c *client) lookup(ctx context.Context, entity, id string, inc []string) ([
}
func (c *client) browse(ctx context.Context, entity, linkedEntity, linkedID string, limit, offset int, inc []string) ([]byte, error) {
return c.browseWithTypes(ctx, entity, linkedEntity, linkedID, limit, offset, inc, nil)
}
func (c *client) browseWithTypes(ctx context.Context, entity, linkedEntity, linkedID string, limit, offset int, inc []string, types []string) ([]byte, error) {
zerolog.Ctx(ctx).Debug().
Str("entity", entity).
Str("linked_entity", linkedEntity).
Str("linked_id", linkedID).
Int("limit", limit).
Int("offset", offset).
Strs("types", types).
Msg("provider browse")
params := url.Values{}
@@ -154,6 +159,10 @@ func (c *client) browse(ctx context.Context, entity, linkedEntity, linkedID stri
params.Set("inc", joined)
}
if typeStr := strings.Join(types, "|"); typeStr != "" {
params.Set("type", typeStr)
}
return c.get(ctx, entity, params)
}
+21 -3
View File
@@ -91,7 +91,7 @@ func (p *Provider) GetAlbum(ctx context.Context, id string) (*domain.Album, erro
return mapAlbum(mb, release), nil
}
func (p *Provider) SearchAlbums(ctx context.Context, query string, artist string, limit, offset int) (*domain.SearchResult[domain.Album], error) {
func (p *Provider) SearchAlbums(ctx context.Context, query string, artist string, limit, offset int, albumTypes []string) (*domain.SearchResult[domain.Album], error) {
if limit <= 0 || limit > 100 {
limit = 25
}
@@ -105,6 +105,10 @@ func (p *Provider) SearchAlbums(ctx context.Context, query string, artist string
luceneQuery = fmt.Sprintf("releasegroup:%s", escapeQuery(query))
}
if typeFilter := buildTypeFilter(albumTypes); typeFilter != "" {
luceneQuery += " AND " + typeFilter
}
data, err := p.client.search(ctx, "release-group", luceneQuery, limit, offset)
if err != nil {
return nil, fmt.Errorf("search albums: %w", err)
@@ -134,12 +138,12 @@ func (p *Provider) SearchAlbums(ctx context.Context, query string, artist string
return result, nil
}
func (p *Provider) GetArtistAlbums(ctx context.Context, artistID string, limit, offset int) (*domain.SearchResult[domain.Album], error) {
func (p *Provider) GetArtistAlbums(ctx context.Context, artistID string, limit, offset int, albumTypes []string) (*domain.SearchResult[domain.Album], error) {
if limit <= 0 || limit > 100 {
limit = 25
}
data, err := p.client.browse(ctx, "release-group", "artist", artistID, limit, offset, []string{"artist-credits"})
data, err := p.client.browseWithTypes(ctx, "release-group", "artist", artistID, limit, offset, []string{"artist-credits"}, albumTypes)
if err != nil {
return nil, fmt.Errorf("browse release-groups: %w", err)
}
@@ -311,6 +315,20 @@ func selectCanonicalRelease(releases []*mbRelease) *mbRelease {
return best
}
func buildTypeFilter(types []string) string {
if len(types) == 0 {
return ""
}
if len(types) == 1 {
return fmt.Sprintf("primarytype:%s", types[0])
}
escaped := make([]string, len(types))
for i, t := range types {
escaped[i] = fmt.Sprintf("primarytype:%s", t)
}
return "(" + strings.Join(escaped, " OR ") + ")"
}
func escapeQuery(s string) string {
special := []string{`+`, `-`, `&`, `|`, `!`, `(`, `)`, `{`, `}`, `[`, `]`, `^`, `"`, `~`, `*`, `?`, `:`, `/`, `\`}
result := s
+2 -2
View File
@@ -13,8 +13,8 @@ type Provider interface {
SearchArtists(ctx context.Context, query string, limit, offset int) (*domain.SearchResult[domain.Artist], error)
GetAlbum(ctx context.Context, id string) (*domain.Album, error)
SearchAlbums(ctx context.Context, query string, artist string, limit, offset int) (*domain.SearchResult[domain.Album], error)
GetArtistAlbums(ctx context.Context, artistID string, limit, offset int) (*domain.SearchResult[domain.Album], error)
SearchAlbums(ctx context.Context, query string, artist string, limit, offset int, albumTypes []string) (*domain.SearchResult[domain.Album], error)
GetArtistAlbums(ctx context.Context, artistID string, limit, offset int, albumTypes []string) (*domain.SearchResult[domain.Album], error)
GetTrack(ctx context.Context, id string) (*domain.Track, error)
GetAlbumTracks(ctx context.Context, albumID string) ([]domain.Track, error)
+15 -4
View File
@@ -114,9 +114,10 @@ func (s *MetadataServer) SearchAlbums(ctx context.Context, req *metadatav1.Searc
limit = 25
}
log.Debug().Str("query", req.Query).Str("artist", req.Artist).Int("limit", limit).Int("offset", int(req.Offset)).Msg("searching albums")
albumTypes := defaultAlbumTypes(req.AlbumTypes)
log.Debug().Str("query", req.Query).Str("artist", req.Artist).Int("limit", limit).Int("offset", int(req.Offset)).Strs("album_types", albumTypes).Msg("searching albums")
result, err := svc.SearchAlbums(ctx, req.Query, req.Artist, limit, int(req.Offset))
result, err := svc.SearchAlbums(ctx, req.Query, req.Artist, limit, int(req.Offset), albumTypes)
if err != nil {
return nil, toGRPCError(ctx, err)
}
@@ -176,9 +177,10 @@ func (s *MetadataServer) GetArtistAlbums(ctx context.Context, req *metadatav1.Ge
limit = 25
}
log.Debug().Str("artist_id", req.ArtistId).Int("limit", limit).Int("offset", int(req.Offset)).Msg("getting artist albums")
albumTypes := defaultAlbumTypes(req.AlbumTypes)
log.Debug().Str("artist_id", req.ArtistId).Int("limit", limit).Int("offset", int(req.Offset)).Strs("album_types", albumTypes).Msg("getting artist albums")
result, err := svc.GetArtistAlbums(ctx, req.ArtistId, limit, int(req.Offset))
result, err := svc.GetArtistAlbums(ctx, req.ArtistId, limit, int(req.Offset), albumTypes)
if err != nil {
return nil, toGRPCError(ctx, err)
}
@@ -268,6 +270,15 @@ func (s *MetadataServer) SyncArtist(ctx context.Context, req *metadatav1.SyncArt
return nil, status.Error(codes.Unimplemented, "sync not yet implemented")
}
var defaultTypes = []string{"album", "ep", "single"}
func defaultAlbumTypes(types []string) []string {
if len(types) > 0 {
return types
}
return defaultTypes
}
func toGRPCError(ctx context.Context, err error) error {
if err == nil {
return nil
+6 -6
View File
@@ -80,9 +80,9 @@ func (s *MetadataService) SearchArtists(ctx context.Context, query string, limit
return s.provider.SearchArtists(ctx, query, limit, offset)
}
func (s *MetadataService) SearchAlbums(ctx context.Context, query string, artist string, limit, offset int) (*domain.SearchResult[domain.Album], error) {
zerolog.Ctx(ctx).Debug().Str("query", query).Str("artist", artist).Str("provider", s.provider.Name()).Msg("searching albums via provider")
return s.provider.SearchAlbums(ctx, query, artist, limit, offset)
func (s *MetadataService) SearchAlbums(ctx context.Context, query string, artist string, limit, offset int, albumTypes []string) (*domain.SearchResult[domain.Album], error) {
zerolog.Ctx(ctx).Debug().Str("query", query).Str("artist", artist).Strs("album_types", albumTypes).Str("provider", s.provider.Name()).Msg("searching albums via provider")
return s.provider.SearchAlbums(ctx, query, artist, limit, offset, albumTypes)
}
func (s *MetadataService) GetAlbum(ctx context.Context, id string) (*domain.Album, error) {
@@ -117,7 +117,7 @@ func (s *MetadataService) GetAlbum(ctx context.Context, id string) (*domain.Albu
return album, nil
}
func (s *MetadataService) GetArtistAlbums(ctx context.Context, artistID string, limit, offset int) (*domain.SearchResult[domain.Album], error) {
func (s *MetadataService) GetArtistAlbums(ctx context.Context, artistID string, limit, offset int, albumTypes []string) (*domain.SearchResult[domain.Album], error) {
log := zerolog.Ctx(ctx)
result, err := s.albums.GetByArtistID(ctx, artistID, limit, offset)
@@ -128,8 +128,8 @@ func (s *MetadataService) GetArtistAlbums(ctx context.Context, artistID string,
}
metrics.CacheMisses.WithLabelValues("artist_albums").Inc()
log.Debug().Str("artist_id", artistID).Str("provider", s.provider.Name()).Msg("artist albums cache miss, querying provider")
return s.provider.GetArtistAlbums(ctx, artistID, limit, offset)
log.Debug().Str("artist_id", artistID).Strs("album_types", albumTypes).Str("provider", s.provider.Name()).Msg("artist albums cache miss, querying provider")
return s.provider.GetArtistAlbums(ctx, artistID, limit, offset, albumTypes)
}
func (s *MetadataService) GetTrack(ctx context.Context, id string) (*domain.Track, error) {