Discord.js: Asynchronous message Cooldown / Antispam - javascript

I am making a Discord Bot that informs Moderators when a user joins a specific voice channel. The Bot is supposed to also have a spam protection that the bot will only log a message once per minute per user.
This is what I have tried before: 
const { Client } = require("discord.js");
const { config } = require("dotenv");
const fs = require('fs');
const client = new Client({
partials: ['MESSAGE', 'CHANNEL', 'REACTION']
});
config({
path: __dirname + "/.env"
})
var supportchannel = '827574015526567947'
var dutychannel = '847445933969113118'
var ondutyrole = '847447374925398016'
client.on("ready", () => {
console.log(`Hi, ${client.user.username} is now online!`);
global.timer = 0;
client.user.setStatus('online');
client.user.setActivity('me getting developed', { type: "WATCHING"})
.then(presence => console.log('status set'))
.catch(console.error);
});
client.on('voiceStateUpdate', (oldMember, newMember) => {
let newUserChannel = newMember.channelID;
let oldUserChannel = oldMember.channelID;
if(newUserChannel === supportchannel)
{
if (timer == 0){
timer = 1
setTimeout(() => {
timer = 0
}, 60000);
const Userfm = client.users.cache.get(newMember.id);
if (Userfm) {
const channelfx = client.channels.cache.get(dutychannel)
let roleId = ondutyrole
channelfx.send(`<#&${roleId}> **${Userfm.tag}** requires Support`);
}
}else{
return;
}
}
console.log("User joined vc with id "+newUserChannel)
});
client.login(process.env.TOKEN);
This doesn't work the way intended because the cooldown is not separate for every user but sets a countdown that blocks every user from getting the Moderator's attention for 60 seconds (the users all share a cooldown).
I thought that the code ran asynchronously for every user.
The same goes for this code in which I made use of the wait-sync npm library:
const { Client } = require("discord.js");
const { config } = require("dotenv");
const fs = require('fs');
const waitSync = require('wait-sync');
const client = new Client({
partials: ['MESSAGE', 'CHANNEL', 'REACTION']
});
config({
path: __dirname + "/.env"
})
var supportchannel = '827574015526567947'
var dutychannel = '847445933969113118'
var ondutyrole = '847447374925398016'
client.on("ready", () => {
console.log(`Hi, ${client.user.username} is now online!`);
global.timer = 0;
client.user.setStatus('online');
client.user.setActivity('me getting developed', { type: "WATCHING"})
.then(presence => console.log('status set'))
.catch(console.error);
});
client.on('voiceStateUpdate', (oldMember, newMember) => {
let newUserChannel = newMember.channelID;
let oldUserChannel = oldMember.channelID;
if(newUserChannel === supportchannel)
{
const Userfm = client.users.cache.get(newMember.id);
if (Userfm) {
const channelfx = client.channels.cache.get(dutychannel)
let roleId = ondutyrole
channelfx.send(`<#&${roleId}> **${Userfm.tag}** requires Support`);
waitSync(60);
}
}
console.log("User joined vc with id "+newUserChannel)
});
client.login(process.env.TOKEN);
If you know how to solve this problem please let me know.
Thanks in advance ;)

What you can do is probably to have some sort of mapping that keeps track of the timer for each user and have the user IDs be the keys:
const timers = {};
client.on('voiceStateUpdate', (oldMember, newMember) => {
...
// If we don't have any timer set for this user, go ahead and set it
if (!timers[newMember.id]) {
timers[newMember.id] = 1;
setTimeout(() => {
// Delete the timer from the mapping
delete timers[newMember.id];
}, 60000);
...

Related

Cannot read properties of undefined (reading '______')

Anything that I change to make this code work just changes said undefined thing.
I have tried to fix using multiple different answers, but no luck.
// Require the necessary discord.js classes
const { Client, GatewayIntentBits, message } = require('discord.js');
const { token } = require('./config.json');
const guildId = '1009548907015057460';
const channelId = '1009548907702915245';
// Create a new client instance
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
// When the client is ready, run this code (only once)
client.once('ready', () => {
console.log('Ready!');
});
client.on('interactionCreate', async interaction => {
if (!interaction.isChatInputCommand()) return;
const { commandName } = interaction;
if (commandName === 'invite') {
const guild = await client.guilds.fetch(guildId);
console.log(guild);
const channel = await guild.channels.cache.get(channelId);
let invite = await guild.channel.createInvite(
{
maxAge: 300000,
maxUses: 1,
},
'${message.author.tag} requested a invite',
).catch(console.log);
await interaction.deferReply({ ephemeral: true });
await interaction.editReply(invite ? 'Join: ${invite}' : 'Error');
}
}
Anything can help.
You don't need to fetch the guild, you can get the channel from the client
There's no need for await when you're getting information from cache
guild.channel.createInvite should be channel.createInvite
You're using single quotes for variables, they'll end up being strings
There's no need for invite to use let when the value doesn't change
Defer the reply at the beginning rather than right before replying
message.author.tag would return undefined, message doesn't exist. Use interaction.user.tag instead
Add await to channel.createInvite as it returns a promise
Replace ${invite} with ${invite.url}
Also it's best to store the token in a .env file rather than a JSON one.
// Require the necessary discord.js classes
const { Client, GatewayIntentBits, message } = require('discord.js');
const { token } = require('./config.json');
const channelId = '1009548907702915245';
// Create a new client instance
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
// When the client is ready, run this code (only once)
client.once('ready', () => {
console.log('Ready!');
});
client.on('interactionCreate', async (interaction) => {
if (!interaction.isChatInputCommand()) return;
await interaction.deferReply({ ephemeral: true });
const { commandName } = interaction;
if (commandName === 'invite') {
const channel = client.channels.cache.get(channelId);
const invite = await channel.createInvite({
maxAge: 604800, // 1 week
maxUses: 1,
reason: `${interaction.user.tag} requested an invite`
}).catch(console.log);
interaction.editReply(invite ? `Join: ${invite.url}` : 'Error');
}
}
Resolving the promise works. This is the code after:
// Require the necessary discord.js classes
const { Client, GatewayIntentBits, message } = require('discord.js');
const { token } = require('./config.json');
const channelId = '1009548907702915245';
// Create a new client instance
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
// When the client is ready, run this code (only once)
client.once('ready', () => {
console.log('Ready!');
});
client.on('interactionCreate', async (interaction) => {
if (!interaction.isChatInputCommand()) return;
await interaction.deferReply({ ephemeral: true });
const { commandName } = interaction;
if (commandName === 'invite') {
const channel = client.channels.cache.get(channelId);
const invite = channel.createInvite({
maxAge: 604800, // 1 week
maxUses: 1,
reason: `${interaction.user.tag} requested an invite`
})
.catch(console.log);
const promise = Promise.resolve(invite);
promise.then((value) => {
interaction.editReply(`Join: ${value}`);
});
}
}

I want my discord bot to send a random message to a text room given by user [by channel id or channel name]

so what I am trying to do is when a user write a command such as
!setchannel #test or !setchannel 86xxxxxxxxxxxxxxx
then the bot will send the random messages to that channel every certain time.
Note that I did the random messages code but I still stuck on creating the !setchannel command.
I am using discord.js v12.5.3
index.js main file
require('events').EventEmitter.prototype._maxListeners = 30;
const Discord = require('discord.js')
const client = new Discord.Client()
require('discord-buttons')(client);
const ytdl = require('ytdl-core');
const config = require('./config.json')
const mongo = require('./mongo')
const command = require('./command')
const loadCommands = require('./commands/load-commands')
const commandBase = require('./commands/command-base')
const { permission, permissionError } = require('./commands/command-base')
const cron = require('node-cron')
const zkrList = require('./zkr.json')
const logo =
'URL HERE'
const db = require(`quick.db`)
let cid;
const { prefix } = config
client.on('ready', async () => {
await mongo().then((mongoose) => {
try {
console.log('Connected to mongo!')
} finally {
mongoose.connection.close()
}
})
console.log(`${client.user.tag} is online`);
console.log(`${client.guilds.cache.size} Servers`);
console.log(`Server Names:\n[ ${client.guilds.cache.map(g => g.name).join(", \n ")} ]`);
loadCommands(client)
cid = db.get(`${message.guild.id}_channel_`)
cron.schedule('*/10 * * * * *', () => {
const zkrRandom = zkrList[Math.floor(Math.random() * zkrList.length)]
const zkrEmbed = new Discord.MessageEmbed()
.setDescription(zkrRandom)
.setAuthor('xx', logo)
.setColor('#447a88')
client.channels.cache.get(cid).send(zkrEmbed);
})
client.on("message", async message => {
if (message.author.bot) {
return
}
try {if (!message.member.hasPermission('ADMINISTRATOR') && message.content.startsWith('!s')) return message.reply('you do not have the required permission') } catch (err) {console.log(err)}
if (!message.content.startsWith(prefix)) return;
const args = message.content.slice(prefix.length).trim().split(/ +/g)
const cmd = args[0]
if (cmd === "s") {
let c_id = args[1]
if (!c_id) return message.reply("you need to mention the text channel")
c_id = c_id.replace(/[<#>]/g, '')
const channelObject = message.guild.channels.cache.get(c_id);
if (client.channels.cache.get(c_id) === client.channels.cache.get(cid)) return message.reply(`we already sending to the mentioned text channel`);
if (client.channels.cache.get(c_id)) {
await db.set(`${message.guild.id}_channel_`, c_id); //Set in the database
console.log(db.set(`${message.guild.id}_channel_`))
message.reply(`sending to ${message.guild.channels.cache.get(c_id)}`);
cid = db.get(`${message.guild.id}_channel_`)
const zkrRandom = zkrList[Math.floor(Math.random() * zkrList.length)]
const zkrEmbed = new Discord.MessageEmbed()
.setDescription(zkrRandom)
.setAuthor('xx', logo)
.setColor('#447a88')
client.channels.cache.get(cid).send(zkrEmbed);
} else {
return message.reply("Error")
}
}
})
})
client.login(config.token)
zkr.json json file
[
"message 1",
"message 2",
"message 3"
]
You'll have to use a database to achieve what you're trying to do
An example using quick.db
const db = require(`quick.db`)
const prefix = "!"
client.on("message", async message => {
if (!message.content.startsWith(prefix)) return;
const args = message.content.slice(prefix.length).trim().split(/ +/g)
const cmd = args[0]
if (cmd === "setchannel") {
let c_id = args[1]
if (!c_id) return message.reply("You need to mention a channel/provide id")
c_id = c_id.replace(/[<#>]/g, '')
if (client.channels.cache.get(c_id)) {
await db.set(`_channel_`, c_id) //Set in the database
} else {
return message.reply("Not a valid channel")
}
}
})
Changes to make in your code
client.on('ready', async () => {
let c_id = await db.get(`_channel_`)
cron.schedule('*/10 * * * * *', () => {
const zkrRandom = zkrList[Math.floor(Math.random() * zkrList.length)]
const zkrEmbed = new Discord.MessageEmbed()
.setTitle('xx')
.setDescription(zkrRandom)
.setFooter("xx")
.setColor('#447a88')
.setAuthor('xx#8752')
client.channels.cache.get(c_id).send(zkrEmbed)
})
})
The above sample of quick.db is just an example
If you're using repl.it, I recommend you to use quickreplit
Edit
require('events').EventEmitter.prototype._maxListeners = 30;
const Discord = require('discord.js')
const client = new Discord.Client()
const ytdl = require('ytdl-core');
const config = require('./config.json')
const mongo = require('./mongo')
const command = require('./command')
const loadCommands = require('./commands/load-commands')
const commandBase = require('./commands/command-base')
const cron = require('node-cron')
const zkrList = require('./zkr.json')
const db = require(`quick.db`)
const prefix = "!"
let cid;
client.on('ready', async () => {
await mongo().then((mongoose) => {
try {
console.log('Connected to mongo!')
} finally {
mongoose.connection.close()
}
})
console.log(`${client.user.tag} is online`);
console.log(`${client.guilds.cache.size} Servers`);
console.log(`Server Names:\n[ ${client.guilds.cache.map(g => g.name).join(", \n ")} ]`);
cid = db.get('_channel_')
loadCommands(client)
//commandBase.listen(client);
})
cron.schedule('*/10 * * * * *', () => {
const zkrRandom = zkrList[Math.floor(Math.random() * zkrList.length)]
const zkrEmbed = new Discord.MessageEmbed()
.setTitle('xx')
.setDescription(zkrRandom)
.setFooter("xx")
.setColor('#447a88')
.setAuthor('xx#8752')
client.channels.cache.get(cid).send(zkrEmbed);
})
client.on("message", async message => {
console.log(db.get('_channel_'))
if (!message.content.startsWith(prefix)) return;
const args = message.content.slice(prefix.length).trim().split(/ +/g)
const cmd = args[0]
if (cmd === "s") {
let c_id = args[1]
if (!c_id) return message.reply("You need to mention a channel/provide id")
c_id = c_id.replace(/[<#>]/g, '')
if (client.channels.cache.get(c_id)) {
console.log('old channel')
console.log(db.get('_channel_'))
await db.set(`_channel_`, c_id); //Set in the database
message.reply(`sending in this channel ${message.guild.channels.cache.get(c_id)}`);
} else {
return message.reply("Not a valid channel")
}
}
})

Make discord bot join a vc using an id from json file

So I want my bot for everytime it boots up I want it to join a specific vc and to play some music! Although, I have come accross a problem. I tried doing this with an id and it worked fine but doing it with json causes some errors and keeps saying that it can't join of undefined. Here is my code:
Processor:
const ytdl = require('ytdl-core-discord');
const editJsonFile = require("edit-json-file");
var fs = require('file-system');
var path = require('path');
const ytfps = require('ytfps');
const prefix = "v_";
let value = true;
let temp;
exports.run = async (client, message, args, ops) => {
const idchannel = client.channels.cache.find(channel => channel.id === "815183065843499008");
const ytchannel = client.channels.cache.find(channel => channel.id === "815183091244597248");
let song = editJsonFile(`live/song.json`);
song.save();
let channelid = editJsonFile(`live/channelid.json`);
song.save();
let count = editJsonFile(`live/count.json`);
count.save();
let cloud = editJsonFile(`live/could.json`);
cloud.save();
let v = count.get(`v`);
let check = cloud.get(`${v}`);
let ope = channelid.get(`${v}`);
if (ope == undefined){
setTimeout(function() {
delete require.cache[require.resolve(`./liveplay.js`)];
let commandFile = require(`./liveplay.js`);
commandFile.run(client, message);
}, 1000);
}
const voiceChannel = client.channels.cache.find(channel => channel.id === `${ope}`);
if (voiceChannel == undefined){
setTimeout(function() {
delete require.cache[require.resolve(`./liveplay.js`)];
let commandFile = require(`./liveplay.js`);
commandFile.run(client, message);
}, 1000);
}
console.log(`${ope}`);
setTimeout(async function() {
try {
console.log("BIP");
setTimeout(async function() {
connection = await voiceChannel.join();
}, 100);
} catch (error) {
console.log(error);
const embed = {
"url": "https://discordapp.com",
"color": 16747962,
"fields": [
{
"name": "🛑 Error ",
"value": "There was an error connecting to the voice channel!"
}
]
};
return message.channel.send({ embed });
}
}, 5000);
setTimeout(async function() {
let ope2 = song.get(`${v}`);
dispatcher = connection.play(await ytdl(ope2), { type: 'opus' })
.on('finish', () => {
voiceChannel.leave();
})
.on('error', error => {
console.log(error);
});
dispatcher.setVolumeLogarithmic(5 / 5);
}, 7000);
count.set(`v`, v-1);
count.save();
v = count.get(`v`);
if (v < 0){
count.set(`v`, v+1);
count.save();
} else {
setTimeout(function() {
delete require.cache[require.resolve(`./liveplay.js`)];
let commandFile = require(`./liveplay.js`);
commandFile.run(client, message);
}, 8000);
}
}
Here is the join command where it actually works:
const ytdl = require('ytdl-core-discord');
const editJsonFile = require("edit-json-file");
var fs = require('file-system');
var path = require('path');
const ytfps = require('ytfps');
const prefix = "v_";
exports.run = async (client, message, args, ops) => {
var value = false;
let number = editJsonFile(`premium/premium.json`);
number.save();
let count = editJsonFile(`premium/count.json`);
count.save();
let v = count.get(`v`)
for(var i = 0; i <= v; i++){
let check = number.get(`${i}`)
if (check == message.author.id){
value = true;
}
}
if(value == false){
return message.channel.send("You do not have premium so you cant run this command");
} else {
args = message.content.substring(prefix.length).split(" ");
const voiceChannel = client.channels.cache.find(channel => channel.id === "809466736491233294");
try {
setTimeout(async function() {
connection = await voiceChannel.join();
}, 500);
} catch(e) {
console.log(e);
}
}
}
EDIT: ope is suppose to equal to the channel id!
i might not be right on this but it seems like your not properly catching the error!
it says that the channel is undefined, that can mean a lot of things. maybe you gave a wrong channel id, maybe a wrong guild id, only way to know for sure is to closely check your code for typos.
as for the error catching, try this:
const channel = client.channels.cache.get("ChannelIDhere");
if (!channel) return console.error("The channel does not exist!");
channel.join().then(connection => {
// Yay, it worked!
console.log("Successfully connected.");
}).catch(e => {
// Oh no, it errored! Let's log it to console :)
console.error(`Failed to connect to the channel! Error:\n${e}`
oh and you forgot to put var before you defined connection
If you wanna export the data from a json file you need to do editJsonFile = require('edit-json-file') then channel.id === ${editJsonFilewhat.channelid} or what ever u define the vc as in json file
in this example in the json file is
{
"channelid":"815183065843499008"
}

Invite Channel Notification Discord.js

So i am coding a bot , in Node.js with Visual Studio Code. I want to have a channel, that when a user joins the guild , will send 'Welcome user and invited by thisuser(Total Invites: 5)
The code is :
module.exports = (client) => {
const invites = {} // { guildId: { memberId: count } }
const getInviteCounts = async (guild) => {
return await new Promise((resolve) => {
guild.fetchInvites().then((invites) => {
const inviteCounter = {} // { memberId: count }
invites.forEach((invite) => {
const { uses, inviter } = invite
const { username, discriminator } = inviter
const name = `${username}#${discriminator}`
inviteCounter[name] = (inviteCounter[name] || 0) + uses
})
resolve(inviteCounter)
})
})
}
client.guilds.cache.forEach(async (guild) => {
invites[guild.id] = await getInviteCounts(guild)
})
client.on('guildMemberAdd', async (member) => {
const { guild, id } = member
const invitesBefore = invites[guild.id]
const invitesAfter = await getInviteCounts(guild)
console.log('BEFORE:', invitesBefore)
console.log('AFTER:', invitesAfter)
for (const inviter in invitesAfter) {
if (invitesBefore[inviter] === invitesAfter[inviter] - 1) {
const channelId = '731801004462571602'
const channel = guild.channels.cache.get(channelId)
const count = invitesAfter[inviter]
channel.send(
`Please welcome <#${id}> to the Discord! Invited by ${inviter} (${count} invites)`
)
invites[guild.id] = invitesAfter
return
}
}
})
}
This code works perfectly with console but i am facing a problem,never post the message in the channel!
The message might not be being sent because of the channel ID double check you are using the right channel ID and you might want to try changing
const channel = guild.channels.cache.get(channelId) to this
const channel = client.channels.cache.get(channelId)

receive audio form a user with discord bot

I'm working on a discord project and in that project i need to record a user voice, i'm following this document.
so far this is what i wrote:
const fs = require('fs');
const Discord = require('discord.js');
const client = new Discord.Client();
client.once('ready', () => {
console.log('Ready!');
});
client.on('message', async message => {
if (message.content === 'a' && message.member.voice.channel) {
const connection = await message.member.voice.channel.join();
const audio = connection.receiver.createStream('user_id?', { mode: 'pcm' });
audio.pipe(fs.createWriteStream('user_audio'));
}
});
client.login('token');
but the problem is that always the user_audio file is empty!
This is a bug in discord.js, to solve this problem we need to play an audio...
const fs = require('fs');
const Discord = require('discord.js');
const client = new Discord.Client();
const { Readable } = require('stream');
const SILENCE_FRAME = Buffer.from([0xF8, 0xFF, 0xFE]);
class Silence extends Readable {
_read() {
this.push(SILENCE_FRAME);
this.destroy();
}
}
client.once('ready', () => {
console.log('Ready!');
});
client.on('message', async message => {
if (message.content === 's' && message.member.voice.channel) {
const connection = await message.member.voice.channel.join();
const audio = connection.receiver.createStream(message, { mode: 'pcm', end: 'manual' });
audio.pipe(fs.createWriteStream('user_audio'));
connection.play(new Silence(), { type: 'opus' });
console.log(message.member.user.id);
}
});
client.login('token');

Categories