Skip to content

Commit f22b07f

Browse files
authored
Merge pull request #9 from ShimmerGlass/count-and-mix
Enanchement: use request track count, better mix artist similar songs
2 parents c279bc1 + 5e90b07 commit f22b07f

File tree

2 files changed

+54
-31
lines changed

2 files changed

+54
-31
lines changed

main.go

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"fmt"
66
"net/url"
7+
"slices"
78
"strconv"
89

910
"github.com/navidrome/navidrome/plugins/pdk/go/metadata"
@@ -13,15 +14,13 @@ import (
1314
// Configuration keys (must match manifest.json)
1415
const (
1516
configAPIUrl = "apiUrl"
16-
configTrackCount = "trackCount"
1717
configEliminateDuplicates = "eliminateDuplicates"
1818
configRadiusSimilarity = "radiusSimilarity"
1919
)
2020

2121
// Default values
2222
const (
2323
defaultAPIUrl = "http://192.168.3.203:8000"
24-
defaultTrackCount = 200
2524
defaultArtistSimilarCount = 10
2625
defaultEliminateDuplicates = true
2726
defaultRadiusSimilarity = true
@@ -81,17 +80,16 @@ func (p *audioMusePlugin) GetSimilarSongsByTrack(input metadata.SimilarSongsByTr
8180

8281
// Read configuration
8382
apiBaseURL := getConfigString(configAPIUrl, defaultAPIUrl)
84-
trackCount := getConfigInt(configTrackCount, defaultTrackCount)
8583
eliminateDuplicates := getConfigBool(configEliminateDuplicates, defaultEliminateDuplicates)
8684
radiusSimilarity := getConfigBool(configRadiusSimilarity, defaultRadiusSimilarity)
8785

8886
pdk.Log(pdk.LogDebug, fmt.Sprintf("[AudioMuse] Config - API URL: %s, TrackCount: %d, EliminateDuplicates: %v, RadiusSimilarity: %v",
89-
apiBaseURL, trackCount, eliminateDuplicates, radiusSimilarity))
87+
apiBaseURL, input.Count, eliminateDuplicates, radiusSimilarity))
9088

9189
// Build the API URL with query parameters
9290
params := url.Values{}
9391
params.Set("item_id", input.ID)
94-
params.Set("n", strconv.Itoa(trackCount))
92+
params.Set("n", strconv.Itoa(int(input.Count)))
9593
params.Set("eliminate_duplicates", strconv.FormatBool(eliminateDuplicates))
9694
params.Set("radius_similarity", strconv.FormatBool(radiusSimilarity))
9795

@@ -151,37 +149,72 @@ func (p *audioMusePlugin) GetSimilarSongsByArtist(input metadata.SimilarSongsByA
151149
return nil, err
152150
}
153151

154-
// Collect unique song IDs preserving order
155-
songIDs := make([]string, 0)
156152
seen := make(map[string]bool)
157153

154+
// songSlices contains artist songs in alternating order: [baseArtist, relatedArtist1, baseArtist, relatedArtist2, ...]
155+
songSlices := [][]metadata.SongRef{}
156+
158157
for _, a := range artists {
158+
var artist1Songs, artist2Songs []metadata.SongRef
159+
159160
for _, cm := range a.ComponentMatches {
160161
for _, s := range cm.Artist1RepresentativeSongs {
162+
161163
if s.ItemID == "" {
162164
continue
163165
}
164-
if !seen[s.ItemID] {
165-
seen[s.ItemID] = true
166-
songIDs = append(songIDs, s.ItemID)
166+
if seen[s.ItemID] {
167+
continue
167168
}
169+
170+
seen[s.ItemID] = true
171+
artist1Songs = append(artist1Songs, metadata.SongRef{ID: s.ItemID, Name: s.Title})
168172
}
173+
169174
for _, s := range cm.Artist2RepresentativeSongs {
170175
if s.ItemID == "" {
171176
continue
172177
}
173-
if !seen[s.ItemID] {
174-
seen[s.ItemID] = true
175-
songIDs = append(songIDs, s.ItemID)
178+
179+
if seen[s.ItemID] {
180+
continue
176181
}
182+
183+
seen[s.ItemID] = true
184+
artist2Songs = append(artist2Songs, metadata.SongRef{ID: s.ItemID, Name: s.Title})
177185
}
178186
}
187+
188+
if len(artist1Songs) > 0 {
189+
songSlices = append(songSlices, artist1Songs)
190+
}
191+
if len(artist2Songs) > 0 {
192+
songSlices = append(songSlices, artist2Songs)
193+
}
179194
}
180195

181-
// Build SongRef list (names not always available)
182-
songs := make([]metadata.SongRef, 0, len(songIDs))
183-
for _, id := range songIDs {
184-
songs = append(songs, metadata.SongRef{ID: id})
196+
songs := make([]metadata.SongRef, 0, input.Count)
197+
198+
// get songs from our slices until we have enough or we ran out
199+
artistID := 0
200+
for len(songs) < int(input.Count) && len(songSlices) > 0 {
201+
song := songSlices[artistID][0] // take a song
202+
songs = append(songs, song)
203+
204+
songSlices[artistID] = songSlices[artistID][1:] // remove it from the pool
205+
206+
if len(songSlices[artistID]) == 0 {
207+
// this slice has no more songs, remove it
208+
songSlices = slices.Delete(songSlices, artistID, artistID+1)
209+
if len(songSlices) == 0 {
210+
break
211+
}
212+
} else {
213+
// else, go to the next slice
214+
artistID++
215+
}
216+
217+
artistID = artistID % len(songSlices) // loop around if needed
185218
}
186219

187220
pdk.Log(pdk.LogInfo, fmt.Sprintf("[AudioMuse] Returning %d artist-related songs to Navidrome", len(songs)))

manifest.json

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,6 @@
1515
"description": "Base URL for the AudioMuse-AI server (e.g., http://192.168.3.203:8000).",
1616
"default": "http://192.168.3.203:8000"
1717
},
18-
"trackCount": {
19-
"type": "integer",
20-
"title": "Number of Similar Tracks",
21-
"description": "Maximum number of similar tracks to return. Default: 200",
22-
"default": 200,
23-
"minimum": 10,
24-
"maximum": 500
25-
},
2618
"artistSimilarCount": {
2719
"type": "integer",
2820
"title": "Number of Similar Artists",
@@ -62,10 +54,6 @@
6254
"type": "Group",
6355
"label": "Song Instant Mix",
6456
"elements": [
65-
{
66-
"type": "Control",
67-
"scope": "#/properties/trackCount"
68-
},
6957
{
7058
"type": "HorizontalLayout",
7159
"elements": [
@@ -100,7 +88,9 @@
10088
},
10189
"http": {
10290
"reason": "To call AudioMuse-AI API for similar tracks",
103-
"requiredHosts": ["*"]
91+
"requiredHosts": [
92+
"*"
93+
]
10494
}
10595
}
106-
}
96+
}

0 commit comments

Comments
 (0)