feat: add configurable artist separator

This commit is contained in:
2026-07-11 01:21:40 +02:00
parent 537959b6ec
commit d2fa098d69
8 changed files with 82 additions and 49 deletions
+19 -12
View File
@@ -122,7 +122,7 @@ func (c *Client) GetMetadata(ctx context.Context, item, mediaType string) (map[s
if err != nil {
return nil, err
}
return collectionMetadata(label, tracks), nil
return c.collectionMetadata(label, tracks), nil
default:
return nil, fmt.Errorf("unsupported beatport media type %q", mediaType)
}
@@ -213,7 +213,7 @@ func (c *Client) getPlaylistMetadata(ctx context.Context, id string) (map[string
continue
}
if track, ok := m["track"].(map[string]any); ok {
tracks = append(tracks, normalizeTrackListItem(track))
tracks = append(tracks, c.normalizeTrackListItem(track))
}
}
return playlistMetadata(playlist, tracks), nil
@@ -231,7 +231,7 @@ func (c *Client) getChartMetadata(ctx context.Context, id string) (map[string]an
normalized := make([]any, 0, len(tracks))
for _, raw := range tracks {
if track, ok := raw.(map[string]any); ok {
normalized = append(normalized, normalizeTrackListItem(track))
normalized = append(normalized, c.normalizeTrackListItem(track))
}
}
return playlistMetadata(chart, normalized), nil
@@ -507,7 +507,7 @@ func (c *Client) normalizeRelease(raw map[string]any, tracks []any) map[string]a
func (c *Client) normalizeTrack(raw map[string]any) map[string]any {
release := mapAny(raw["release"])
artistName := joinArtists(raw["artists"])
artistName := c.joinArtists(raw["artists"])
artistID := firstArtistID(raw["artists"])
albumArtist := c.releaseArtistName(release["artists"])
if albumArtist == "" {
@@ -543,25 +543,25 @@ func (c *Client) normalizeTrack(raw map[string]any) map[string]any {
return track
}
func normalizeTrackListItem(raw map[string]any) map[string]any {
func (c *Client) normalizeTrackListItem(raw map[string]any) map[string]any {
return map[string]any{
"id": jsonutil.StringFromAny(raw["id"]),
"title": jsonutil.StringFromAny(raw["name"]),
"version": jsonutil.StringFromAny(raw["mix_name"]),
"artist": map[string]any{"name": joinArtists(raw["artists"])},
"artist": map[string]any{"name": c.joinArtists(raw["artists"])},
"album": map[string]any{"id": jsonutil.NestedString(raw, "release", "id"), "title": jsonutil.NestedString(raw, "release", "name")},
"track_number": jsonutil.IntFromAny(raw["number"]),
}
}
func collectionMetadata(raw map[string]any, tracks []any) map[string]any {
func (c *Client) collectionMetadata(raw map[string]any, tracks []any) map[string]any {
items := make([]any, 0, len(tracks))
for _, entry := range tracks {
track, ok := entry.(map[string]any)
if !ok {
continue
}
items = append(items, normalizeTrackListItem(track))
items = append(items, c.normalizeTrackListItem(track))
}
return map[string]any{
"id": jsonutil.StringFromAny(raw["id"]),
@@ -620,7 +620,7 @@ func (c *Client) normalizeSearchItems(mediaType string, items []any) []any {
}
switch mediaType {
case "track":
out = append(out, normalizeTrackListItem(m))
out = append(out, c.normalizeTrackListItem(m))
case "album":
out = append(out, map[string]any{"id": jsonutil.StringFromAny(m["id"]), "title": jsonutil.StringFromAny(m["name"]), "artist": map[string]any{"name": c.releaseArtistName(m["artists"])}, "tracks_count": jsonutil.IntFromAny(m["track_count"]), "release_date_original": jsonutil.StringFromAny(m["new_release_date"])})
case "label":
@@ -653,7 +653,7 @@ func audioProfile(quality, streamQuality string) (provider.AudioProfile, string)
}
}
func joinArtists(v any) string {
func (c *Client) joinArtists(v any) string {
items := sliceAny(v)
names := make([]string, 0, len(items))
for _, raw := range items {
@@ -665,7 +665,7 @@ func joinArtists(v any) string {
names = append(names, name)
}
}
return strings.Join(names, ", ")
return strings.Join(names, artistSeparator(c.cfg.Session.Metadata.ArtistSeparator))
}
func (c *Client) releaseArtistName(v any) string {
@@ -674,7 +674,14 @@ func (c *Client) releaseArtistName(v any) string {
if threshold >= 0 && len(items) > threshold {
return "Various Artists"
}
return joinArtists(v)
return c.joinArtists(v)
}
func artistSeparator(separator string) string {
if separator == "" {
return "; "
}
return separator
}
func firstArtistID(v any) string {
+14 -1
View File
@@ -164,11 +164,24 @@ func TestReleaseArtistCollapseCanBeDisabled(t *testing.T) {
map[string]any{"name": "C"},
map[string]any{"name": "D"},
})
if got != "A, B, C, D" {
if got != "A; B; C; D" {
t.Fatalf("releaseArtistName() = %q", got)
}
}
func TestArtistSeparatorCanBeConfigured(t *testing.T) {
cfg := &config.Config{Session: config.DefaultConfigData(), File: config.DefaultConfigData()}
cfg.Session.Metadata.ArtistSeparator = " / "
c := New(cfg)
got := c.joinArtists([]any{
map[string]any{"name": "A"},
map[string]any{"name": "B"},
})
if got != "A / B" {
t.Fatalf("joinArtists() = %q", got)
}
}
func TestArtistMetadataUsesReleases(t *testing.T) {
c, closeServer := newTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {