fix: truncate long activity fields before sending to Discord
Apply truncateText to Name, Details, State, and LargeText fields. Apply truncateURL to DetailsURL, StateURL, LargeURL, and SmallURL fields. This prevents Discord from silently rejecting the entire presence update. Fixes #16
This commit is contained in:
@@ -224,6 +224,18 @@ func (r *discordRPC) processImage(imageURL, clientID, token string, ttl int64) (
|
||||
func (r *discordRPC) sendActivity(clientID, username, token string, data activity) error {
|
||||
pdk.Log(pdk.LogInfo, fmt.Sprintf("Sending activity for user %s: %s - %s", username, data.Details, data.State))
|
||||
|
||||
// Truncate text fields to Discord's 128-character limit
|
||||
data.Name = truncateText(data.Name)
|
||||
data.Details = truncateText(data.Details)
|
||||
data.State = truncateText(data.State)
|
||||
data.Assets.LargeText = truncateText(data.Assets.LargeText)
|
||||
|
||||
// Omit URLs that exceed Discord's 256-character limit
|
||||
data.DetailsURL = truncateURL(data.DetailsURL)
|
||||
data.StateURL = truncateURL(data.StateURL)
|
||||
data.Assets.LargeURL = truncateURL(data.Assets.LargeURL)
|
||||
data.Assets.SmallURL = truncateURL(data.Assets.SmallURL)
|
||||
|
||||
// Try track artwork first, fall back to Navidrome logo
|
||||
usingDefaultImage := false
|
||||
processedImage, err := r.processImage(data.Assets.LargeImage, clientID, token, imageCacheTTL)
|
||||
|
||||
+43
@@ -435,6 +435,49 @@ var _ = Describe("discordRPC", func() {
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("truncates long text fields and omits long URLs", func() {
|
||||
host.CacheMock.On("GetString", discordImageKey).Return("mp:cached/art", true, nil).Once()
|
||||
host.CacheMock.On("GetString", discordImageKey).Return("mp:cached/logo", true, nil).Once()
|
||||
|
||||
longName := strings.Repeat("N", 200)
|
||||
longTitle := strings.Repeat("T", 200)
|
||||
longArtist := strings.Repeat("A", 200)
|
||||
longAlbum := strings.Repeat("B", 200)
|
||||
longURL := "https://example.com/" + strings.Repeat("x", 237)
|
||||
|
||||
host.WebSocketMock.On("SendText", "testuser", mock.MatchedBy(func(msg string) bool {
|
||||
// Text fields should be truncated to 128 runes (127 + "…")
|
||||
truncatedName := strings.Repeat("N", 127) + "…"
|
||||
truncatedTitle := strings.Repeat("T", 127) + "…"
|
||||
truncatedArtist := strings.Repeat("A", 127) + "…"
|
||||
truncatedAlbum := strings.Repeat("B", 127) + "…"
|
||||
return strings.Contains(msg, truncatedName) &&
|
||||
strings.Contains(msg, truncatedTitle) &&
|
||||
strings.Contains(msg, truncatedArtist) &&
|
||||
strings.Contains(msg, truncatedAlbum) &&
|
||||
!strings.Contains(msg, longURL) // URL should be omitted
|
||||
})).Return(nil)
|
||||
|
||||
err := r.sendActivity("client123", "testuser", "token123", activity{
|
||||
Application: "client123",
|
||||
Name: longName,
|
||||
Type: 2,
|
||||
Details: longTitle,
|
||||
DetailsURL: longURL,
|
||||
State: longArtist,
|
||||
StateURL: longURL,
|
||||
Assets: activityAssets{
|
||||
LargeImage: "https://example.com/art.jpg",
|
||||
LargeText: longAlbum,
|
||||
LargeURL: longURL,
|
||||
SmallImage: navidromeLogoURL,
|
||||
SmallText: "Navidrome",
|
||||
SmallURL: longURL,
|
||||
},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("clearActivity", func() {
|
||||
|
||||
Reference in New Issue
Block a user