noobami
noobami

Reputation: 39

Ask for file, read and send content to the channel using discord.js/javascript?

I want to ask for a .txt file, read file and send the file content to the channel using a discord bot.

Description of intended behavior:

This is my most recent attempt at creating this command:

if (message.content === '!readfile') {

message.channel.send("Send your file please...");

 message.channel.awaitMessages(filter, {max: 1}).then(msg => {
   const filter = m => m.author.id === message.author.id;
   let file = msg.attachments.first().file;
   fs.readFile(file, (err, data) => {
     msg.channel.send("Read the file! Fetching data...");
     msg.channel.send(data);
   });
 });
}

Upvotes: 1

Views: 688

Answers (1)

Zsolt Meszaros
Zsolt Meszaros

Reputation: 23169

As I've mentioned in a previous post, you can't use the fs module to read the content of the attached files as it only deals with local files.

When you upload a file through Discord, it gets uploaded to a CDN. You can't grab the file itself (and there is no file property on the MessageAttachment either), all you can do is to grab the URL of the uploaded file using the url property.

As you want to get a file from the web, you will need to fetch it by a URL. You can use the built-in https module, or you can install one from npm, like axios, node-fetch, etc.

I used node-fetch in my example and make sure you install it first by running npm i node-fetch in your root folder.

Check out the working code below, it works fine with text files:

// on the top
const fetch = require('node-fetch');

client.on('message', async (message) => {
  if (message.author.bot) return;

  const args = message.content.slice(prefix.length).split(/ +/);
  const command = args.shift().toLowerCase();

  if (command === 'readfile') {
    message.channel.send('Send your file please...');

    const filter = (m) => m.author.id === message.author.id;

    try {
      const collected = await message.channel.awaitMessages(filter, { max: 1 });

      // get the file's URL
      const file = collected.first().attachments.first()?.url;
      if (!file) return console.log('No attached file found');

      // await the message, so we can later delete it
      const sent = await message.channel.send(
        'Reading the file! Fetching data...',
      );

      // fetch the file from the external URL
      const response = await fetch(file);

      // if there was an error send a message with the status
      if (!response.ok) {
        sent.delete();
        return message.channel.send(
          'There was an error fetching your file:',
          response.statusText,
        );
      }

      // take the response stream and read it to completion
      const text = await response.text();

      if (text) {
        sent.delete();
        return message.channel.send(`\`\`\`${text}\`\`\``);
      }
    } catch (err) {
      console.log(err);
      return message.channel
        .send(`Oops, that's lame. There was an error...`)
        .then((sent) => setTimeout(() => sent.delete(), 2000));
    }
  }
});

Also, don't forget that awaitMessages() returns a collection of messages, even if the max option is set to 1, so you will need to grab the first() one.

enter image description here

Upvotes: 1

Related Questions