From a054192e4522379886aff418d429930850c5bbfc Mon Sep 17 00:00:00 2001 From: benya Date: Fri, 3 Apr 2026 21:10:40 +0300 Subject: [PATCH] fix: align subsonic artist and album response shapes --- internal/subsonic/service.go | 53 +++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/internal/subsonic/service.go b/internal/subsonic/service.go index 6d08de2..e478507 100644 --- a/internal/subsonic/service.go +++ b/internal/subsonic/service.go @@ -1,7 +1,10 @@ package subsonic import ( + "sort" + "strings" "time" + "unicode" "github.com/benya/temporserv/internal/library" "github.com/benya/temporserv/internal/playlist" @@ -18,7 +21,7 @@ type Response struct { Type string `json:"type"` Server string `json:"serverVersion"` OpenAPI bool `json:"openSubsonic"` - Artists []ArtistRef `json:"artists,omitempty"` + Artists *Artists `json:"artists,omitempty"` Artist *ArtistFull `json:"artist,omitempty"` Album *AlbumFull `json:"album,omitempty"` AlbumList2 *AlbumList2 `json:"albumList2,omitempty"` @@ -42,6 +45,15 @@ type ArtistRef struct { Name string `json:"name"` } +type Artists struct { + Index []ArtistIndex `json:"index,omitempty"` +} + +type ArtistIndex struct { + Name string `json:"name"` + Artist []ArtistRef `json:"artist,omitempty"` +} + type SongRef struct { ID string `json:"id"` Title string `json:"title"` @@ -62,10 +74,11 @@ type ArtistFull struct { type AlbumRef struct { ID string `json:"id"` - Name string `json:"name"` + Title string `json:"title"` Artist string `json:"artist"` ArtistID string `json:"artistId"` Year int `json:"year,omitempty"` + Genre string `json:"genre,omitempty"` CoverArt string `json:"coverArt,omitempty"` } @@ -194,12 +207,34 @@ func PingResponse() Envelope { func ArtistsResponse(artists []library.Artist) Envelope { response := PingResponse() + groups := map[string][]ArtistRef{} for _, artist := range artists { - response.SubsonicResponse.Artists = append(response.SubsonicResponse.Artists, ArtistRef{ + initial := "#" + name := []rune(strings.TrimSpace(artist.Name)) + if len(name) > 0 { + first := unicode.ToUpper(name[0]) + if unicode.IsLetter(first) { + initial = string(first) + } + } + groups[initial] = append(groups[initial], ArtistRef{ ID: artist.ID, Name: artist.Name, }) } + keys := make([]string, 0, len(groups)) + for key := range groups { + keys = append(keys, key) + } + sort.Strings(keys) + payload := &Artists{} + for _, key := range keys { + payload.Index = append(payload.Index, ArtistIndex{ + Name: key, + Artist: groups[key], + }) + } + response.SubsonicResponse.Artists = payload return response } @@ -230,10 +265,11 @@ func ArtistResponse(artist library.ArtistDetail) Envelope { for _, album := range artist.Albums { item.Albums = append(item.Albums, AlbumRef{ ID: album.ID, - Name: album.Title, + Title: album.Title, Artist: album.ArtistName, ArtistID: album.ArtistID, Year: album.Year, + Genre: album.Genre, CoverArt: album.CoverArtID, }) } @@ -253,10 +289,11 @@ func Search3Response(results library.SearchResults) Envelope { for _, album := range results.Albums { payload.Album = append(payload.Album, AlbumRef{ ID: album.ID, - Name: album.Title, + Title: album.Title, Artist: album.ArtistName, ArtistID: album.ArtistID, Year: album.Year, + Genre: album.Genre, CoverArt: album.CoverArtID, }) } @@ -287,10 +324,11 @@ func Starred2Response(results library.StarredResults) Envelope { for _, album := range results.Albums { payload.Album = append(payload.Album, AlbumRef{ ID: album.ID, - Name: album.Title, + Title: album.Title, Artist: album.ArtistName, ArtistID: album.ArtistID, Year: album.Year, + Genre: album.Genre, CoverArt: album.CoverArtID, }) } @@ -384,10 +422,11 @@ func AlbumList2Response(albums []library.Album) Envelope { for _, album := range albums { payload.Album = append(payload.Album, AlbumRef{ ID: album.ID, - Name: album.Title, + Title: album.Title, Artist: album.ArtistName, ArtistID: album.ArtistID, Year: album.Year, + Genre: album.Genre, CoverArt: album.CoverArtID, }) }