Reputation: 1110
According to the Discord.NET documentation page for the EmbedBuilder
class, the syntax (converted to VB) to add a local image to an EmbedBuilder
object should look something like this:
Dim fileName = "image.png"
Dim embed = New EmbedBuilder() With {
.ImageUrl = $"attachment://{fileName}"
}.Build()
I'm trying to use something like this to add a dynamically created image to the EmbedBuilder
, but I can't seem to get it to work properly. Here's basically what I've got:
Dim TweetBuilder As New Discord.EmbedBuilder
Dim DynamicImagePath As String = CreateDynamicImage()
Dim AttachURI As String = $"attachment:///" & DynamicImagePath.Replace("\", "/").Replace(" ", "%20")
With Builder
.Description = "SAMPLE DESCRIPTION"
.ImageUrl = AttachURI
End With
MyClient.GetGuild(ServerID).GetTextChannel(PostChannelID).SendMessageAsync("THIS IS A TEST", False, Builder.Build)
My CreateDynamicImage
method returns the full path to the locally created image (e.g., C:\Folder\Another Folder\image.png
). I've done a fair amount of "fighting"/testing with this to get past the Url must be a well-formed URI
exception I was initially getting because of the [SPACE]
in the path.
MyClient
is a Discord.WebSocket.SocketClient
object set elsewhere.
The SendMessageAsync
method does send the Embed to Discord on the correct channel, but without the embedded image.
If I instead send the image using the SendFileAsync
method (like so):
MyClient.GetGuild(ServerID).GetTextChannel(PostChannelID).SendFileAsync(DynamicImagePath, "THIS IS A TEST", False, Builder.Build)
the image is sent, but as a part of the message, rather than included as a part of the Embed (this is expected behavior - I only bring it up b/c it was a part of my testing to ensure that there wasn't a problem with actually sending the image to Discord).
I've tried using the file:///
scheme instead of the attachment:///
scheme, but that results in the entire post never making it to Discord at all.
Additionally, I've tried setting the ImageUrl
property to a Web resource (e.g., https://www.somesite.com/someimage.png
) and the Embed looks exactly as expected with the image and everything when it successfully posts to Discord.
So, I'm just wondering at this point if I'm just missing something, or if I'm just doing it completely wrong?
Upvotes: 0
Views: 2096
Reputation: 1110
I cross-posted this to issue #1609 in the Discord.Net GitHub project to get a better idea of what options are available for this and received a good explanation of the issue:
The
Embed
(andEmbedImage
) objects don't do anything with files. They simply pass the URI as configured straight into Discord. Discord then expects a URI in the formattachment://filename.ext
if you want to refer to an attached image.What you need to do is use
SendFileAsync
with the embed. You have two options here:Use
SendFileAsync
with theStream stream, string filename
overload. I think this makes it clear what you need to do: you provide a file stream (viaFile.OpenRead
or similar) and a filename. The provided filename does not have to match any file on disk. > So, for example:var embed = new EmbedBuilder() .WithImageUrl("attachment://myimage.png") .Build(); await channel.SendFileAsync(stream, "myimage.png", embed: embed);
Alternatively, you can use
SendFileAsync
with thestring filePath
overload. Internally, this gets a stream of the file at the path, and setsfilename
(as sent to Discord) to the last part of the path. So it's equivalent to:using var stream = File.OpenRead(filePath); var filename = Path.GetFileName(filePath); await channel.SendFileAsync(stream, filename);
From here, you can see that if you want to use the
string filePath
overload, you need to set embed image URI to something like$"attachment://{Path.GetFileName(filePath)}"
, because the attachment filename must match the one sent to Discord.
I almost had it with my code above, but I misunderstood the intention and usage of the method and property. I guess I thought the .ImageUrl
property somehow "automatically" initiated a Stream
in the background. Additionally, I missed one very important piece:
As it's an async method, you must await (or whatever the VB.NET equivalent is) on SendFileAsync.
So, after making my calling method into an async method, my code now looks like this:
Private Async Sub TestMessageToDiscord()
Dim Builder As New Discord.EmbedBuilder
Dim AttachmentPath As String = CreateDynamicImage() '<-- Returns the full, local path to the created file
With Builder
.Description = "SAMPLE DESCRIPTION"
.ImageUrl = $"attachment://{IO.Path.GetFileName(AttachmentPath)}"
End With
Using AttachmentStream As IO.Stream = IO.File.OpenRead(AttachmentPath)
Await MyClient.GetGuild(ServerID).GetTextChannel(PostChannelID).SendFileAsync(AttachmentStream, IO.Path.GetFileName(AttachmentPath), "THIS IS A TEST", False, Builder.Build)
End Using
End Sub
Now, everything works exactly as expected and I didn't have to resort to uploading the image to a hosting site and using the new URL (I actually had that working before I got the response on GitHub. I'm sure that code won't go to waste).
Okay, so I still ended up going back to my separately hosted image option for one reason: I have a separate event method that modifies the original Embed
object during which I want to remove the image and replace the text. However, when that event fired, while the text was replaced, the image was "moved" to the body of the Discord message. While I may have been able to figure out how to get rid of the image entirely, I decided to "drop back and punt" since I had already worked out the hosted image solution.
Upvotes: 1
Reputation: 178
I've tried everyting I could, but I got stuck at the same point at where you are now. My guesses are that Discord doesn't like the embedded images from https://cdn.discordapp.com/attachments, and only accepts the new files from https://media.discordapp.net. I might be wrong though, this is the way it worked for me.
I believe it's only a visual glitch, as I found if you send a link for an image from cdn.discordapp.com/attchments in your regular Discord client, it bugs out and shows an empty embed for some reason.
That would make sense since the default link used in an embedded image actually starts with https://cdn.discordapp.com/attachments/...
You could solve this issue by using https://media.discordapp.net, but it seems like Discord.net is configured to use the old domain.
Upvotes: 0