2025-12-31 17:06:29 -05:00

191 lines
4.6 KiB
Go

// Test scrobbler plugin for Navidrome plugin system integration tests.
// Build with: tinygo build -o ../test-scrobbler.wasm -target wasip1 -buildmode=c-shared ./main.go
package main
import (
"encoding/json"
"strconv"
"github.com/extism/go-pdk"
)
// Manifest types
type Manifest struct {
Name string `json:"name"`
Author string `json:"author"`
Version string `json:"version"`
Description string `json:"description"`
}
// Scrobbler input/output types
type AuthInput struct {
UserID string `json:"user_id"`
Username string `json:"username"`
}
type AuthOutput struct {
Authorized bool `json:"authorized"`
}
type TrackInfo struct {
ID string `json:"id"`
Title string `json:"title"`
Album string `json:"album"`
Artist string `json:"artist"`
AlbumArtist string `json:"album_artist"`
Duration float32 `json:"duration"`
TrackNumber int `json:"track_number"`
DiscNumber int `json:"disc_number"`
MbzRecordingID string `json:"mbz_recording_id,omitempty"`
MbzAlbumID string `json:"mbz_album_id,omitempty"`
MbzArtistID string `json:"mbz_artist_id,omitempty"`
MbzReleaseGroupID string `json:"mbz_release_group_id,omitempty"`
}
type NowPlayingInput struct {
UserID string `json:"user_id"`
Username string `json:"username"`
Track TrackInfo `json:"track"`
Position int `json:"position"`
}
type ScrobbleInput struct {
UserID string `json:"user_id"`
Username string `json:"username"`
Track TrackInfo `json:"track"`
Timestamp int64 `json:"timestamp"`
}
type ScrobblerOutput struct {
Error string `json:"error,omitempty"`
ErrorType string `json:"error_type,omitempty"`
}
// checkConfigError checks if the plugin is configured to return an error.
// If "error" config is set, it returns the error message and error type.
func checkConfigError() (bool, string, string) {
errMsg, hasErr := pdk.GetConfig("error")
if !hasErr || errMsg == "" {
return false, "", ""
}
errType, _ := pdk.GetConfig("error_type")
if errType == "" {
errType = "unrecoverable"
}
return true, errMsg, errType
}
// checkAuthConfig returns whether the plugin is configured to authorize users.
// If "authorized" config is set to "false", users are not authorized.
// Default is true (authorized).
func checkAuthConfig() bool {
authStr, hasAuth := pdk.GetConfig("authorized")
if !hasAuth {
return true // Default: authorized
}
auth, err := strconv.ParseBool(authStr)
if err != nil {
return true // Default on parse error
}
return auth
}
//go:wasmexport nd_manifest
func ndManifest() int32 {
manifest := Manifest{
Name: "Test Scrobbler",
Author: "Navidrome Test",
Version: "1.0.0",
Description: "A test scrobbler plugin for integration testing",
}
out, err := json.Marshal(manifest)
if err != nil {
pdk.SetError(err)
return 1
}
pdk.Output(out)
return 0
}
//go:wasmexport nd_scrobbler_is_authorized
func ndScrobblerIsAuthorized() int32 {
var input AuthInput
if err := pdk.InputJSON(&input); err != nil {
pdk.SetError(err)
return 1
}
output := AuthOutput{
Authorized: checkAuthConfig(),
}
if err := pdk.OutputJSON(output); err != nil {
pdk.SetError(err)
return 1
}
return 0
}
//go:wasmexport nd_scrobbler_now_playing
func ndScrobblerNowPlaying() int32 {
var input NowPlayingInput
if err := pdk.InputJSON(&input); err != nil {
pdk.SetError(err)
return 1
}
// Check for configured error
hasErr, errMsg, errType := checkConfigError()
if hasErr {
output := ScrobblerOutput{
Error: errMsg,
ErrorType: errType,
}
if err := pdk.OutputJSON(output); err != nil {
pdk.SetError(err)
return 1
}
return 0
}
// Log the now playing (for potential debugging)
// In a real plugin, this would send to an external service
pdk.Log(pdk.LogInfo, "NowPlaying: "+input.Track.Title+" by "+input.Track.Artist)
// Success - no output needed
return 0
}
//go:wasmexport nd_scrobbler_scrobble
func ndScrobblerScrobble() int32 {
var input ScrobbleInput
if err := pdk.InputJSON(&input); err != nil {
pdk.SetError(err)
return 1
}
// Check for configured error
hasErr, errMsg, errType := checkConfigError()
if hasErr {
output := ScrobblerOutput{
Error: errMsg,
ErrorType: errType,
}
if err := pdk.OutputJSON(output); err != nil {
pdk.SetError(err)
return 1
}
return 0
}
// Log the scrobble (for potential debugging)
// In a real plugin, this would send to an external service
pdk.Log(pdk.LogInfo, "Scrobble: "+input.Track.Title+" by "+input.Track.Artist)
// Success - no output needed
return 0
}
func main() {}