refactor: update HTTP request handling to use host.HTTPSend for improved error management
This commit is contained in:
+12
-8
@@ -84,17 +84,21 @@ func uploadToUguu(imageData []byte, contentType string) (string, error) {
|
||||
body = append(body, imageData...)
|
||||
body = append(body, []byte(fmt.Sprintf("\r\n--%s--\r\n", boundary))...)
|
||||
|
||||
req := pdk.NewHTTPRequest(pdk.MethodPost, "https://uguu.se/upload")
|
||||
req.SetHeader("Content-Type", fmt.Sprintf("multipart/form-data; boundary=%s", boundary))
|
||||
req.SetBody(body)
|
||||
|
||||
resp := req.Send()
|
||||
if resp.Status() >= 400 {
|
||||
return "", fmt.Errorf("uguu.se upload failed: HTTP %d", resp.Status())
|
||||
resp, err := host.HTTPSend(host.HTTPRequest{
|
||||
Method: "POST",
|
||||
URL: "https://uguu.se/upload",
|
||||
Headers: map[string]string{"Content-Type": fmt.Sprintf("multipart/form-data; boundary=%s", boundary)},
|
||||
Body: body,
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("uguu.se upload failed: %w", err)
|
||||
}
|
||||
if resp.StatusCode >= 400 {
|
||||
return "", fmt.Errorf("uguu.se upload failed: HTTP %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var result uguuResponse
|
||||
if err := json.Unmarshal(resp.Body(), &result); err != nil {
|
||||
if err := json.Unmarshal(resp.Body, &result); err != nil {
|
||||
return "", fmt.Errorf("failed to parse uguu.se response: %w", err)
|
||||
}
|
||||
|
||||
|
||||
+8
-7
@@ -20,6 +20,8 @@ var _ = Describe("getImageURL", func() {
|
||||
host.ArtworkMock.Calls = nil
|
||||
host.SubsonicAPIMock.ExpectedCalls = nil
|
||||
host.SubsonicAPIMock.Calls = nil
|
||||
host.HTTPMock.ExpectedCalls = nil
|
||||
host.HTTPMock.Calls = nil
|
||||
pdk.PDKMock.On("Log", mock.Anything, mock.Anything).Maybe()
|
||||
})
|
||||
|
||||
@@ -71,10 +73,9 @@ var _ = Describe("getImageURL", func() {
|
||||
Return("image/jpeg", imageData, nil)
|
||||
|
||||
// Mock uguu.se HTTP upload
|
||||
uguuReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, "https://uguu.se/upload").Return(uguuReq)
|
||||
pdk.PDKMock.On("Send", uguuReq).Return(pdk.NewStubHTTPResponse(200, nil,
|
||||
[]byte(`{"success":true,"files":[{"url":"https://a.uguu.se/uploaded.jpg"}]}`)))
|
||||
host.HTTPMock.On("Send", mock.MatchedBy(func(req host.HTTPRequest) bool {
|
||||
return req.URL == "https://uguu.se/upload"
|
||||
})).Return(&host.HTTPResponse{StatusCode: 200, Body: []byte(`{"success":true,"files":[{"url":"https://a.uguu.se/uploaded.jpg"}]}`)}, nil)
|
||||
|
||||
// Mock cache set
|
||||
host.CacheMock.On("SetString", "uguu.artwork.track1", "https://a.uguu.se/uploaded.jpg", int64(9000)).Return(nil)
|
||||
@@ -98,9 +99,9 @@ var _ = Describe("getImageURL", func() {
|
||||
host.SubsonicAPIMock.On("CallRaw", "/getCoverArt?u=testuser&id=track1&size=300").
|
||||
Return("image/jpeg", []byte("fake-image-data"), nil)
|
||||
|
||||
uguuReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, "https://uguu.se/upload").Return(uguuReq)
|
||||
pdk.PDKMock.On("Send", uguuReq).Return(pdk.NewStubHTTPResponse(500, nil, []byte(`{"success":false}`)))
|
||||
host.HTTPMock.On("Send", mock.MatchedBy(func(req host.HTTPRequest) bool {
|
||||
return req.URL == "https://uguu.se/upload"
|
||||
})).Return(&host.HTTPResponse{StatusCode: 500, Body: []byte(`{"success":false}`)}, nil)
|
||||
|
||||
url := getImageURL("testuser", "track1")
|
||||
Expect(url).To(BeEmpty())
|
||||
|
||||
@@ -3,7 +3,7 @@ module discord-rich-presence
|
||||
go 1.25
|
||||
|
||||
require (
|
||||
github.com/navidrome/navidrome/plugins/pdk/go v0.0.0-20260207182358-29f98b889b11
|
||||
github.com/navidrome/navidrome/plugins/pdk/go v0.0.0-20260224182233-40719d928320
|
||||
github.com/onsi/ginkgo/v2 v2.28.1
|
||||
github.com/onsi/gomega v1.39.1
|
||||
github.com/stretchr/testify v1.11.1
|
||||
|
||||
@@ -30,8 +30,8 @@ github.com/maruel/natural v1.3.0 h1:VsmCsBmEyrR46RomtgHs5hbKADGRVtliHTyCOLFBpsg=
|
||||
github.com/maruel/natural v1.3.0/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=
|
||||
github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE=
|
||||
github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A=
|
||||
github.com/navidrome/navidrome/plugins/pdk/go v0.0.0-20260207182358-29f98b889b11 h1:VE4bqzkS6apWDtco9hAGdThFttjbYoLR0DEILAGDyyc=
|
||||
github.com/navidrome/navidrome/plugins/pdk/go v0.0.0-20260207182358-29f98b889b11/go.mod h1:HijQ0Z0OeEa6LIwUJh6H9WqAptye096jHazmKXf+YV4=
|
||||
github.com/navidrome/navidrome/plugins/pdk/go v0.0.0-20260224182233-40719d928320 h1:TVn0Jv9Xd4aoyTbBoSMAv38Mfh8lWX/kMP2au2KX1cQ=
|
||||
github.com/navidrome/navidrome/plugins/pdk/go v0.0.0-20260224182233-40719d928320/go.mod h1:HijQ0Z0OeEa6LIwUJh6H9WqAptye096jHazmKXf+YV4=
|
||||
github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI=
|
||||
github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
|
||||
github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
|
||||
|
||||
+10
-12
@@ -33,6 +33,8 @@ var _ = Describe("discordPlugin", func() {
|
||||
host.ArtworkMock.Calls = nil
|
||||
host.SubsonicAPIMock.ExpectedCalls = nil
|
||||
host.SubsonicAPIMock.Calls = nil
|
||||
host.HTTPMock.ExpectedCalls = nil
|
||||
host.HTTPMock.Calls = nil
|
||||
})
|
||||
|
||||
Describe("getConfig", func() {
|
||||
@@ -128,9 +130,9 @@ var _ = Describe("discordPlugin", func() {
|
||||
|
||||
// Mock HTTP GET request for gateway discovery
|
||||
gatewayResp := []byte(`{"url":"wss://gateway.discord.gg"}`)
|
||||
gatewayReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodGet, "https://discord.com/api/gateway").Return(gatewayReq).Once()
|
||||
pdk.PDKMock.On("Send", gatewayReq).Return(pdk.NewStubHTTPResponse(200, nil, gatewayResp)).Once()
|
||||
host.HTTPMock.On("Send", mock.MatchedBy(func(req host.HTTPRequest) bool {
|
||||
return req.Method == "GET" && req.URL == "https://discord.com/api/gateway"
|
||||
})).Return(&host.HTTPResponse{StatusCode: 200, Body: gatewayResp}, nil)
|
||||
|
||||
// Mock WebSocket connection
|
||||
host.WebSocketMock.On("Connect", mock.MatchedBy(func(url string) bool {
|
||||
@@ -148,9 +150,7 @@ var _ = Describe("discordPlugin", func() {
|
||||
host.ArtworkMock.On("GetTrackUrl", "track1", int32(300)).Return("https://example.com/art.jpg", nil)
|
||||
|
||||
// Mock HTTP POST requests (Discord external assets API)
|
||||
postReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, externalAssetsURL).Return(postReq)
|
||||
pdk.PDKMock.On("Send", postReq).Return(pdk.NewStubHTTPResponse(200, nil, []byte(`{}`)))
|
||||
host.HTTPMock.On("Send", externalAssetsReq).Return(&host.HTTPResponse{StatusCode: 200, Body: []byte(`{}`)}, nil)
|
||||
|
||||
// Schedule clear activity callback
|
||||
host.SchedulerMock.On("ScheduleOneTime", mock.Anything, payloadClearActivity, "testuser-clear").Return("testuser-clear", nil)
|
||||
@@ -180,9 +180,9 @@ var _ = Describe("discordPlugin", func() {
|
||||
// Connect mocks
|
||||
host.CacheMock.On("GetInt", "discord.seq.testuser").Return(int64(0), false, errors.New("not found"))
|
||||
gatewayResp := []byte(`{"url":"wss://gateway.discord.gg"}`)
|
||||
gatewayReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodGet, "https://discord.com/api/gateway").Return(gatewayReq).Once()
|
||||
pdk.PDKMock.On("Send", gatewayReq).Return(pdk.NewStubHTTPResponse(200, nil, gatewayResp)).Once()
|
||||
host.HTTPMock.On("Send", mock.MatchedBy(func(req host.HTTPRequest) bool {
|
||||
return req.Method == "GET" && req.URL == "https://discord.com/api/gateway"
|
||||
})).Return(&host.HTTPResponse{StatusCode: 200, Body: gatewayResp}, nil)
|
||||
host.WebSocketMock.On("Connect", mock.MatchedBy(func(url string) bool {
|
||||
return strings.Contains(url, "gateway.discord.gg")
|
||||
}), mock.Anything, "testuser").Return("testuser", nil)
|
||||
@@ -199,9 +199,7 @@ var _ = Describe("discordPlugin", func() {
|
||||
host.CacheMock.On("GetString", discordImageKey).Return("", false, nil)
|
||||
host.CacheMock.On("SetString", discordImageKey, mock.Anything, mock.Anything).Return(nil)
|
||||
host.ArtworkMock.On("GetTrackUrl", "track1", int32(300)).Return("https://example.com/art.jpg", nil)
|
||||
postReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, externalAssetsURL).Return(postReq)
|
||||
pdk.PDKMock.On("Send", postReq).Return(pdk.NewStubHTTPResponse(200, nil, []byte(`{}`)))
|
||||
host.HTTPMock.On("Send", externalAssetsReq).Return(&host.HTTPResponse{StatusCode: 200, Body: []byte(`{}`)}, nil)
|
||||
host.SchedulerMock.On("ScheduleOneTime", mock.Anything, payloadClearActivity, "testuser-clear").Return("testuser-clear", nil)
|
||||
|
||||
err := plugin.NowPlaying(scrobbler.NowPlayingRequest{
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/navidrome/navidrome/plugins/pdk/go/host"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/stretchr/testify/mock"
|
||||
@@ -17,6 +18,6 @@ func TestDiscordPlugin(t *testing.T) {
|
||||
// Shared matchers for tighter mock expectations across all test files.
|
||||
var (
|
||||
discordImageKey = mock.MatchedBy(func(key string) bool { return strings.HasPrefix(key, "discord.image.") })
|
||||
externalAssetsURL = mock.MatchedBy(func(url string) bool { return strings.Contains(url, "external-assets") })
|
||||
externalAssetsReq = mock.MatchedBy(func(req host.HTTPRequest) bool { return strings.Contains(req.URL, "external-assets") })
|
||||
spotifyURLKey = mock.MatchedBy(func(key string) bool { return strings.HasPrefix(key, "spotify.url.") })
|
||||
)
|
||||
|
||||
@@ -147,18 +147,22 @@ func (r *discordRPC) processImage(imageURL, clientID, token string, ttl int64) (
|
||||
|
||||
// Process via Discord API
|
||||
body := fmt.Sprintf(`{"urls":[%q]}`, imageURL)
|
||||
req := pdk.NewHTTPRequest(pdk.MethodPost, fmt.Sprintf("https://discord.com/api/v9/applications/%s/external-assets", clientID))
|
||||
req.SetHeader("Authorization", token)
|
||||
req.SetHeader("Content-Type", "application/json")
|
||||
req.SetBody([]byte(body))
|
||||
|
||||
resp := req.Send()
|
||||
if resp.Status() >= 400 {
|
||||
return "", fmt.Errorf("failed to process image: HTTP %d", resp.Status())
|
||||
resp, err := host.HTTPSend(host.HTTPRequest{
|
||||
Method: "POST",
|
||||
URL: fmt.Sprintf("https://discord.com/api/v9/applications/%s/external-assets", clientID),
|
||||
Headers: map[string]string{"Authorization": token, "Content-Type": "application/json"},
|
||||
Body: []byte(body),
|
||||
})
|
||||
if err != nil {
|
||||
pdk.Log(pdk.LogWarn, fmt.Sprintf("HTTP request failed for image processing: %v", err))
|
||||
return "", fmt.Errorf("failed to process image: %w", err)
|
||||
}
|
||||
if resp.StatusCode >= 400 {
|
||||
return "", fmt.Errorf("failed to process image: HTTP %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var data []map[string]string
|
||||
if err := json.Unmarshal(resp.Body(), &data); err != nil {
|
||||
if err := json.Unmarshal(resp.Body, &data); err != nil {
|
||||
return "", fmt.Errorf("failed to unmarshal image response: %w", err)
|
||||
}
|
||||
|
||||
@@ -257,14 +261,20 @@ func (r *discordRPC) sendMessage(username string, opCode int, payload any) error
|
||||
|
||||
// getDiscordGateway retrieves the Discord gateway URL.
|
||||
func (r *discordRPC) getDiscordGateway() (string, error) {
|
||||
req := pdk.NewHTTPRequest(pdk.MethodGet, "https://discord.com/api/gateway")
|
||||
resp := req.Send()
|
||||
if resp.Status() != 200 {
|
||||
return "", fmt.Errorf("failed to get Discord gateway: HTTP %d", resp.Status())
|
||||
resp, err := host.HTTPSend(host.HTTPRequest{
|
||||
Method: "GET",
|
||||
URL: "https://discord.com/api/gateway",
|
||||
})
|
||||
if err != nil {
|
||||
pdk.Log(pdk.LogWarn, fmt.Sprintf("HTTP request failed for Discord gateway: %v", err))
|
||||
return "", fmt.Errorf("failed to get Discord gateway: %w", err)
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return "", fmt.Errorf("failed to get Discord gateway: HTTP %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var result map[string]string
|
||||
if err := json.Unmarshal(resp.Body(), &result); err != nil {
|
||||
if err := json.Unmarshal(resp.Body, &result); err != nil {
|
||||
return "", fmt.Errorf("failed to parse Discord gateway response: %w", err)
|
||||
}
|
||||
return result["url"], nil
|
||||
|
||||
+15
-35
@@ -25,6 +25,8 @@ var _ = Describe("discordRPC", func() {
|
||||
host.WebSocketMock.Calls = nil
|
||||
host.SchedulerMock.ExpectedCalls = nil
|
||||
host.SchedulerMock.Calls = nil
|
||||
host.HTTPMock.ExpectedCalls = nil
|
||||
host.HTTPMock.Calls = nil
|
||||
})
|
||||
|
||||
Describe("sendMessage", func() {
|
||||
@@ -81,9 +83,9 @@ var _ = Describe("discordRPC", func() {
|
||||
|
||||
// Mock HTTP GET request for gateway discovery
|
||||
gatewayResp := []byte(`{"url":"wss://gateway.discord.gg"}`)
|
||||
httpReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodGet, "https://discord.com/api/gateway").Return(httpReq)
|
||||
pdk.PDKMock.On("Send", mock.Anything).Return(pdk.NewStubHTTPResponse(200, nil, gatewayResp))
|
||||
host.HTTPMock.On("Send", mock.MatchedBy(func(req host.HTTPRequest) bool {
|
||||
return req.Method == "GET" && req.URL == "https://discord.com/api/gateway"
|
||||
})).Return(&host.HTTPResponse{StatusCode: 200, Body: gatewayResp}, nil)
|
||||
|
||||
// Mock WebSocket connection
|
||||
host.WebSocketMock.On("Connect", mock.MatchedBy(func(url string) bool {
|
||||
@@ -265,9 +267,7 @@ var _ = Describe("discordRPC", func() {
|
||||
return val == "mp:external/new-asset"
|
||||
}), int64(imageCacheTTL)).Return(nil)
|
||||
|
||||
httpReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, externalAssetsURL).Return(httpReq)
|
||||
pdk.PDKMock.On("Send", mock.Anything).Return(pdk.NewStubHTTPResponse(200, nil, []byte(`[{"external_asset_path":"external/new-asset"}]`)))
|
||||
host.HTTPMock.On("Send", externalAssetsReq).Return(&host.HTTPResponse{StatusCode: 200, Body: []byte(`[{"external_asset_path":"external/new-asset"}]`)}, nil)
|
||||
|
||||
result, err := r.processImage("https://example.com/art.jpg", "client123", "token123", imageCacheTTL)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -277,9 +277,7 @@ var _ = Describe("discordRPC", func() {
|
||||
It("returns error on HTTP failure", func() {
|
||||
host.CacheMock.On("GetString", discordImageKey).Return("", false, nil)
|
||||
|
||||
httpReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, externalAssetsURL).Return(httpReq)
|
||||
pdk.PDKMock.On("Send", mock.Anything).Return(pdk.NewStubHTTPResponse(500, nil, []byte(`error`)))
|
||||
host.HTTPMock.On("Send", externalAssetsReq).Return(&host.HTTPResponse{StatusCode: 500, Body: []byte(`error`)}, nil)
|
||||
|
||||
_, err := r.processImage("https://example.com/art.jpg", "client123", "token123", imageCacheTTL)
|
||||
Expect(err).To(HaveOccurred())
|
||||
@@ -289,9 +287,7 @@ var _ = Describe("discordRPC", func() {
|
||||
It("returns error on unmarshal failure", func() {
|
||||
host.CacheMock.On("GetString", discordImageKey).Return("", false, nil)
|
||||
|
||||
httpReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, externalAssetsURL).Return(httpReq)
|
||||
pdk.PDKMock.On("Send", mock.Anything).Return(pdk.NewStubHTTPResponse(200, nil, []byte(`{"not":"an-array"}`)))
|
||||
host.HTTPMock.On("Send", externalAssetsReq).Return(&host.HTTPResponse{StatusCode: 200, Body: []byte(`{"not":"an-array"}`)}, nil)
|
||||
|
||||
_, err := r.processImage("https://example.com/art.jpg", "client123", "token123", imageCacheTTL)
|
||||
Expect(err).To(HaveOccurred())
|
||||
@@ -301,9 +297,7 @@ var _ = Describe("discordRPC", func() {
|
||||
It("returns error on empty response array", func() {
|
||||
host.CacheMock.On("GetString", discordImageKey).Return("", false, nil)
|
||||
|
||||
httpReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, externalAssetsURL).Return(httpReq)
|
||||
pdk.PDKMock.On("Send", mock.Anything).Return(pdk.NewStubHTTPResponse(200, nil, []byte(`[]`)))
|
||||
host.HTTPMock.On("Send", externalAssetsReq).Return(&host.HTTPResponse{StatusCode: 200, Body: []byte(`[]`)}, nil)
|
||||
|
||||
_, err := r.processImage("https://example.com/art.jpg", "client123", "token123", imageCacheTTL)
|
||||
Expect(err).To(HaveOccurred())
|
||||
@@ -313,9 +307,7 @@ var _ = Describe("discordRPC", func() {
|
||||
It("returns error on empty external_asset_path", func() {
|
||||
host.CacheMock.On("GetString", discordImageKey).Return("", false, nil)
|
||||
|
||||
httpReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, externalAssetsURL).Return(httpReq)
|
||||
pdk.PDKMock.On("Send", mock.Anything).Return(pdk.NewStubHTTPResponse(200, nil, []byte(`[{"external_asset_path":""}]`)))
|
||||
host.HTTPMock.On("Send", externalAssetsReq).Return(&host.HTTPResponse{StatusCode: 200, Body: []byte(`[{"external_asset_path":""}]`)}, nil)
|
||||
|
||||
_, err := r.processImage("https://example.com/art.jpg", "client123", "token123", imageCacheTTL)
|
||||
Expect(err).To(HaveOccurred())
|
||||
@@ -332,9 +324,7 @@ var _ = Describe("discordRPC", func() {
|
||||
host.CacheMock.On("GetString", discordImageKey).Return("", false, nil)
|
||||
host.CacheMock.On("SetString", discordImageKey, mock.Anything, mock.Anything).Return(nil)
|
||||
|
||||
httpReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, externalAssetsURL).Return(httpReq)
|
||||
pdk.PDKMock.On("Send", mock.Anything).Return(pdk.NewStubHTTPResponse(200, nil, []byte(`[{"external_asset_path":"external/art"}]`)))
|
||||
host.HTTPMock.On("Send", externalAssetsReq).Return(&host.HTTPResponse{StatusCode: 200, Body: []byte(`[{"external_asset_path":"external/art"}]`)}, nil)
|
||||
|
||||
host.WebSocketMock.On("SendText", "testuser", mock.MatchedBy(func(msg string) bool {
|
||||
return strings.Contains(msg, `"op":3`) &&
|
||||
@@ -364,15 +354,9 @@ var _ = Describe("discordRPC", func() {
|
||||
host.CacheMock.On("GetString", discordImageKey).Return("", false, nil)
|
||||
host.CacheMock.On("SetString", discordImageKey, mock.Anything, mock.Anything).Return(nil)
|
||||
|
||||
trackReq := &pdk.HTTPRequest{}
|
||||
defaultReq := &pdk.HTTPRequest{}
|
||||
|
||||
// First call (track art) returns 500, second call (default) succeeds
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, externalAssetsURL).Return(trackReq).Once()
|
||||
pdk.PDKMock.On("Send", trackReq).Return(pdk.NewStubHTTPResponse(500, nil, []byte(`error`))).Once()
|
||||
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, externalAssetsURL).Return(defaultReq).Once()
|
||||
pdk.PDKMock.On("Send", defaultReq).Return(pdk.NewStubHTTPResponse(200, nil, []byte(`[{"external_asset_path":"external/logo"}]`))).Once()
|
||||
host.HTTPMock.On("Send", externalAssetsReq).Return(&host.HTTPResponse{StatusCode: 500, Body: []byte(`error`)}, nil).Once()
|
||||
host.HTTPMock.On("Send", externalAssetsReq).Return(&host.HTTPResponse{StatusCode: 200, Body: []byte(`[{"external_asset_path":"external/logo"}]`)}, nil).Once()
|
||||
|
||||
host.WebSocketMock.On("SendText", "testuser", mock.MatchedBy(func(msg string) bool {
|
||||
return strings.Contains(msg, `"op":3`) &&
|
||||
@@ -400,9 +384,7 @@ var _ = Describe("discordRPC", func() {
|
||||
It("clears all images when both track art and default fail", func() {
|
||||
host.CacheMock.On("GetString", discordImageKey).Return("", false, nil)
|
||||
|
||||
httpReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, externalAssetsURL).Return(httpReq)
|
||||
pdk.PDKMock.On("Send", mock.Anything).Return(pdk.NewStubHTTPResponse(200, nil, []byte(`{"not":"array"}`)))
|
||||
host.HTTPMock.On("Send", externalAssetsReq).Return(&host.HTTPResponse{StatusCode: 200, Body: []byte(`{"not":"array"}`)}, nil)
|
||||
|
||||
host.WebSocketMock.On("SendText", "testuser", mock.MatchedBy(func(msg string) bool {
|
||||
return strings.Contains(msg, `"op":3`) &&
|
||||
@@ -431,9 +413,7 @@ var _ = Describe("discordRPC", func() {
|
||||
host.CacheMock.On("GetString", discordImageKey).Return("mp:cached/large", true, nil).Once()
|
||||
host.CacheMock.On("GetString", discordImageKey).Return("", false, nil).Once()
|
||||
|
||||
httpReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, externalAssetsURL).Return(httpReq)
|
||||
pdk.PDKMock.On("Send", mock.Anything).Return(pdk.NewStubHTTPResponse(500, nil, []byte(`error`)))
|
||||
host.HTTPMock.On("Send", externalAssetsReq).Return(&host.HTTPResponse{StatusCode: 500, Body: []byte(`error`)}, nil)
|
||||
|
||||
host.WebSocketMock.On("SendText", "testuser", mock.MatchedBy(func(msg string) bool {
|
||||
return strings.Contains(msg, `"large_image":"mp:cached/large"`) &&
|
||||
|
||||
+28
-19
@@ -49,19 +49,23 @@ func spotifyCacheKey(artist, title, album string) string {
|
||||
// trySpotifyFromMBID calls the ListenBrainz spotify-id-from-mbid endpoint.
|
||||
func trySpotifyFromMBID(mbid string) string {
|
||||
body := fmt.Sprintf(`[{"recording_mbid":%q}]`, mbid)
|
||||
req := pdk.NewHTTPRequest(pdk.MethodPost, "https://labs.api.listenbrainz.org/spotify-id-from-mbid/json")
|
||||
req.SetHeader("Content-Type", "application/json")
|
||||
req.SetBody([]byte(body))
|
||||
|
||||
resp := req.Send()
|
||||
status := resp.Status()
|
||||
if status < 200 || status >= 300 {
|
||||
pdk.Log(pdk.LogDebug, fmt.Sprintf("ListenBrainz MBID lookup failed: HTTP %d, body=%s", status, string(resp.Body())))
|
||||
resp, err := host.HTTPSend(host.HTTPRequest{
|
||||
Method: "POST",
|
||||
URL: "https://labs.api.listenbrainz.org/spotify-id-from-mbid/json",
|
||||
Headers: map[string]string{"Content-Type": "application/json"},
|
||||
Body: []byte(body),
|
||||
})
|
||||
if err != nil {
|
||||
pdk.Log(pdk.LogInfo, fmt.Sprintf("ListenBrainz MBID lookup request failed: %v", err))
|
||||
return ""
|
||||
}
|
||||
id := parseSpotifyID(resp.Body())
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
pdk.Log(pdk.LogDebug, fmt.Sprintf("ListenBrainz MBID lookup failed: HTTP %d, body=%s", resp.StatusCode, string(resp.Body)))
|
||||
return ""
|
||||
}
|
||||
id := parseSpotifyID(resp.Body)
|
||||
if id == "" {
|
||||
pdk.Log(pdk.LogDebug, fmt.Sprintf("ListenBrainz MBID lookup returned no spotify_track_id for mbid=%s, body=%s", mbid, string(resp.Body())))
|
||||
pdk.Log(pdk.LogDebug, fmt.Sprintf("ListenBrainz MBID lookup returned no spotify_track_id for mbid=%s, body=%s", mbid, string(resp.Body)))
|
||||
}
|
||||
return id
|
||||
}
|
||||
@@ -69,20 +73,25 @@ func trySpotifyFromMBID(mbid string) string {
|
||||
// trySpotifyFromMetadata calls the ListenBrainz spotify-id-from-metadata endpoint.
|
||||
func trySpotifyFromMetadata(artist, title, album string) string {
|
||||
payload := fmt.Sprintf(`[{"artist_name":%q,"track_name":%q,"release_name":%q}]`, artist, title, album)
|
||||
req := pdk.NewHTTPRequest(pdk.MethodPost, "https://labs.api.listenbrainz.org/spotify-id-from-metadata/json")
|
||||
req.SetHeader("Content-Type", "application/json")
|
||||
req.SetBody([]byte(payload))
|
||||
|
||||
pdk.Log(pdk.LogDebug, fmt.Sprintf("ListenBrainz metadata request: %s", payload))
|
||||
|
||||
resp := req.Send()
|
||||
status := resp.Status()
|
||||
if status < 200 || status >= 300 {
|
||||
pdk.Log(pdk.LogDebug, fmt.Sprintf("ListenBrainz metadata lookup failed: HTTP %d, body=%s", status, string(resp.Body())))
|
||||
resp, err := host.HTTPSend(host.HTTPRequest{
|
||||
Method: "POST",
|
||||
URL: "https://labs.api.listenbrainz.org/spotify-id-from-metadata/json",
|
||||
Headers: map[string]string{"Content-Type": "application/json"},
|
||||
Body: []byte(payload),
|
||||
})
|
||||
if err != nil {
|
||||
pdk.Log(pdk.LogInfo, fmt.Sprintf("ListenBrainz metadata lookup request failed: %v", err))
|
||||
return ""
|
||||
}
|
||||
pdk.Log(pdk.LogDebug, fmt.Sprintf("ListenBrainz metadata response: HTTP %d, body=%s", status, string(resp.Body())))
|
||||
id := parseSpotifyID(resp.Body())
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
pdk.Log(pdk.LogDebug, fmt.Sprintf("ListenBrainz metadata lookup failed: HTTP %d, body=%s", resp.StatusCode, string(resp.Body)))
|
||||
return ""
|
||||
}
|
||||
pdk.Log(pdk.LogDebug, fmt.Sprintf("ListenBrainz metadata response: HTTP %d, body=%s", resp.StatusCode, string(resp.Body)))
|
||||
id := parseSpotifyID(resp.Body)
|
||||
if id == "" {
|
||||
pdk.Log(pdk.LogDebug, fmt.Sprintf("ListenBrainz metadata returned no spotify_track_id for %q - %q", artist, title))
|
||||
}
|
||||
|
||||
+17
-18
@@ -118,6 +118,8 @@ var _ = Describe("Spotify", func() {
|
||||
pdk.ResetMock()
|
||||
host.CacheMock.ExpectedCalls = nil
|
||||
host.CacheMock.Calls = nil
|
||||
host.HTTPMock.ExpectedCalls = nil
|
||||
host.HTTPMock.Calls = nil
|
||||
pdk.PDKMock.On("Log", mock.Anything, mock.Anything).Maybe()
|
||||
})
|
||||
|
||||
@@ -138,10 +140,9 @@ var _ = Describe("Spotify", func() {
|
||||
host.CacheMock.On("SetString", spotifyURLKey, mock.Anything, mock.Anything).Return(nil)
|
||||
|
||||
// Mock the MBID HTTP request
|
||||
mbidReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, "https://labs.api.listenbrainz.org/spotify-id-from-mbid/json").Return(mbidReq)
|
||||
pdk.PDKMock.On("Send", mbidReq).Return(pdk.NewStubHTTPResponse(200, nil,
|
||||
[]byte(`[{"spotify_track_ids":["63OQupATfueTdZMWIV7nzz"]}]`)))
|
||||
host.HTTPMock.On("Send", mock.MatchedBy(func(req host.HTTPRequest) bool {
|
||||
return req.URL == "https://labs.api.listenbrainz.org/spotify-id-from-mbid/json"
|
||||
})).Return(&host.HTTPResponse{StatusCode: 200, Body: []byte(`[{"spotify_track_ids":["63OQupATfueTdZMWIV7nzz"]}]`)}, nil)
|
||||
|
||||
url := resolveSpotifyURL(scrobbler.TrackInfo{
|
||||
Title: "Karma Police",
|
||||
@@ -159,15 +160,14 @@ var _ = Describe("Spotify", func() {
|
||||
host.CacheMock.On("SetString", spotifyURLKey, mock.Anything, mock.Anything).Return(nil)
|
||||
|
||||
// MBID request fails
|
||||
mbidReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, "https://labs.api.listenbrainz.org/spotify-id-from-mbid/json").Return(mbidReq)
|
||||
pdk.PDKMock.On("Send", mbidReq).Return(pdk.NewStubHTTPResponse(404, nil, []byte(`[]`)))
|
||||
host.HTTPMock.On("Send", mock.MatchedBy(func(req host.HTTPRequest) bool {
|
||||
return req.URL == "https://labs.api.listenbrainz.org/spotify-id-from-mbid/json"
|
||||
})).Return(&host.HTTPResponse{StatusCode: 404, Body: []byte(`[]`)}, nil)
|
||||
|
||||
// Metadata request succeeds
|
||||
metaReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, "https://labs.api.listenbrainz.org/spotify-id-from-metadata/json").Return(metaReq)
|
||||
pdk.PDKMock.On("Send", metaReq).Return(pdk.NewStubHTTPResponse(200, nil,
|
||||
[]byte(`[{"spotify_track_ids":["4wlLbLeDWbA6TzwZFp1UaK"]}]`)))
|
||||
host.HTTPMock.On("Send", mock.MatchedBy(func(req host.HTTPRequest) bool {
|
||||
return req.URL == "https://labs.api.listenbrainz.org/spotify-id-from-metadata/json"
|
||||
})).Return(&host.HTTPResponse{StatusCode: 200, Body: []byte(`[{"spotify_track_ids":["4wlLbLeDWbA6TzwZFp1UaK"]}]`)}, nil)
|
||||
|
||||
url := resolveSpotifyURL(scrobbler.TrackInfo{
|
||||
Title: "Karma Police",
|
||||
@@ -184,9 +184,9 @@ var _ = Describe("Spotify", func() {
|
||||
host.CacheMock.On("SetString", spotifyURLKey, mock.Anything, mock.Anything).Return(nil)
|
||||
|
||||
// No MBID, metadata request fails
|
||||
metaReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, "https://labs.api.listenbrainz.org/spotify-id-from-metadata/json").Return(metaReq)
|
||||
pdk.PDKMock.On("Send", metaReq).Return(pdk.NewStubHTTPResponse(500, nil, []byte(`error`)))
|
||||
host.HTTPMock.On("Send", mock.MatchedBy(func(req host.HTTPRequest) bool {
|
||||
return req.URL == "https://labs.api.listenbrainz.org/spotify-id-from-metadata/json"
|
||||
})).Return(&host.HTTPResponse{StatusCode: 500, Body: []byte(`error`)}, nil)
|
||||
|
||||
url := resolveSpotifyURL(scrobbler.TrackInfo{
|
||||
Title: "Karma Police",
|
||||
@@ -203,10 +203,9 @@ var _ = Describe("Spotify", func() {
|
||||
host.CacheMock.On("GetString", spotifyURLKey).Return("", false, nil)
|
||||
host.CacheMock.On("SetString", spotifyURLKey, mock.Anything, mock.Anything).Return(nil)
|
||||
|
||||
metaReq := &pdk.HTTPRequest{}
|
||||
pdk.PDKMock.On("NewHTTPRequest", pdk.MethodPost, "https://labs.api.listenbrainz.org/spotify-id-from-metadata/json").Return(metaReq)
|
||||
pdk.PDKMock.On("Send", metaReq).Return(pdk.NewStubHTTPResponse(200, nil,
|
||||
[]byte(`[{"spotify_track_ids":["4tIGK5G9hNDA50ZdGioZRG"]}]`)))
|
||||
host.HTTPMock.On("Send", mock.MatchedBy(func(req host.HTTPRequest) bool {
|
||||
return req.URL == "https://labs.api.listenbrainz.org/spotify-id-from-metadata/json"
|
||||
})).Return(&host.HTTPResponse{StatusCode: 200, Body: []byte(`[{"spotify_track_ids":["4tIGK5G9hNDA50ZdGioZRG"]}]`)}, nil)
|
||||
|
||||
url := resolveSpotifyURL(scrobbler.TrackInfo{
|
||||
Title: "Some Song",
|
||||
|
||||
Reference in New Issue
Block a user