Deluan b3ec005fa2 feat(plugins): implement new plugin system with using Extism
Signed-off-by: Deluan <deluan@navidrome.org>
2025-12-31 17:06:28 -05:00

286 lines
6.2 KiB
Go

// Test plugin for Navidrome plugin system integration tests.
// Build with: tinygo build -o ../test-plugin.wasm -target wasip1 -buildmode=c-shared ./main.go
package main
import (
"encoding/json"
"github.com/extism/go-pdk"
)
type Manifest struct {
Name string `json:"name"`
Author string `json:"author"`
Version string `json:"version"`
Description string `json:"description"`
Capabilities []string `json:"capabilities"`
Permissions *Permissions `json:"permissions,omitempty"`
}
type Permissions struct {
HTTP *HTTPPermission `json:"http,omitempty"`
}
type HTTPPermission struct {
Reason string `json:"reason,omitempty"`
AllowedURLs map[string][]string `json:"allowedUrls,omitempty"`
}
type ArtistInput struct {
ID string `json:"id"`
Name string `json:"name"`
MBID string `json:"mbid,omitempty"`
}
type ArtistInputWithLimit struct {
ID string `json:"id"`
Name string `json:"name"`
MBID string `json:"mbid,omitempty"`
Limit int `json:"limit,omitempty"`
}
type ArtistInputWithCount struct {
ID string `json:"id"`
Name string `json:"name"`
MBID string `json:"mbid,omitempty"`
Count int `json:"count,omitempty"`
}
type AlbumInput struct {
Name string `json:"name"`
Artist string `json:"artist"`
MBID string `json:"mbid,omitempty"`
}
type MBIDOutput struct {
MBID string `json:"mbid"`
}
type URLOutput struct {
URL string `json:"url"`
}
type BiographyOutput struct {
Biography string `json:"biography"`
}
type ArtistImage struct {
URL string `json:"url"`
Size int `json:"size"`
}
type ImagesOutput struct {
Images []ArtistImage `json:"images"`
}
type SimilarArtist struct {
Name string `json:"name"`
MBID string `json:"mbid,omitempty"`
}
type SimilarArtistsOutput struct {
Artists []SimilarArtist `json:"artists"`
}
type TopSong struct {
Name string `json:"name"`
MBID string `json:"mbid,omitempty"`
}
type TopSongsOutput struct {
Songs []TopSong `json:"songs"`
}
type AlbumInfoOutput struct {
Name string `json:"name"`
MBID string `json:"mbid,omitempty"`
Description string `json:"description,omitempty"`
URL string `json:"url,omitempty"`
}
type AlbumImagesOutput struct {
Images []ArtistImage `json:"images"`
}
//go:wasmexport nd_manifest
func ndManifest() int32 {
manifest := Manifest{
Name: "Test Plugin",
Author: "Navidrome Test",
Version: "1.0.0",
Description: "A test plugin for integration testing",
Capabilities: []string{"MetadataAgent"},
Permissions: &Permissions{
HTTP: &HTTPPermission{
Reason: "Test HTTP access",
AllowedURLs: map[string][]string{
"https://test.example.com/*": {"GET"},
},
},
},
}
out, err := json.Marshal(manifest)
if err != nil {
pdk.SetError(err)
return 1
}
pdk.Output(out)
return 0
}
//go:wasmexport nd_get_artist_mbid
func ndGetArtistMBID() int32 {
var input ArtistInput
if err := pdk.InputJSON(&input); err != nil {
pdk.SetError(err)
return 1
}
output := MBIDOutput{MBID: "test-mbid-" + input.Name}
if err := pdk.OutputJSON(output); err != nil {
pdk.SetError(err)
return 1
}
return 0
}
//go:wasmexport nd_get_artist_url
func ndGetArtistURL() int32 {
var input ArtistInput
if err := pdk.InputJSON(&input); err != nil {
pdk.SetError(err)
return 1
}
output := URLOutput{URL: "https://test.example.com/artist/" + input.Name}
if err := pdk.OutputJSON(output); err != nil {
pdk.SetError(err)
return 1
}
return 0
}
//go:wasmexport nd_get_artist_biography
func ndGetArtistBiography() int32 {
var input ArtistInput
if err := pdk.InputJSON(&input); err != nil {
pdk.SetError(err)
return 1
}
output := BiographyOutput{Biography: "Biography for " + input.Name}
if err := pdk.OutputJSON(output); err != nil {
pdk.SetError(err)
return 1
}
return 0
}
//go:wasmexport nd_get_artist_images
func ndGetArtistImages() int32 {
var input ArtistInput
if err := pdk.InputJSON(&input); err != nil {
pdk.SetError(err)
return 1
}
output := ImagesOutput{
Images: []ArtistImage{
{URL: "https://test.example.com/images/" + input.Name + "/large.jpg", Size: 500},
{URL: "https://test.example.com/images/" + input.Name + "/small.jpg", Size: 100},
},
}
if err := pdk.OutputJSON(output); err != nil {
pdk.SetError(err)
return 1
}
return 0
}
//go:wasmexport nd_get_similar_artists
func ndGetSimilarArtists() int32 {
var input ArtistInputWithLimit
if err := pdk.InputJSON(&input); err != nil {
pdk.SetError(err)
return 1
}
limit := input.Limit
if limit == 0 {
limit = 5
}
artists := make([]SimilarArtist, 0, limit)
for i := range limit {
artists = append(artists, SimilarArtist{
Name: input.Name + " Similar " + string(rune('A'+i)),
})
}
output := SimilarArtistsOutput{Artists: artists}
if err := pdk.OutputJSON(output); err != nil {
pdk.SetError(err)
return 1
}
return 0
}
//go:wasmexport nd_get_artist_top_songs
func ndGetArtistTopSongs() int32 {
var input ArtistInputWithCount
if err := pdk.InputJSON(&input); err != nil {
pdk.SetError(err)
return 1
}
count := input.Count
if count == 0 {
count = 5
}
songs := make([]TopSong, 0, count)
for i := range count {
songs = append(songs, TopSong{
Name: input.Name + " Song " + string(rune('1'+i)),
})
}
output := TopSongsOutput{Songs: songs}
if err := pdk.OutputJSON(output); err != nil {
pdk.SetError(err)
return 1
}
return 0
}
//go:wasmexport nd_get_album_info
func ndGetAlbumInfo() int32 {
var input AlbumInput
if err := pdk.InputJSON(&input); err != nil {
pdk.SetError(err)
return 1
}
output := AlbumInfoOutput{
Name: input.Name,
MBID: "test-album-mbid-" + input.Name,
Description: "Description for " + input.Name + " by " + input.Artist,
URL: "https://test.example.com/album/" + input.Name,
}
if err := pdk.OutputJSON(output); err != nil {
pdk.SetError(err)
return 1
}
return 0
}
//go:wasmexport nd_get_album_images
func ndGetAlbumImages() int32 {
var input AlbumInput
if err := pdk.InputJSON(&input); err != nil {
pdk.SetError(err)
return 1
}
output := AlbumImagesOutput{
Images: []ArtistImage{
{URL: "https://test.example.com/albums/" + input.Name + "/cover.jpg", Size: 500},
},
}
if err := pdk.OutputJSON(output); err != nil {
pdk.SetError(err)
return 1
}
return 0
}
func main() {}