From be211c2ef10405d9b6eda5927658276f2746205c Mon Sep 17 00:00:00 2001 From: Akayashuu Date: Tue, 4 Aug 2026 19:51:33 +0200 Subject: [PATCH] feat(embeds): surface an embed image's proxy_url MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An embed's image url is wherever the picture really lives — for a link preview that is a third-party site. Discord mirrors it on its own CDN and reports that copy as proxy_url. A reader that pins downloads to Discord hosts needs the mirror, not the original, or every previewed image is off-allowlist. --- messages_test.go | 5 ++++- types.go | 9 ++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/messages_test.go b/messages_test.go index 0cf2195..4ada609 100644 --- a/messages_test.go +++ b/messages_test.go @@ -81,7 +81,7 @@ func TestMessagesGetUsesTheDefaultChannel(t *testing.T) { func TestMessageDecodesEmbeds(t *testing.T) { s := transport.NewStub().Reply(`{"id":"m1","content":"","embeds":[{ "title":"Quest failed","description":"stack trace here","url":"https://example.test/run/1", - "image":{"url":"https://cdn.example.test/shot.png"}, + "image":{"url":"https://cdn.example.test/shot.png","proxy_url":"https://media.discordapp.net/external/shot.png"}, "thumbnail":{"url":"https://cdn.example.test/thumb.png"}, "fields":[{"name":"env","value":"prod"}]}]}`) got, err := msgs(s, "def").Get(context.Background(), "c", "m1") @@ -98,6 +98,9 @@ func TestMessageDecodesEmbeds(t *testing.T) { if e.Image == nil || e.Image.URL != "https://cdn.example.test/shot.png" { t.Errorf("image = %+v", e.Image) } + if e.Image.ProxyURL != "https://media.discordapp.net/external/shot.png" { + t.Errorf("proxy url = %q", e.Image.ProxyURL) + } if e.Thumbnail == nil || e.Thumbnail.URL != "https://cdn.example.test/thumb.png" { t.Errorf("thumbnail = %+v", e.Thumbnail) } diff --git a/types.go b/types.go index 5adbe20..0957e51 100644 --- a/types.go +++ b/types.go @@ -30,10 +30,13 @@ type Attachment struct { Size int `json:"size"` } -// EmbedMedia is an image carried by an embed. Only the URL is surfaced: it is -// what a reader needs to fetch the picture. +// EmbedMedia is an image carried by an embed. URL is where the picture actually +// lives, which for a link preview is a third-party site; ProxyURL is Discord's +// own copy of it and is present whenever Discord could fetch it. A reader that +// only trusts Discord hosts wants ProxyURL, falling back to URL. type EmbedMedia struct { - URL string `json:"url"` + URL string `json:"url"` + ProxyURL string `json:"proxy_url"` } // EmbedField is one name/value pair in an embed's body.