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
+69 -1
View File
@@ -40,6 +40,18 @@ type MetadataAgent interface {
// GetAlbumImages retrieves images for an album.
//nd:export name=nd_get_album_images
GetAlbumImages(AlbumRequest) (*AlbumImagesResponse, error)
// GetSimilarSongsByTrack retrieves songs similar to a specific track.
//nd:export name=nd_get_similar_songs_by_track
GetSimilarSongsByTrack(SimilarSongsByTrackRequest) (*SimilarSongsResponse, error)
// GetSimilarSongsByAlbum retrieves songs similar to tracks on an album.
//nd:export name=nd_get_similar_songs_by_album
GetSimilarSongsByAlbum(SimilarSongsByAlbumRequest) (*SimilarSongsResponse, error)
// GetSimilarSongsByArtist retrieves songs similar to an artist's catalog.
//nd:export name=nd_get_similar_songs_by_artist
GetSimilarSongsByArtist(SimilarSongsByArtistRequest) (*SimilarSongsResponse, error)
}
// ArtistMBIDRequest is the request for GetArtistMBID.
@@ -122,7 +134,7 @@ type TopSongsRequest struct {
Count int32 `json:"count"`
}
// SongRef is a reference to a song with name and optional MBID.
// SongRef is a reference to a song with metadata for matching.
type SongRef struct {
// ID is the internal Navidrome mediafile ID (if known).
ID string `json:"id,omitempty"`
@@ -130,6 +142,16 @@ type SongRef struct {
Name string `json:"name"`
// MBID is the MusicBrainz ID for the song.
MBID string `json:"mbid,omitempty"`
// Artist is the artist name.
Artist string `json:"artist,omitempty"`
// ArtistMBID is the MusicBrainz artist ID.
ArtistMBID string `json:"artistMbid,omitempty"`
// Album is the album name.
Album string `json:"album,omitempty"`
// AlbumMBID is the MusicBrainz release ID.
AlbumMBID string `json:"albumMbid,omitempty"`
// Duration is the song duration in seconds.
Duration float32 `json:"duration,omitempty"`
}
// TopSongsResponse is the response for GetArtistTopSongs.
@@ -165,3 +187,49 @@ type AlbumImagesResponse struct {
// Images is the list of album images.
Images []ImageInfo `json:"images"`
}
// SimilarSongsByTrackRequest is the request for GetSimilarSongsByTrack.
type SimilarSongsByTrackRequest struct {
// ID is the internal Navidrome mediafile ID.
ID string `json:"id"`
// Name is the track title.
Name string `json:"name"`
// Artist is the artist name.
Artist string `json:"artist"`
// MBID is the MusicBrainz recording ID (if known).
MBID string `json:"mbid,omitempty"`
// Count is the maximum number of similar songs to return.
Count int32 `json:"count"`
}
// SimilarSongsByAlbumRequest is the request for GetSimilarSongsByAlbum.
type SimilarSongsByAlbumRequest struct {
// ID is the internal Navidrome album ID.
ID string `json:"id"`
// Name is the album name.
Name string `json:"name"`
// Artist is the album artist name.
Artist string `json:"artist"`
// MBID is the MusicBrainz release ID (if known).
MBID string `json:"mbid,omitempty"`
// Count is the maximum number of similar songs to return.
Count int32 `json:"count"`
}
// SimilarSongsByArtistRequest is the request for GetSimilarSongsByArtist.
type SimilarSongsByArtistRequest struct {
// ID is the internal Navidrome artist ID.
ID string `json:"id"`
// Name is the artist name.
Name string `json:"name"`
// MBID is the MusicBrainz artist ID (if known).
MBID string `json:"mbid,omitempty"`
// Count is the maximum number of similar songs to return.
Count int32 `json:"count"`
}
// SimilarSongsResponse is the response for GetSimilarSongsBy* functions.
type SimilarSongsResponse struct {
// Songs is the list of similar songs.
Songs []SongRef `json:"songs"`
}
+119 -1
View File
@@ -64,6 +64,30 @@ exports:
output:
$ref: '#/components/schemas/AlbumImagesResponse'
contentType: application/json
nd_get_similar_songs_by_track:
description: GetSimilarSongsByTrack retrieves songs similar to a specific track.
input:
$ref: '#/components/schemas/SimilarSongsByTrackRequest'
contentType: application/json
output:
$ref: '#/components/schemas/SimilarSongsResponse'
contentType: application/json
nd_get_similar_songs_by_album:
description: GetSimilarSongsByAlbum retrieves songs similar to tracks on an album.
input:
$ref: '#/components/schemas/SimilarSongsByAlbumRequest'
contentType: application/json
output:
$ref: '#/components/schemas/SimilarSongsResponse'
contentType: application/json
nd_get_similar_songs_by_artist:
description: GetSimilarSongsByArtist retrieves songs similar to an artist's catalog.
input:
$ref: '#/components/schemas/SimilarSongsByArtistRequest'
contentType: application/json
output:
$ref: '#/components/schemas/SimilarSongsResponse'
contentType: application/json
components:
schemas:
AlbumImagesResponse:
@@ -229,8 +253,86 @@ components:
$ref: '#/components/schemas/ArtistRef'
required:
- artists
SimilarSongsByAlbumRequest:
description: SimilarSongsByAlbumRequest is the request for GetSimilarSongsByAlbum.
properties:
id:
type: string
description: ID is the internal Navidrome album ID.
name:
type: string
description: Name is the album name.
artist:
type: string
description: Artist is the album artist name.
mbid:
type: string
description: MBID is the MusicBrainz release ID (if known).
count:
type: integer
format: int32
description: Count is the maximum number of similar songs to return.
required:
- id
- name
- artist
- count
SimilarSongsByArtistRequest:
description: SimilarSongsByArtistRequest is the request for GetSimilarSongsByArtist.
properties:
id:
type: string
description: ID is the internal Navidrome artist ID.
name:
type: string
description: Name is the artist name.
mbid:
type: string
description: MBID is the MusicBrainz artist ID (if known).
count:
type: integer
format: int32
description: Count is the maximum number of similar songs to return.
required:
- id
- name
- count
SimilarSongsByTrackRequest:
description: SimilarSongsByTrackRequest is the request for GetSimilarSongsByTrack.
properties:
id:
type: string
description: ID is the internal Navidrome mediafile ID.
name:
type: string
description: Name is the track title.
artist:
type: string
description: Artist is the artist name.
mbid:
type: string
description: MBID is the MusicBrainz recording ID (if known).
count:
type: integer
format: int32
description: Count is the maximum number of similar songs to return.
required:
- id
- name
- artist
- count
SimilarSongsResponse:
description: SimilarSongsResponse is the response for GetSimilarSongsBy* functions.
properties:
songs:
type: array
description: Songs is the list of similar songs.
items:
$ref: '#/components/schemas/SongRef'
required:
- songs
SongRef:
description: SongRef is a reference to a song with name and optional MBID.
description: SongRef is a reference to a song with metadata for matching.
properties:
id:
type: string
@@ -241,6 +343,22 @@ components:
mbid:
type: string
description: MBID is the MusicBrainz ID for the song.
artist:
type: string
description: Artist is the artist name.
artistMbid:
type: string
description: ArtistMBID is the MusicBrainz artist ID.
album:
type: string
description: Album is the album name.
albumMbid:
type: string
description: AlbumMBID is the MusicBrainz release ID.
duration:
type: number
format: float
description: Duration is the song duration in seconds.
required:
- name
TopSongsRequest: