0

Right now I'm working on making a bot that will post a random image from a local folder on my VSC. However, posting an embed message with the image results in an error:

DiscordAPIError: Invalid Form Body embeds[0].image.url: Could not interpret "{'attachment': ['1.jpg', '2mkjR-3__400x400.jpg', '8921036_sa.jpg', '91Vk1mS1x3L.png'], 'name': None}" as string.

This can be reproduced with the sample code:

const Discord = require('discord.js');
const { Intents } = Discord;
const fs = require('fs');

const config = require('config');
const authToken = config.get('authToken');

const myIntents = new Intents([
    Intents.FLAGS.GUILDS,
    Intents.FLAGS.GUILD_MESSAGES
]);
const client = new Discord.Client({ intents: myIntents });

client.on("ready", (client) => {
    console.log(`Logged in as ${client.user.tag}.`);
});

client.on("messageCreate", (message) => {
    if ('.pic' === message.content) {
        let files = fs.readdirSync('./assets/images/');
        let chosenFile = files[Math.floor(Math.random() * files.length)];
        const image = new Discord.MessageAttachment(files);
        const embed = new Discord.MessageEmbed()
              .setTitle('yeet')
              .setImage(image)
              .setFooter('By K4STOR','');
        message.channel.send({embeds: [embed]});
    }
});

client.login(authToken);

In addition to the above script, you'll need to:

  • create an 'assets/images' directory and
  • add at least one image;
  • create a configuration file (e.g. 'config/local.json') and
  • add an appropriate 'authToken' entry

How can the above code be fixed to send the image?

outis
  • 75,655
  • 22
  • 151
  • 221
Sky
  • 47
  • 5
  • 1
    Please add the error you get when trying or what is the expected behavior vs what you get. – Gvinfinity Nov 04 '21 at 03:18
  • You're using `readFilesSync` to find the files in a directory. You need to use `readdirSync` [How do you get a list of the names of all files present in a directory in Node.js?](https://stackoverflow.com/questions/2727167/how-do-you-get-a-list-of-the-names-of-all-files-present-in-a-directory-in-node-j) – Samathingamajig Nov 04 '21 at 03:23
  • @Samathingamajig I did that and now Im getting an error stating "embed.image.url: Could not interpret "{'attachment': ['1.jpg', '2mkjR-3__400x400.jpg', '8921036_sa.jpg', '91Vk1mS1x3L.png'], 'name': None}" as string." – Sky Nov 04 '21 at 03:28
  • @Sky readdirSync returns an array of all the files in the folder. You can not use an array as source for your image. – Christoph Blüm Nov 04 '21 at 16:18
  • @Sky: information relevant to the question should be edited into the question, rather than left in [comments](https://stackoverflow.com/help/privileges/comment). – outis Nov 05 '21 at 00:32
  • @Sky: Note that, in general, you shouldn't change a question for a new issue but should post a new question instead. However, as your original question would have been closed, rewriting it is acceptable. This is because SO is a Q&A site, not a forum. All information (such as error messages) should be added to the question (as explained in the [site guidelines](https://stackoverflow.com/help/how-to-ask)), not left as [comments](https://stackoverflow.com/help/privileges/comment). For one thing, a question should be understandable without reading comments. – outis Nov 05 '21 at 03:19
  • ... Also, your most recent code did not produce the error you showed since you passed embed directly to `message.channel.send()`, which resulted in an error about the message being empty (as per the API, the `send()` argument should either be a string, a `MessageOptions` or a `MessagePayload`). It also referred to various undefined symbols. While most (e.g. `Discord`, `fs`) were standard parts of node.js and discord.js, `command` was not, and implementing it to make the code work is not a trivial task. [Sample code](https://stackoverflow.com/help/mcve) should be complete and representative. – outis Nov 05 '21 at 03:36
  • Does this answer your question? "[How do I use a local image on a discord.js rich embed?](https://stackoverflow.com/q/51199950/90527)", "[Discord.js random image](https://stackoverflow.com/q/49677884/90527)", "[Getting an array from folder and sending a random file with discord.js](https://stackoverflow.com/q/50851030/90527)" – outis Nov 05 '21 at 19:29

2 Answers2

0

Try this:

var fs = require('fs');

client.on("ready", () => {
    
    console.log("Why did I make this...")

    command(client, 'pic', (message) => {
        //choose one file from folder "./images" randomly
        var files = fs.readdirSync("./images/")
        let chosenFile = files[Math.floor(Math.random() * files.length)]
 
        //create embed and use image from messageAttachments
        const embed = new Discord.MessageEmbed()
            .setTitle('yeet')
            .setImage(`attachment://${chosenFile}`)
            .setFooter('By K4STOR','')

        //discord.js V13 variant of sending embeds
        //necessary to set files, otherwise #setImage with localfile does not work
        message.channel.send({
          embeds: [embed], 
          files: [`./images/${chosenFile}`]
        });
    })
})

Christoph Blüm
  • 925
  • 1
  • 9
  • 23
0

Main Issue

MessageEmbed.setImage() takes a URL, not a MessageAttachment. For attachments, you must pass them via the files option TextChannel.send(). Note the guide on attaching images to an embed message shows this.

Additionally, the path to the image directory must be combined with the chosen file name when the attachment object is created.

Minor issue

Note that all images appear in the error message. This is due to a minor issue: the attachment is set to files, rather than chosenFile. Note this sort of issue is considered on SO.

Changes

Just these changes would look like:

const path = require('path');
...
const imgDir = './assets/images/';
...
        const image = new Discord.MessageAttachment(
            path.join(imgDir, chosenFile),
            chosenFile,
            {url: 'attachment://' + chosenFile});
        const embed = new Discord.MessageEmbed()
              .setImage(image.url)
              ...
        
        message.channel.send({embeds: [embed], files: [image]});

Full Sample

The sample with the above changes applied would be:

const Discord = require('discord.js');
const { Intents } = Discord;
const fs = require('fs');
const path = require('path');

const config = require('config');
const authToken = config.get('authToken');

const myIntents = new Intents([
    Intents.FLAGS.GUILDS,
    Intents.FLAGS.GUILD_MESSAGES
]);
const client = new Discord.Client({ intents: myIntents });

client.on("ready", (client) => {
    console.log(`Logged in as ${client.user.tag}.`);
});

const imgDir = './assets/images/';
client.on("messageCreate", (message) => {
    if ('.pic' === message.content) {
        let files = fs.readdirSync(imgDir);
        let chosenFile = files[Math.floor(Math.random() * files.length)];
        const image = new Discord.MessageAttachment(
            path.join(imgDir, chosenFile),
            chosenFile,
            {url: 'attachment://' + chosenFile});
        const embed = new Discord.MessageEmbed()
              .setTitle('yeet')
              .setImage(image.url)
              .setFooter('By K4STOR','');
        console.log(`Sending ${chosenFile}.`);
        message.channel.send({embeds: [embed], files: [image]});
    }
});

client.login(authToken);
outis
  • 75,655
  • 22
  • 151
  • 221