How to add a cooldown on discord.js?

719 Views Asked by At

I don't know how to add cooldown in discord.js but only for 1 command, for example : /buy count: 100, if user call the command again will activate the cooldown, 'sorry you have to wait 5minute to execute this command again'

Can you help me to make a cooldown? Like the syntax and the position to place it

2

There are 2 best solutions below

0
Apollo24 On

A simple way to set up cooldowns would be to store their user IDs in a set and remove it after 5 minutes. When the user ID is already in the set, you send the notification.

const buyCooldown = new Set();


// Check if the user is on cooldown
if (buyCooldown.has(interaction.user.id)) return interaction.reply(`Sorry you have to wait 5 minutes to execute this command again.`);

// Otherwise add cooldown
buyCooldown.add(interaction.user.id);
setTimeout(() => buyCooldown.delete(interaction.user.id), 5*60*1000);

Note that this is a very simple implementation and the cooldowns would be reset if you restart your bot. If you don't want that you'll have to store it along with a timestamp in your database and check if it's been 5 minutes since.

0
YetNT On

Not sure if you have found your answer but here is how I do it. This does assume that

  1. You are in an asynchronous environment
  2. you use MongoDB,
  3. you've got a cooldowns model,
  4. it looks like this:
const { Schema, model } = require('mongoose')

const cdSchema = new Schema({
    userId: {
        type: String,
        required: true
    },
    COMMAND_NAME: {
        type: Date,
        default: new Date(0)
    }
})
module.exports = model('cooldown', cdSchema)

Your command's file -

const { Interaction, EmbedBuilder } = require('discord.js')
const { newCooldown, checkCooldown } = require('path-to-file/cooldown.js')

// place all checks here, like an if to check if a user has enough money, has permissions etc.

// Pass in the Interaction and EmbedBuilder into the command
const cooldownResult = await checkCooldown(COMMAND_NAME, Interaction, EmbedBuilder);
if (cooldownResult === 0) {
   return;
}

/*
the code here
*/

// Don't forget to pass interaction again
await newCooldown(TIME, interaction, COMMAND_NAME)

Then where the magic is, cooldown.js -

const { Interaction, EmbedBuilder } = require('discord.js')
const Cooldown = require('../models/Cooldown'); // the path to the Cooldown model
/* const strToMilli = require('../utils/strToMilli') */ //code that turns strings like '9d' to 777600000 ms

/**
 * 
 * @param {any} time Can be a string like '2min' or '9d'
 * @param {Interaction} interaction 
 * @param {String} name The command's name
 * @returns 
 */
const newCooldown = async (time, interaction, name) => {
    let query = {
      userId: interaction.user.id
    };
    let date = Date.now();
    let cooldown = await Cooldown.findOne(query);
  
    if (cooldown && cooldown[name] && cooldown[name].getTime() > date) {
      return;
    }
  
    let cooldownTime;
    /* if (typeof time == "string") {
      cooldownTime = strToMilli(time);
    } else */ if (typeof time == "integer") {
      cooldownTime = time;
    } else {
      throw `ERROR. What is "${time}"?`;
    }
  
    if (cooldown) {
      cooldown[name] = new Date(date + cooldownTime);
      await cooldown.save();
    } else {
      const newCooldown = new Cooldown({
        ...query,
        [name]: new Date(date + cooldownTime)
      });
      await newCooldown.save();
    }
};
  


/**
 * 
 * @param {String} name The command's name
 * @param {Interaction} interaction 
 * @param {EmbedBuilder} EmbedBuilder
 * @returns 
 */
const checkCooldown = async (name, interaction, EmbedBuilder) => {
    let query = {
        userId: interaction.user.id
    }
    let date = Date.now()

    let cooldown = await Cooldown.findOne(query)

    if (cooldown && cooldown[name]) {
        let remainingTime = cooldown[name] - date
        let endTime = Math.floor((Date.now() + remainingTime) / 1000);
        if ( remainingTime > 0 ) {
            interaction.editReply({
                embeds: [
                    new EmbedBuilder()
                        .setTitle("Cooldown")
                        .setDescription(`Slow down bro. This command has a cooldown, you will be able to run this command <t:${endTime}:R>`)
                        .setColor("Random")
                ]
            })
            return 0;
        }
    } else {
        return
    }

}

module.exports = { newCooldown, checkCooldown }

Yeah and from there you can edit the embed (or remove the embed entirely, up to you). Here is an example of use of this code in one of my projects : https://github.com/Yetity/y2b/blob/main/src/commands/economy-earn/daily.js . And if you'd like to implement strToMilli here is the file :

module.exports = (input) => {
    var ar = input.match(/[a-zA-Z]+|[0-9]+/g)
    if (ar[1] == "s" || ar[1] == "seconds") { return +ar[0] * 1000; }
    if (ar[1] == "min" || ar[1] == "minutes" || ar[1] == "mins") { return +ar[0] * 60000; } 
    if (ar[1] == "h" || ar[1] == "hour" || ar[1] == "hours") { return +ar[0] * 3.6e+6; } 
    if (ar[1] == "d" || ar[1] == "day" || ar[1] == "days") { return +ar[0] * 8.64e+7; } 
    if (ar[1] == "w" || ar[1] == "week" || ar[1] == "weeks") { return +ar[0] * 6.048e+8; }
    if (ar[1] == "m" || ar[1] == "month" || ar[1] == "months") { return +ar[0] * 2.628e+9; }
}