Aqua
Aqua

Reputation: 41

How to get my bot to get random messages that are already sent from users in a channel and send that random message when an autoresponse is triggered

Like the title says, I tried to use fetchMessages to check the messages a certain channel is sent but when I tried to mess with this, it just gives me unending blocks of information in the console.

I tried reading it but there seems to be no actual message in there and just gives me information about the server, like channel id, member id, their perms, etc.

At first I thought using this method would give me random messages so I could just have the bot send the messages directly to a channel but it gives me an error so I just used console.log to get more information. But that didn't seem the case, or I'm just using it wrong...

Here's the code I'm trying:

    bot.on('message', msg =>{

    if(msg.author.bot) return;
    lowerCase = msg.content.toLowerCase();

    if(lowerCase.includes ("fetch")){ 
        msg.channel.fetchMessages({limit: 1}).then(console.log);
    }
})

Also apparently it can't track old messages since when I tried filtering out messages using a user id, it shows that they sent 0 messages even though they have been sending messages way before? I'm trying to achieve so that it can still read very old messages and still send those when I use an autorespond message.

Upvotes: 4

Views: 1884

Answers (1)

luxmiyu
luxmiyu

Reputation: 615

TextChannel.fetchMessages() can only fetch up to 100 messages at a time

Short Answer:

Although it doesn't show in the docs, if you fetch more than 100, you'll get an API error:

DiscordAPIError: Invalid Form Body
limit: int value should be less than or equal to 100.

Console logging the Message object will indeed give you a whole lot of information regarding the Guild and everything else in it. You should probably want to only console log the message's content and author id/usertag

So if you want to search beyond the past 100 messages, you'll have to continuously fetch 100 messages by using the ID of the oldest message in ChannelLogsQueryOptions's before parameter in each consecutive TextChannel.fetchMessages() call, and then concatinating each Collection together using Collection.concat().


Long Answer:

If you wanted, for example, to fetch the past 200 messages you could write something like this:

// using .then()
await channel.fetchMessages({limit: 100})
.then(first100 => {
  let next100 = await channel.fetchMessages({limit: 100, before: first100.lastKey()})
  .then(next100 => {
    let all200 = first100.concat(next100);
  });
});
// in async function
let first100 = await channel.fetchMessages({limit: 100});
let next100 = await channel.fetchMessages({limit: 100, before: first100.last().id});
let all200 = first100.concat(next100);

Take a look at this answer for an async function that stores past messages in an array.

I made my own version which will give you a Collection and returns it as a proper Promise instead:

const fetchManyMessages = (channel, limit = 200) => {
  return new Promise((resolve, reject) => {
    channel.fetchMessages({limit: limit < 100 ? limit : 100})
    .then(collection => {
      const nextBatch = () => {
        console.log(collection.size);
        let remaining = limit - collection.size;

        channel.fetchMessages({limit: remaining<100 ? remaining : 100, before: collection.lastKey()})
        .then(next => {
          let concatenated = collection.concat(next);

          // resolve when limit is met or when no new msgs were added (reached beginning of channel)
          if (collection.size >= limit || collection.size == concatenated.size) return resolve(concatenated);

          collection = concatenated;
          nextBatch();
        })
        .catch(error => reject(error));
      }

      nextBatch();
    })
    .catch(error => reject(error));
  });
}

Example Usage:

fetchManyMessages(message.channel, 1500)
.then(msgs => console.log(msgs.size))
.catch(err => console.log(err));

And here I've also made a prototype version, which I think is great for some syntactical awesomeness:

Discord.TextChannel.prototype.fetchManyMessages = function (limit = 200) {
  return new Promise((resolve, reject) => {
    this.fetchMessages({limit: limit < 100 ? limit : 100})
    .then(collection => {
      const nextBatch = () => {
        console.log(collection.size);
        let remaining = limit - collection.size;

        this.fetchMessages({limit: remaining<100 ? remaining : 100, before: collection.lastKey()})
        .then(next => {
          let concatenated = collection.concat(next);

          // resolve when limit is met or when no new msgs were added (reached beginning of channel)
          if (collection.size >= limit || collection.size == concatenated.size) return resolve(concatenated);

          collection = concatenated;
          nextBatch();
        })
        .catch(error => reject(error));
      }

      nextBatch();
    })
    .catch(error => reject(error));
  });
}

Example Usage:

message.channel.fetchManyMessages(1500)
.then(msgs => console.log(msgs.size))
.catch(err => console.log(err));

Upvotes: 3

Related Questions