Lua Discord webhook bugged image dont display

240 Views Asked by At

When I try to upload an image through a Discord webhook with the following code below everything works except Discord is not uploading my file correct on there server. When I click on "image.png" or try to download it, then it takes me to this link which is invalid https://cdn.discordapp.com/attachments/1086674608368931027/1149816147466780672/image.png. I know it's 99% my fault and not Discord's but I just can't find the bug. Would be nice if someone here could help me :D Screenshot of the Discord channel This is the image that I try to send (before I uploaded it it was .png now it is .jpg I dont know why)

function base64_encode(data)
    local b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    return ((data:gsub('.', function(x)
        local r, b = '', x:byte()
        for i = 8, 1, -1 do
            r = r .. (b % 2 ^ i - b % 2 ^ (i - 1) > 0 and '1' or '0')
        end
        return r
    end) .. '0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
        if #x < 6 then
            return ''
        end
        local c = 0
        for i = 1, 6 do
            c = c + (x:sub(i, i) == '1' and 2 ^ (6 - i) or 0)
        end
        return b64chars:sub(c + 1, c + 1)
    end) .. (#data % 3 == 1 and '==' or #data % 3 == 2 and '=' or ''))
end

function sendDiscordWebhook(webhookUrl, message, imageFilePath)
    local boundary = "----------------------------" .. os.time()

    local headers = {
        ["Content-Type"] = "multipart/form-data; boundary=" .. boundary
    }

    local body = {}
    table.insert(body, "--" .. boundary)
    table.insert(body, 'Content-Disposition: form-data; name="content"\r\n\r\n' .. message)

    local imageFileData
    if imageFilePath then
        local file = io.open(imageFilePath, "rb")
        if file then
            imageFileData = file:read("*all")
            file:close()
            local fileName = imageFilePath:match("^.+[\\/](.+)$")
            local fileExtension = fileName:match("%.([^%.]+)$")
            local contentType = "image/" .. fileExtension
            table.insert(body, "--" .. boundary)
            table.insert(body, 'Content-Disposition: form-data; name="file[0]"; filename="' .. fileName .. '"')
            table.insert(body, 'Content-Type: ' .. contentType)
            table.insert(body, "")
            table.insert(body, "data:" .. contentType .. ";base64," .. base64_encode(imageFileData))
        end
    end

    table.insert(body, "--" .. boundary .. "--")
    local requestBody = table.concat(body, "\r\n")

    PerformHttpRequest(webhookUrl, function(err, text, headers)
        print("TEXT:" .. text)
        print("ERROR:" .. err)
        print("HEADERS:" .. json.encode(headers))
    end, 'POST', requestBody, headers)
end

sendDiscordWebhook("https://discord.com/api/webhooks/MYWEBHOOK/MYWEBHOOK", "Test", "image.png")

I now try for over 2 month to get this to work with thausands of code modifications but I think that Im just to dumb.

2

There are 2 best solutions below

1
Motta On

It looks like the issue you're facing might be related to the way you're encoding and sending the image data in your Lua Discord webhook code. Here's a modified version of your code that should properly handle the image attachment:

function sendDiscordWebhook(webhookUrl, message, imageFilePath)
local boundary = "---------------------------" .. os.time()

local headers = {
    ["Content-Type"] = "multipart/form-data; boundary=" .. boundary
}

local body = {}
table.insert(body, "--" .. boundary)
table.insert(body, 'Content-Disposition: form-data; name="content"\r\n\r\n' .. message)

if imageFilePath then
    local fileName = imageFilePath:match("^.+[\\/](.+)$")
    local fileExtension = fileName:match("%.([^%.]+)$")
    local contentType = "image/" .. fileExtension

    table.insert(body, "--" .. boundary)
    table.insert(body, 'Content-Disposition: form-data; name="file"; filename="' .. fileName .. '"')
    table.insert(body, 'Content-Type: ' .. contentType)
    table.insert(body, "")

    local imageFileData
    local file = io.open(imageFilePath, "rb")
    if file then
        imageFileData = file:read("*all")
        file:close()
        table.insert(body, imageFileData)
    else
        print("Failed to open the image file: " .. imageFilePath)
        return
    end
end

table.insert(body, "--" .. boundary .. "--")
local requestBody = table.concat(body, "\r\n")

PerformHttpRequest(webhookUrl, function(err, text, headers)
    if err == 200 then
        print("Message sent successfully!")
    else
        print("Failed to send message. Error code: " .. err)
    end
end, 'POST', requestBody, headers)
0
Mey On

First of all, thanks for sharing your code. I was in the same boat as you for the whole day yesterday. Now, I think the problem is that the methods used for decoding the base64 string data is incorrect. I've also tried so many decoding functions none of the seemed to work. Thankfully, there's just a simple solution.

Solution

We just need to take your base64 image data url and filter out the unneeded gibberish.

This should remove the data:image/png;base64... part.

-- Unsure about your data string variable name so I made one up
local commaAt = imageDataString:find(",")
local formattedImageString = imageDataString:sub(commaAt + 1)

Then add this to set the encoding language to parse base64 so that we don't need to use any decoders.

table.insert(body, 'Content-Disposition: form-data; name="file"; filename="' .. fileName .. '"')
table.insert(body, 'Content-Type: ' .. contentType)

-- Insert this line to your code
table.insert(body, 'Content-Transfer-Encoding: base64')
table.insert(body, "")
table.insert(body, formattedImageString)

This should work. I've tried and tested this and it worked like a charm. Don't forget the step wherein you omit the unnecessary part of the base64 url, otherwise your webhook won't send at all, which will let you know something's not right.

Cheers!