I've been trying to create a system that automatically sets the slowmode in a channel to a certain amount depending on how many messages have been sent. Lua is my primary language, and not Node.js, therefore I'm having quite a bit of trouble as to how I would go about this. If anyone had any suggestions, please let me know.
Two ways to go about it:
Use discord.js's <TextChannel>.setRateLimitPerUser(number)
https://discord.js.org/#/docs/main/stable/class/TextChannel?scrollTo=setRateLimitPerUser
Not sure if this actually does what you want though, the other option is creating a session storage of the text channels msgCount and compare it to time, i found setRateLimitPerUser in the middle of writing the code so didn't finish it, be here's a start:
const { Client, Collection } = require("discord.js");
const client = new Client();
client.slowdown = new Collection();
client.on("message", msg => {
const id = msg.channel.id;
const attempt = client.slowdown.get(id);
//4 messages at most per second
const ratio = 4;
//look at last how many seconds
const timeSpace = 5;
//TODO: check if channel already has cooldown
if (attempt) {
attempt.msgCount++;
const currentTime = Date.now();
const timePassed = (currentTime - attempt.time) / 1000;
if (attempt.msgCount >= ratio && attempt.msgCount / timePassed >= ratio) {
//setCoolDown
}
if (timePassed >= timeSpace) {
attempt.time = currentTime;
attempt.msgCount = 0;
}
} else {
client.slowdown.set(id, {
time: Date.now(),
msgCount: 1
});
}
});
Related
I'm in the process of debugging the /purge command for my Discord bot.
My intention is to fetch the entirety of a text channel, and delete any amount of messages, by calling the TextChannel.bulkDelete method multiple times, since that method has a limit of deleting 100 messages at a time. This is my code:
async purgeDelete(
channel: TextChannel,
amount: number | undefined,
target: GuildMember | undefined,
keyword: string | undefined
): Promise<number> {
// Most confused about this line: Am I doing the right thing?
const messages = await channel.messages.fetch();
const twoWeeksAgo = new Date();
twoWeeksAgo.setDate(twoWeeksAgo.getDate() - 14);
const purgelist = messages.filter(message => (
(!target || message.author.id === target.id)
&& (!keyword || message.content.includes(keyword))
&& this.resultMessage?.id !== message.id
&& message.createdAt > twoWeeksAgo
));
let purgeAmount: number;
if (amount === undefined) {
purgeAmount = purgelist.size;
} else {
console.log(purgelist.size, messages.size);
purgeAmount = Math.min(amount, purgelist.size);
}
const slicedPurgelist = purgelist.first(purgeAmount);
const partitionedPurgelist = [];
for (let i = 0; i < slicedPurgelist.length; i += 100) {
partitionedPurgelist.push(slicedPurgelist.slice(i, i + 100));
}
await Promise.all(partitionedPurgelist.map(messages => channel.bulkDelete(messages)));
return purgeAmount;
}
I'm pretty sure the only line that matters is the fetch() call. When called in my program, the API is giving me 50 messages. Is that intentional? I know there is an option for limit, but that only goes up to 100. If there is any workarounds to this, please let me know!
The Discord API has a hard limit of 100 messages per GET request. Unfortunately, this is a hard limit you can't bypass, and is intentional on Discord's part.
Furthermore, fetching the entirety of a text channel is probably a bad idea, especially with larger servers which could have 100k+ messages per channel.
A "sort-of" workaround is to use the before param in FetchMessageOptions plus a loop to continue fetching messages. See below for an example:
const messages = [];
const messagesToFetch = 1000
while(messages.length < messagesToFetch) {
// Handle first run
if(!messages.length) {
const msg = await channel.messages.fetch({ limit: 100 })
messages.push(msg)
continue;
}
// Fetch messages before the oldest message in the array
messages.push(await channel.messages.fetch({ limit: 100, before: messages[0].id }))
}
Im trying to make a stopwatch command that when you say !duty on and then !duty off it will calculate the time took to stop it. It works like a regular stopwatch but it is for discord. I have been trying to fix the err for a week but i cant understand why it doesnt work pls help me. The err is in line 10 id where it says message.guild.id
the code:
const Discord = require('discord.js');
const StopWatch = require("timer-stopwatch-dev");
const moment = require('moment');
module.exports = {
name: 'duty',
description: "This is a stopwatch command",
async execute(client, message, args, CurrentTimers) {
try {
let guildTimers = CurrentTimers.get(message.guild.id);
let guildTimersUser = guildTimers.get(message.author.id);
if(!guildTimersUser){ guildTimers.set(message.author.id, new StopWatch()); guildTimersUser = guildTimers.get(message.author.id); };
if(!args[0] || args[0] === 'on'){
if(guildTimersUser.isRunning()) return message.channel.send('You need to stop your shift first!')
guildTimersUser.start();
message.channel.send('You have started your shift')
} else if(args[0] === 'off'){
if(!guildTimersUser.isRunning()) return message.channel.send('You need to start the Stopwatch first!')
guildTimersUser.stop();
message.channel.send(new Discord.RichEmbed().setTitle('You have stopped the Stopwatch!').setDescription('Total Time: ' + dhm(guildTimersUser.ms)).setTimestamp());
}
}
catch(err) {
console.log(err)
}
function dhm(ms){
days = Math.floor(ms / (24*60*60*1000));
daysms=ms % (24*60*60*1000);
hours = Math.floor((daysms)/(60*60*1000));
hoursms=ms % (60*60*1000);
minutes = Math.floor((hoursms)/(60*1000));
minutesms=ms % (60*1000);
sec = Math.floor((minutesms)/(1000));
return days+" days, "+hours+" hours, "+minutes+" minutes, "+sec+" seconds.";
}
}
}
my main:
require('dotenv').config();
//create cooldowns map
const cooldowns = new Map();
module.exports = (Discord, client, message) => {
const prefix = '!';
if(!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).split(/ +/);
const cmd = args.shift().toLowerCase();
const command = client.commands.get(cmd) ||
client.commands.find(a => a.aliases && a.aliases.includes(cmd));
if(command){
//If cooldowns map doesn't have a command.name key then create one.
if(!cooldowns.has(command.name)){
cooldowns.set(command.name, new Discord.Collection());
}
const current_time = Date.now();
const time_stamps = cooldowns.get(command.name);
const cooldown_amount = (command.cooldown) * 1000;
//If time_stamps has a key with the author's id then check the expiration time to send a message to a user.
if(time_stamps.has(message.author.id)){
const expiration_time = time_stamps.get(message.author.id) + cooldown_amount;
if(current_time < expiration_time){
const time_left = (expiration_time - current_time) / 1000;
return message.reply(`Please wait ${time_left.toFixed(1)} more seconds before using ${command.name}`);
}
}
//If the author's id is not in time_stamps then add them with the current time.
time_stamps.set(message.author.id, current_time);
//Delete the user's id once the cooldown is over.
setTimeout(() => time_stamps.delete(message.author.id), cooldown_amount);
}
try{
command.execute(message,args, cmd, client, Discord, CurrentTimers);
} catch (err){
message.reply("There was an error trying to execute this command!");
console.log(err);
}
}
You didn’t show the actual error but I suspect that it is something like Cannot read property 'id' of undefined. The way to fix this is to make sure of 2 things:
Make sure the message is not in DM
Make sure your execution parameters are passed in correctly.
command.execute(client, message, args, CurrentTimers)
//these may not be the same variable names, but make sure the values are correct
TL:DR - I need help using a variable in more than 1 file
Currently I have a bot that counts how many times the word ":p" has been used. It adds that number to the variable "numberofp". On a separate file I want to call the variable on an embed but it says numberofp is undefined. Code is below. If you would like more code just ask!
code for index.js
// variables
var numberofp = 0;
client.on('message', (message) => {
if(message.author.id = 714544589305806868){
if(message.content.includes(':p')){
numberofp = numberofp + 1;
console.log('Porsha_boy said :p, so far it has been sent this many times:', numberofp);
}
}
})
Code for embed
const db = require("quick.db")
const Discord = require('discord.js')
module.exports = {
name: 'rub',
description: 'a command that tells you what your ping is',
execute(message, args, Discord){
// Basic embed
var embed = new Discord.MessageEmbed()
.setAuthor(numberofp)
.setColor("#34BDE1")
console.log('working')
}
}
You need to export the variable to be visible from the module outside:
wordcounter.js
let counter = 0;
function increase(a = 1) {
counter += a;
}
function getCounter() {
return counter;
}
exports.increase = increase;
exports.getCounter = getCounter;
clientone.js
const wc = require('./wordcounter');
wc.increase();
wc.increase(2);
wc.increase(5);
clienttwo.js
const wc = require('./wordcounter');
wc.increase(1);
wc.increase(1);
wc.increase(5);
index.js
const wc = require('./wordcounter');
const c1 = require('./clientone');
const c2 = require('./clienttwo');
console.log(wc.getCounter());
I'm making a function in my bot where when a phrase is sent to the bot, it displays that it's the first user to send that phrase, then the second user, it displays second, and so on. As of now I have the for loop so it displays all numbers 1-3 all at once. I am just having some difficulty creating the function to display one number for each user that sends the message.
For more clarification
Any Help is appreciated, thank you!
Code:
const channel = bot.channels.cache.get('732757852615344139');
channel.updateOverwrite(message.author,{
VIEW_CHANNEL: true,
})
for(let i = 1; i< 4; i++){
let scavWelcome = new Discord.MessageEmbed()
.setTitle('Good Work')
.setDescription(`Welcome ${message.author}, you placed number ${i}`)
channel.send(scavWelcome)
}
}
Set up a global counter variable along with a max count, either by global variable or hoisting to the bot object. Increment the counter on each message. Once the counter reaches max, reset the counter back to 1.
// Under where you defined bot
bot.counter = 1;
bot.maxCount = 4;
bot.on('message', message => {
// Your message event code...
const channel = bot.channels.cache.get('732757852615344139');
channel.updateOverwrite(message.author,{
VIEW_CHANNEL: true
})
if (message.content === 'Phrase Here') {
if (bot.counter === bot.maxCount) bot.counter = 1;
else bot.counter++;
}
let scavWelcome = new Discord.MessageEmbed()
.setTitle('Good Work')
.setDescription(`Welcome ${message.author}, you placed number ${bot.counter}`)
channel.send(scavWelcome);
});
If i understood your question correctly, you could use an array to store the users and get the index of the elements which would correspond to their position
client.on('message', message => {
const userArr = [];
if (message.content.toLowerCase() == 'a phrase') userArr.push(`${message.author.username`);
});
Then you can view the list in appropriate order by doing
for (let i = 0; i < userArr.length; i++) arrWithIndex.push(`${i + 1} ${userArr[i]}`) // i + 1 because index starts with 0, but we're counting from 1
message.channel.send(arrWithIndex.join('\n'));
if i misinterpreted your question, could you please explain it in the comments, ty
I want my bot to respond to commands that are typen with capital letters, but where should I put it, I really don't know... :heh:. So yea where should I put the .toLowercase for my bot to respond to capital letters?
client.on('message', async message => {
if(message.content.startsWith(";stats")){
cpuStat.usagePercent(function (error, percent) {
if (error) {
return console.error(error)
}
const cores = os.cpus().length // Counting how many cores your hosting has.
const cpuModel = os.cpus()[0].model // Your hosting CPU model.
const guild = client.guilds.cache.size.toLocaleString() // Counting how many servers invite your bot. Tolocalestring, meaning separate 3 numbers with commas.
const user = client.users.cache.size.toLocaleString() // Counting how many members in the server that invite your bot.
const channel = client.channels.cache.size.toLocaleString() // Counting how many channels in the server that invite your bot
const Node = process.version // Your node version.
const CPU = percent.toFixed(2) // Your CPU usage.
const d = moment.duration(message.client.uptime);
const days = (d.days() == 1) ? `${d.days()} day` : `${d.days()} days`;
const hours = (d.hours() == 1) ? `${d.hours()} hour` : `${d.hours()} hours`;
const minutes = (d.minutes() == 1) ? `${d.minutes()} minute` : `${d.minutes()} minutes`;
const seconds = (d.seconds() == 1) ? `${d.seconds()} second` : `${d.seconds()} seconds`;
const date = moment().subtract(d, 'ms').format('dddd, MMMM Do YYYY');
const embed = new Discord.MessageEmbed() // Stable or < below than 11.x.x use RichEmbed. More than 12.x.x or Master or https://github.com/discordjs/discord.js/ (github:discordjs/discord.js) use MessageEmbed.
embed.setTitle('Axmy#0102', message.author.displayAvatarURL());
embed.setDescription('Really non-useful bot, I know that everyone hates Axmy')
embed.addField('Servers 🏠', `\n${client.guilds.cache.size}`)
embed.addField('Users 🧑🤝🧑', `${client.guilds.cache.reduce((a, g) => a + g.memberCount, 0)}`)
embed.addField('Uptime <:tired:811194778149715979>', `${days}, ${hours}, ${minutes}, ${seconds}`)
embed.addField("Discord.js Version <:discord:811200194640216094> ", '12.3.1')
embed.addField("CPU Usage <:down:811195966714937395>", ` ${CPU}%`)
embed.addField("Node.js Version <:node:811196465095376896>", `${Node}`)
embed.setColor('PURPLE')
message.channel.send(embed)
})
}
})
A quick solution to your problem is this:
const prefix=";";
client.on('message', async message => {
if (message.author.bot) return;
if (!message.content.toLowerCase().startsWith(prefix)) return;
const args=message.content.slice(prefix.length).trim().split(/ +/g);
const command = args.shift().toLowerCase();
if (command==="stats") {
cpuStat.usagePercent(function (error, percent) {
if (error) {
return console.error(error)
}
//rest of the code...
But I suggest you to learn about command-handling, your codebase will look much better when you seperate commands into seperate files. There are a lot of youtube tutorials about it.