feat(plugins): add similar songs retrieval functions and improve duration consistency (#4933)

* feat: add duration filtering for similar songs matching

Signed-off-by: Deluan <deluan@navidrome.org>

* test: refactor expectations for similar songs in provider matching tests

Signed-off-by: Deluan <deluan@navidrome.org>

* feat(plugins): add functions to retrieve similar songs by track, album, and artist

Signed-off-by: Deluan <deluan@navidrome.org>

* fix(plugins): support uint32 in ndpgen

Signed-off-by: Deluan <deluan@navidrome.org>

* fix(plugins): update duration field to use seconds as float instead of milliseconds as uint32

Signed-off-by: Deluan <deluan@navidrome.org>

* fix: add helper functions for Rust's skip_serializing_if with numeric types

Signed-off-by: Deluan <deluan@navidrome.org>

* feat(provider): enhance track matching logic to fallback to title match when duration-filtered tracks fail

---------

Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
Deluan Quintão
2026-01-26 18:28:41 -05:00
committed by GitHub
parent 4d4740b83b
commit fda35dd8ce
20 changed files with 1147 additions and 70 deletions
+60
View File
@@ -120,4 +120,64 @@ func (t *testMetadataAgent) GetAlbumImages(input metadata.AlbumRequest) (*metada
}, nil
}
func (t *testMetadataAgent) GetSimilarSongsByTrack(input metadata.SimilarSongsByTrackRequest) (*metadata.SimilarSongsResponse, error) {
if err := checkConfigError(); err != nil {
return nil, err
}
count := int(input.Count)
if count == 0 {
count = 5
}
songs := make([]metadata.SongRef, 0, count)
for i := range count {
songs = append(songs, metadata.SongRef{
ID: "similar-track-id-" + strconv.Itoa(i+1),
Name: "Similar to " + input.Name + " #" + strconv.Itoa(i+1),
MBID: "similar-mbid-" + strconv.Itoa(i+1),
Artist: input.Artist,
ArtistMBID: "artist-mbid-" + strconv.Itoa(i+1),
})
}
return &metadata.SimilarSongsResponse{Songs: songs}, nil
}
func (t *testMetadataAgent) GetSimilarSongsByAlbum(input metadata.SimilarSongsByAlbumRequest) (*metadata.SimilarSongsResponse, error) {
if err := checkConfigError(); err != nil {
return nil, err
}
count := int(input.Count)
if count == 0 {
count = 5
}
songs := make([]metadata.SongRef, 0, count)
for i := range count {
songs = append(songs, metadata.SongRef{
ID: "album-similar-id-" + strconv.Itoa(i+1),
Name: "Album Similar #" + strconv.Itoa(i+1),
Artist: input.Artist,
Album: input.Name,
})
}
return &metadata.SimilarSongsResponse{Songs: songs}, nil
}
func (t *testMetadataAgent) GetSimilarSongsByArtist(input metadata.SimilarSongsByArtistRequest) (*metadata.SimilarSongsResponse, error) {
if err := checkConfigError(); err != nil {
return nil, err
}
count := int(input.Count)
if count == 0 {
count = 5
}
songs := make([]metadata.SongRef, 0, count)
for i := range count {
songs = append(songs, metadata.SongRef{
ID: "artist-similar-id-" + strconv.Itoa(i+1),
Name: input.Name + " Style Song #" + strconv.Itoa(i+1),
Artist: input.Name + " Similar Artist",
})
}
return &metadata.SimilarSongsResponse{Songs: songs}, nil
}
func main() {}