From e6b0af63ced4f86f016aa7b3746ef5359d7ea6a5 Mon Sep 17 00:00:00 2001 From: Deluan Date: Wed, 31 Dec 2025 10:32:52 -0500 Subject: [PATCH] fix(plugins): update return types in metadata interfaces to use pointers Signed-off-by: Deluan --- plugins/README.md | 40 +++++++++++++----------- plugins/capabilities/doc.go | 10 +++--- plugins/capabilities/metadata_agent.go | 16 +++++----- plugins/metadata_agent.go | 34 +++++++++++--------- plugins/pdk/go/metadata/metadata.go | 32 +++++++++---------- plugins/pdk/go/metadata/metadata_stub.go | 16 +++++----- 6 files changed, 77 insertions(+), 71 deletions(-) diff --git a/plugins/README.md b/plugins/README.md index e6859fec6..f7e5259ad 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -191,11 +191,11 @@ Agents = "lastfm,spotify,my-plugin" Integrates with external scrobbling services. Export one or more of these functions: -| Function | Input | Output | Description | -|------------------------------|-----------------------|-------------------------|-----------------------------| -| `nd_scrobbler_is_authorized` | `{userId, username}` | `{authorized}` | Check if user is authorized | -| `nd_scrobbler_now_playing` | See below | `{error?, errorType?}` | Send now playing | -| `nd_scrobbler_scrobble` | See below | `{error?, errorType?}` | Submit a scrobble | +| Function | Input | Output | Description | +|------------------------------|-----------------------|----------------|-----------------------------|| +| `nd_scrobbler_is_authorized` | `{userId, username}` | `{authorized}` | Check if user is authorized | +| `nd_scrobbler_now_playing` | See below | (none) | Send now playing | +| `nd_scrobbler_scrobble` | See below | (none) | Submit a scrobble | **NowPlaying/Scrobble Input:** @@ -220,21 +220,23 @@ Integrates with external scrobbling services. Export one or more of these functi } ``` -**Error Output (on failure):** +**Error Handling:** -```json -{ - "error": "error message", - "errorType": "notAuthorized|retryLater|unrecoverable" -} +On success, return `0`. On failure, use `pdk.SetError()` with one of these error types: + +- `scrobbler(not_authorized)` – User needs to re-authorize +- `scrobbler(retry_later)` – Temporary failure, Navidrome will retry +- `scrobbler(unrecoverable)` – Permanent failure, scrobble discarded + +```go +import "github.com/navidrome/navidrome/plugins/pdk/go/scrobbler" + +// Return error using predefined constants +return scrobbler.ScrobblerErrorNotAuthorized +return scrobbler.ScrobblerErrorRetryLater +return scrobbler.ScrobblerErrorUnrecoverable ``` -- `notAuthorized` – User needs to re-authorize -- `retryLater` – Temporary failure, Navidrome will retry -- `unrecoverable` – Permanent failure, scrobble discarded - -On success, return empty JSON `{}` or omit output entirely. - ### Lifecycle Optional initialization callback. Export this function to run code when your plugin loads: @@ -718,8 +720,8 @@ import ( type myPlugin struct{} -func (p *myPlugin) GetArtistBiography(input metadata.ArtistBiographyInput) metadata.ArtistBiographyOutput { - return metadata.ArtistBiographyOutput{Biography: "Biography text..."} +func (p *myPlugin) GetArtistBiography(input metadata.ArtistRequest) (*metadata.ArtistBiographyResponse, error) { + return &metadata.ArtistBiographyResponse{Biography: "Biography text..."}, nil } func init() { diff --git a/plugins/capabilities/doc.go b/plugins/capabilities/doc.go index 7569fae52..a90737f89 100644 --- a/plugins/capabilities/doc.go +++ b/plugins/capabilities/doc.go @@ -10,7 +10,7 @@ // //nd:capability name=metadata // type MetadataAgent interface { // //nd:export name=nd_get_artist_biography -// GetArtistBiography(ArtistInput) (ArtistBiographyOutput, error) +// GetArtistBiography(ArtistRequest) (*ArtistBiographyResponse, error) // } // // Annotation Reference: @@ -35,7 +35,7 @@ // // // Optional provider interfaces // type ArtistBiographyProvider interface { -// GetArtistBiography(ArtistInput) (ArtistBiographyOutput, error) +// GetArtistBiography(ArtistRequest) (*ArtistBiographyResponse, error) // } // // // Registration function @@ -47,9 +47,9 @@ // // // Scrobbler requires all methods // type Scrobbler interface { -// IsAuthorized(AuthInput) (AuthOutput, error) -// NowPlaying(NowPlayingInput) (ScrobblerOutput, error) -// Scrobble(ScrobbleInput) (ScrobblerOutput, error) +// IsAuthorized(IsAuthorizedRequest) (*IsAuthorizedResponse, error) +// NowPlaying(NowPlayingRequest) error +// Scrobble(ScrobbleRequest) error // } // // func Register(impl Scrobbler) { ... } diff --git a/plugins/capabilities/metadata_agent.go b/plugins/capabilities/metadata_agent.go index 0658740ab..a28ec29d3 100644 --- a/plugins/capabilities/metadata_agent.go +++ b/plugins/capabilities/metadata_agent.go @@ -11,35 +11,35 @@ package capabilities type MetadataAgent interface { // GetArtistMBID retrieves the MusicBrainz ID for an artist. //nd:export name=nd_get_artist_mbid - GetArtistMBID(ArtistMBIDRequest) (ArtistMBIDResponse, error) + GetArtistMBID(ArtistMBIDRequest) (*ArtistMBIDResponse, error) // GetArtistURL retrieves the external URL for an artist. //nd:export name=nd_get_artist_url - GetArtistURL(ArtistRequest) (ArtistURLResponse, error) + GetArtistURL(ArtistRequest) (*ArtistURLResponse, error) // GetArtistBiography retrieves the biography for an artist. //nd:export name=nd_get_artist_biography - GetArtistBiography(ArtistRequest) (ArtistBiographyResponse, error) + GetArtistBiography(ArtistRequest) (*ArtistBiographyResponse, error) // GetSimilarArtists retrieves similar artists for a given artist. //nd:export name=nd_get_similar_artists - GetSimilarArtists(SimilarArtistsRequest) (SimilarArtistsResponse, error) + GetSimilarArtists(SimilarArtistsRequest) (*SimilarArtistsResponse, error) // GetArtistImages retrieves images for an artist. //nd:export name=nd_get_artist_images - GetArtistImages(ArtistRequest) (ArtistImagesResponse, error) + GetArtistImages(ArtistRequest) (*ArtistImagesResponse, error) // GetArtistTopSongs retrieves top songs for an artist. //nd:export name=nd_get_artist_top_songs - GetArtistTopSongs(TopSongsRequest) (TopSongsResponse, error) + GetArtistTopSongs(TopSongsRequest) (*TopSongsResponse, error) // GetAlbumInfo retrieves album information. //nd:export name=nd_get_album_info - GetAlbumInfo(AlbumRequest) (AlbumInfoResponse, error) + GetAlbumInfo(AlbumRequest) (*AlbumInfoResponse, error) // GetAlbumImages retrieves images for an album. //nd:export name=nd_get_album_images - GetAlbumImages(AlbumRequest) (AlbumImagesResponse, error) + GetAlbumImages(AlbumRequest) (*AlbumImagesResponse, error) } // ArtistMBIDRequest is the request for GetArtistMBID. diff --git a/plugins/metadata_agent.go b/plugins/metadata_agent.go index c0fedd160..ae53ca63d 100644 --- a/plugins/metadata_agent.go +++ b/plugins/metadata_agent.go @@ -55,12 +55,12 @@ func (a *MetadataAgent) AgentName() string { // GetArtistMBID retrieves the MusicBrainz ID for an artist func (a *MetadataAgent) GetArtistMBID(ctx context.Context, id string, name string) (string, error) { input := capabilities.ArtistMBIDRequest{ID: id, Name: name} - result, err := callPluginFunction[capabilities.ArtistMBIDRequest, capabilities.ArtistMBIDResponse](ctx, a.plugin, FuncGetArtistMBID, input) + result, err := callPluginFunction[capabilities.ArtistMBIDRequest, *capabilities.ArtistMBIDResponse](ctx, a.plugin, FuncGetArtistMBID, input) if err != nil { return "", errors.Join(agents.ErrNotFound, err) } - if result.MBID == "" { + if result == nil || result.MBID == "" { return "", agents.ErrNotFound } @@ -70,11 +70,11 @@ func (a *MetadataAgent) GetArtistMBID(ctx context.Context, id string, name strin // GetArtistURL retrieves the external URL for an artist func (a *MetadataAgent) GetArtistURL(ctx context.Context, id, name, mbid string) (string, error) { input := capabilities.ArtistRequest{ID: id, Name: name, MBID: mbid} - result, err := callPluginFunction[capabilities.ArtistRequest, capabilities.ArtistURLResponse](ctx, a.plugin, FuncGetArtistURL, input) + result, err := callPluginFunction[capabilities.ArtistRequest, *capabilities.ArtistURLResponse](ctx, a.plugin, FuncGetArtistURL, input) if err != nil { return "", errors.Join(agents.ErrNotFound, err) } - if result.URL == "" { + if result == nil || result.URL == "" { return "", agents.ErrNotFound } return result.URL, nil @@ -83,12 +83,12 @@ func (a *MetadataAgent) GetArtistURL(ctx context.Context, id, name, mbid string) // GetArtistBiography retrieves the biography for an artist func (a *MetadataAgent) GetArtistBiography(ctx context.Context, id, name, mbid string) (string, error) { input := capabilities.ArtistRequest{ID: id, Name: name, MBID: mbid} - result, err := callPluginFunction[capabilities.ArtistRequest, capabilities.ArtistBiographyResponse](ctx, a.plugin, FuncGetArtistBiography, input) + result, err := callPluginFunction[capabilities.ArtistRequest, *capabilities.ArtistBiographyResponse](ctx, a.plugin, FuncGetArtistBiography, input) if err != nil { return "", errors.Join(agents.ErrNotFound, err) } - if result.Biography == "" { + if result == nil || result.Biography == "" { return "", agents.ErrNotFound } @@ -98,12 +98,12 @@ func (a *MetadataAgent) GetArtistBiography(ctx context.Context, id, name, mbid s // GetSimilarArtists retrieves similar artists func (a *MetadataAgent) GetSimilarArtists(ctx context.Context, id, name, mbid string, limit int) ([]agents.Artist, error) { input := capabilities.SimilarArtistsRequest{ID: id, Name: name, MBID: mbid, Limit: int32(limit)} - result, err := callPluginFunction[capabilities.SimilarArtistsRequest, capabilities.SimilarArtistsResponse](ctx, a.plugin, FuncGetSimilarArtists, input) + result, err := callPluginFunction[capabilities.SimilarArtistsRequest, *capabilities.SimilarArtistsResponse](ctx, a.plugin, FuncGetSimilarArtists, input) if err != nil { return nil, errors.Join(agents.ErrNotFound, err) } - if len(result.Artists) == 0 { + if result == nil || len(result.Artists) == 0 { return nil, agents.ErrNotFound } @@ -118,12 +118,12 @@ func (a *MetadataAgent) GetSimilarArtists(ctx context.Context, id, name, mbid st // GetArtistImages retrieves images for an artist func (a *MetadataAgent) GetArtistImages(ctx context.Context, id, name, mbid string) ([]agents.ExternalImage, error) { input := capabilities.ArtistRequest{ID: id, Name: name, MBID: mbid} - result, err := callPluginFunction[capabilities.ArtistRequest, capabilities.ArtistImagesResponse](ctx, a.plugin, FuncGetArtistImages, input) + result, err := callPluginFunction[capabilities.ArtistRequest, *capabilities.ArtistImagesResponse](ctx, a.plugin, FuncGetArtistImages, input) if err != nil { return nil, errors.Join(agents.ErrNotFound, err) } - if len(result.Images) == 0 { + if result == nil || len(result.Images) == 0 { return nil, agents.ErrNotFound } @@ -138,12 +138,12 @@ func (a *MetadataAgent) GetArtistImages(ctx context.Context, id, name, mbid stri // GetArtistTopSongs retrieves top songs for an artist func (a *MetadataAgent) GetArtistTopSongs(ctx context.Context, id, artistName, mbid string, count int) ([]agents.Song, error) { input := capabilities.TopSongsRequest{ID: id, Name: artistName, MBID: mbid, Count: int32(count)} - result, err := callPluginFunction[capabilities.TopSongsRequest, capabilities.TopSongsResponse](ctx, a.plugin, FuncGetArtistTopSongs, input) + result, err := callPluginFunction[capabilities.TopSongsRequest, *capabilities.TopSongsResponse](ctx, a.plugin, FuncGetArtistTopSongs, input) if err != nil { return nil, errors.Join(agents.ErrNotFound, err) } - if len(result.Songs) == 0 { + if result == nil || len(result.Songs) == 0 { return nil, agents.ErrNotFound } @@ -158,11 +158,15 @@ func (a *MetadataAgent) GetArtistTopSongs(ctx context.Context, id, artistName, m // GetAlbumInfo retrieves album information func (a *MetadataAgent) GetAlbumInfo(ctx context.Context, name, artist, mbid string) (*agents.AlbumInfo, error) { input := capabilities.AlbumRequest{Name: name, Artist: artist, MBID: mbid} - result, err := callPluginFunction[capabilities.AlbumRequest, capabilities.AlbumInfoResponse](ctx, a.plugin, FuncGetAlbumInfo, input) + result, err := callPluginFunction[capabilities.AlbumRequest, *capabilities.AlbumInfoResponse](ctx, a.plugin, FuncGetAlbumInfo, input) if err != nil { return nil, errors.Join(agents.ErrNotFound, err) } + if result == nil { + return nil, agents.ErrNotFound + } + return &agents.AlbumInfo{ Name: result.Name, MBID: result.MBID, @@ -174,12 +178,12 @@ func (a *MetadataAgent) GetAlbumInfo(ctx context.Context, name, artist, mbid str // GetAlbumImages retrieves images for an album func (a *MetadataAgent) GetAlbumImages(ctx context.Context, name, artist, mbid string) ([]agents.ExternalImage, error) { input := capabilities.AlbumRequest{Name: name, Artist: artist, MBID: mbid} - result, err := callPluginFunction[capabilities.AlbumRequest, capabilities.AlbumImagesResponse](ctx, a.plugin, FuncGetAlbumImages, input) + result, err := callPluginFunction[capabilities.AlbumRequest, *capabilities.AlbumImagesResponse](ctx, a.plugin, FuncGetAlbumImages, input) if err != nil { return nil, errors.Join(agents.ErrNotFound, err) } - if len(result.Images) == 0 { + if result == nil || len(result.Images) == 0 { return nil, agents.ErrNotFound } diff --git a/plugins/pdk/go/metadata/metadata.go b/plugins/pdk/go/metadata/metadata.go index d212e7106..ca744d8df 100644 --- a/plugins/pdk/go/metadata/metadata.go +++ b/plugins/pdk/go/metadata/metadata.go @@ -153,52 +153,52 @@ type Metadata interface{} // ArtistMBIDProvider provides the GetArtistMBID function. type ArtistMBIDProvider interface { - GetArtistMBID(ArtistMBIDRequest) (ArtistMBIDResponse, error) + GetArtistMBID(ArtistMBIDRequest) (*ArtistMBIDResponse, error) } // ArtistURLProvider provides the GetArtistURL function. type ArtistURLProvider interface { - GetArtistURL(ArtistRequest) (ArtistURLResponse, error) + GetArtistURL(ArtistRequest) (*ArtistURLResponse, error) } // ArtistBiographyProvider provides the GetArtistBiography function. type ArtistBiographyProvider interface { - GetArtistBiography(ArtistRequest) (ArtistBiographyResponse, error) + GetArtistBiography(ArtistRequest) (*ArtistBiographyResponse, error) } // SimilarArtistsProvider provides the GetSimilarArtists function. type SimilarArtistsProvider interface { - GetSimilarArtists(SimilarArtistsRequest) (SimilarArtistsResponse, error) + GetSimilarArtists(SimilarArtistsRequest) (*SimilarArtistsResponse, error) } // ArtistImagesProvider provides the GetArtistImages function. type ArtistImagesProvider interface { - GetArtistImages(ArtistRequest) (ArtistImagesResponse, error) + GetArtistImages(ArtistRequest) (*ArtistImagesResponse, error) } // ArtistTopSongsProvider provides the GetArtistTopSongs function. type ArtistTopSongsProvider interface { - GetArtistTopSongs(TopSongsRequest) (TopSongsResponse, error) + GetArtistTopSongs(TopSongsRequest) (*TopSongsResponse, error) } // AlbumInfoProvider provides the GetAlbumInfo function. type AlbumInfoProvider interface { - GetAlbumInfo(AlbumRequest) (AlbumInfoResponse, error) + GetAlbumInfo(AlbumRequest) (*AlbumInfoResponse, error) } // AlbumImagesProvider provides the GetAlbumImages function. type AlbumImagesProvider interface { - GetAlbumImages(AlbumRequest) (AlbumImagesResponse, error) + GetAlbumImages(AlbumRequest) (*AlbumImagesResponse, error) } // Internal implementation holders var ( - artistMBIDImpl func(ArtistMBIDRequest) (ArtistMBIDResponse, error) - artistURLImpl func(ArtistRequest) (ArtistURLResponse, error) - artistBiographyImpl func(ArtistRequest) (ArtistBiographyResponse, error) - similarArtistsImpl func(SimilarArtistsRequest) (SimilarArtistsResponse, error) - artistImagesImpl func(ArtistRequest) (ArtistImagesResponse, error) - artistTopSongsImpl func(TopSongsRequest) (TopSongsResponse, error) - albumInfoImpl func(AlbumRequest) (AlbumInfoResponse, error) - albumImagesImpl func(AlbumRequest) (AlbumImagesResponse, error) + artistMBIDImpl func(ArtistMBIDRequest) (*ArtistMBIDResponse, error) + artistURLImpl func(ArtistRequest) (*ArtistURLResponse, error) + artistBiographyImpl func(ArtistRequest) (*ArtistBiographyResponse, error) + similarArtistsImpl func(SimilarArtistsRequest) (*SimilarArtistsResponse, error) + artistImagesImpl func(ArtistRequest) (*ArtistImagesResponse, error) + artistTopSongsImpl func(TopSongsRequest) (*TopSongsResponse, error) + albumInfoImpl func(AlbumRequest) (*AlbumInfoResponse, error) + albumImagesImpl func(AlbumRequest) (*AlbumImagesResponse, error) ) // Register registers a metadata implementation. diff --git a/plugins/pdk/go/metadata/metadata_stub.go b/plugins/pdk/go/metadata/metadata_stub.go index 60817a108..165ad6240 100644 --- a/plugins/pdk/go/metadata/metadata_stub.go +++ b/plugins/pdk/go/metadata/metadata_stub.go @@ -150,42 +150,42 @@ type Metadata interface{} // ArtistMBIDProvider provides the GetArtistMBID function. type ArtistMBIDProvider interface { - GetArtistMBID(ArtistMBIDRequest) (ArtistMBIDResponse, error) + GetArtistMBID(ArtistMBIDRequest) (*ArtistMBIDResponse, error) } // ArtistURLProvider provides the GetArtistURL function. type ArtistURLProvider interface { - GetArtistURL(ArtistRequest) (ArtistURLResponse, error) + GetArtistURL(ArtistRequest) (*ArtistURLResponse, error) } // ArtistBiographyProvider provides the GetArtistBiography function. type ArtistBiographyProvider interface { - GetArtistBiography(ArtistRequest) (ArtistBiographyResponse, error) + GetArtistBiography(ArtistRequest) (*ArtistBiographyResponse, error) } // SimilarArtistsProvider provides the GetSimilarArtists function. type SimilarArtistsProvider interface { - GetSimilarArtists(SimilarArtistsRequest) (SimilarArtistsResponse, error) + GetSimilarArtists(SimilarArtistsRequest) (*SimilarArtistsResponse, error) } // ArtistImagesProvider provides the GetArtistImages function. type ArtistImagesProvider interface { - GetArtistImages(ArtistRequest) (ArtistImagesResponse, error) + GetArtistImages(ArtistRequest) (*ArtistImagesResponse, error) } // ArtistTopSongsProvider provides the GetArtistTopSongs function. type ArtistTopSongsProvider interface { - GetArtistTopSongs(TopSongsRequest) (TopSongsResponse, error) + GetArtistTopSongs(TopSongsRequest) (*TopSongsResponse, error) } // AlbumInfoProvider provides the GetAlbumInfo function. type AlbumInfoProvider interface { - GetAlbumInfo(AlbumRequest) (AlbumInfoResponse, error) + GetAlbumInfo(AlbumRequest) (*AlbumInfoResponse, error) } // AlbumImagesProvider provides the GetAlbumImages function. type AlbumImagesProvider interface { - GetAlbumImages(AlbumRequest) (AlbumImagesResponse, error) + GetAlbumImages(AlbumRequest) (*AlbumImagesResponse, error) } // NotImplementedCode is the standard return code for unimplemented functions.