clearTimeOut function for not working while using with discord.js - javascript

I am trying to make a bot that deletes a channel ('general') after 10 min after calling execcmd() function but if the msg is sent by someone having 'idofsomeuser' then it should cancel the previous timeout and start the timer again. But it's not working.
function execcmd(msg) {
let ID = msg.author.id
let chan = msg.guild.channels.cache.find(
(channel) => channel.name === 'general'
);
x = 'idofsomeuser'
if (ID == x) {
clearTimeout(x);
ID = setTimeout(() => {
chan.delete();
}, 600000); //10min
} else {
x = setTimeout(() => {
chan.delete();
}, 600000);
}
}
execcmd(msg); //msg is received by client and passed here

Create a closure function in which you store the timeout variable. Doing this enables you to store the timeout safely without having to create a global variable to store it in.
Inside the callback function first check if the id of the author matches. If it does, clear the timeout and set it to null. Then check if the timeout is equal to null and start the timer.
So now the timer will start when the function is called for the first time, and is restarted everytime the user with the id you're looking for is found.
function createClearChannel(channelName, authorId) {
let timeout = null;
const timeoutDuration = 1000 * 60 * 10;
return function (msg) {
const isAuthor = authorId === msg.author.id;
const channel = msg.guild.channels.cache.find(
channel => channel.name === channelName
);
if (isAuthor) {
clearTimeout(timeout);
timeout = null;
}
if (timeout === null) {
timeout = setTimeout(channel.delete, timoutDuration);
}
};
}
To set this up, first call the createClearChannel function and pass the arguments below. Store the result in execcmd and call that function when a message enters.
(You could always omit these parameters and simply hardcode the channel name and id of the user, but by doing this you make the function more flexible so it can be used for other cases as well.)
Important: The createClearChannel should only be called ONCE. So don't create a new execcmd when receives each message, but use the same one everytime.
const execcmd = createClearChannel('general', 'idofsomeuser');
execcmd(msg);

Related

How do I make my discord bot react with ✅ to the last message

I am in the process of programming a counting bot and want the bot to respond to the message with the emoji ✅ for every correct number. The bot was written in js.
I want the bot to respond to the right message with the emoji ✅.
This is the code snippet I have so far:
let count = 1
let timeout
client.on('messageCreate', ({channel, content, member}) => {
// Only do this for the counting channel of course
// If you want to simply make this work for all channels called 'counting', you
// could use this line:
// if (client.channels.cache.filter(c => c.name === 'counting').has(channel.id))
if (channel.id === channelid) {
if (member.user.bot) return
if (Number(content) === count + 1) {
// ...increase the count
count++
if (timeout) clearTimeout(timeout)
// Add a new timeout
timeout = setTimeout(
// This will make the bot count and log all errors
() => channel.send(++count).catch(console.error),
// after 30 seconds
30000
)
// If the message wasn't sent by the bot...
} else if (member.id !== client.user.id) {
// ...send a message because the person stuffed up the counting (and log all errors)
channel.send(`${member} messed up!`).catch(console.error)
// Reset the count
count = 0
// Reset any existing timeout because the bot has counted so it doesn't need to
// count again
if (timeout) clearTimeout(timeout)
} else if (lastMsgAuthor && message.author.id === lastMsgAuthor) {
message.delete();
}
}
});
You should use message.react('✅'). The problem is that there is no message object as you've already destructured it. Instead, you could name the argument message and destructure it as the first thing in your callback, like this:
client.on('messageCreate', (message) => {
const { channel, content, member } = message;
if (channel.id === channelid) {
// ...
And use the message object to send a reaction:
if (Number(content) === count + 1) {
message.react('✅').catch(console.error);
count++;
if (timeout)
clearTimeout(timeout);
// ...
You could also grab the react() method though, like this:
client.on('messageCreate', ({ channel, content, member, react }) => {
if (channel.id === channelid) {
// ...
And then just call react():
if (Number(content) === count + 1) {
react('✅').catch(console.error);
count++;
if (timeout)
clearTimeout(timeout);
// ...

The parameter I'm passing through a async function is undefined in the function

I have an async function that on page load it runs a function that gets a JSON file and stores it in songResults. it then gets a random object from the JSON and takes some parameters from it and uses them to set the sources for some elements in my HTML file. I am having an issue with the callback for the event listener, the parameter I am passing through guessingGame() is undefined inside the guessingGame() function and I'm not sure why. any help would be muchly appreciated.
JS code
//A async function to run when the page loads to get the first song and album cover to display.
const onPageLoad = async () => {
let songResults = await getSongData();
let randomSong = songResults[Math.floor(Math.random() * songResults.length)];
audioSound.src = randomSong.song_path;
audioSound.load();
albumCover.src = randomSong.photo_path;
//An event listener for the submit button to run the guessing game function.
submitButton.addEventListener("click", guessingGame(randomSong.song_path))
};
//async function for when the button is clicked to check the answer in the input box to the json data.
const guessingGame = async (songPath) => {
//get the value of the input box
let input = document.getElementById("guessInputBox").value;
//check if the value of the input box matches the song path in the json data
if (input) {
if (input === songPath) {
alert('correct')
score++;
alert("that took " + score + " attempts");
score = 0;
changeSong();
} else {
alert('incorrect')
alert(songPath);
score++;
};
};
};
What a json file response looks like
{
"song_name": "Listen to Us",
"release_date": "1/05/2012",
"album": "Home Brew",
"photo_path": "/pictures/home-brew.jpg",
"song_path": "/songs/homebrewski-listenToUs.mp3"
}
so the new code updates it kind of it works the first time you guess but the second time you guess it says your incorrect then correct and keeps looping heaps really weird and lags out the browser.
const onPageLoad = async () => {
let songResults = await getSongData();
let randomSong = songResults[Math.floor(Math.random() * songResults.length)];
audioSound.src = randomSong.song_path;
audioSound.load();
albumCover.src = randomSong.photo_path;
//An event listener for the submit button to run the guessing game function.
submitButton.addEventListener("click", () => {
guessingGame(randomSong.song_name);
});
};
//async function for when the button is clicked to check the answer in the input box to the json data.
const guessingGame = async (songPath) => {
//get the value of the input box
let input = document.getElementById("guessInputBox").value;
//check if the value of the input box matches the song path in the json data
if (input) {
if (input.toLowerCase() === songPath.toLowerCase()) {
alert('correct')
score++;
alert("that took " + score + " attempts");
score = 0;
changeSong();
} else {
alert('incorrect')
alert(songPath);
score++;
};
};
};
//need to change this to an async function once figured out how to store data.
const changeSong = async () => {
let songResults = await getSongData();
let randomSong = songResults[Math.floor(Math.random() * songResults.length)];
audioSound.src = randomSong.song_path;
audioSound.load();
albumCover.src = randomSong.photo_path;
submitButton.addEventListener("click", () => {
guessingGame(randomSong.song_name);
});
};
Updated Answer
Thank you for posting more code. It looks like you may have mistakenly passed along the song_name instead of the song_path:
// From the onPageLoad and changeSong functions
guessingGame(randomSong.song_name);
// From the guessingGame function
input.toLowerCase() === songPath.toLowerCase()
Another thing to consider is your click-handler; you're adding one to the submitButton every time a song is loaded. As such, the first time you click the button, a single event handler is called. The second time you click, two are called. The third time, three, etc.
Your submit button behavior really only needs to be set once, and forgotten. It's job is to do one thing: see if the user's selection matches the currently-playing song. And, if the user got the correct answer, load another song:
// Minimal game state
let score = 0;
let songs = [];
let songIndex = -1;
// References to game elements
const submit = document.querySelector("#submit")
const selection = document.querySelector("options");
// Begin game functionality
async function onPageLoad () {
// Load meta data for all songs into `songs`
songs = await getSongData();
// TODO: Populate #options based on `songs` data
setRandomSong();
}
function setRandomSong () {
songIndex = Math.floor( Math.random() * songs.length );
audioSound.src = songs[ songIndex ].path;
albumCover.src = songs[ songIndex ].photo;
}
// This will be called whenever a song is changed
audioSound.addEventListener( "load", function audioLoaded () {
console.log( "Audio has loaded, game can be played." );
});
// We need only a single handler for our guess-button
submit.addEventListener( "click", function guess () {
// Get our values to compare
const guess = selection.value;
const answer = songs[ songIndex ].name;
// Increment the number of attempts
score += 1;
// Check lowercase values for equality
// If the answer is false, share number of attempts
if ( guess.toLowerCase() !== answer.toLowerCase() ) {
alert( `You have guessed ${ score } times.` );
return;
}
// If the answer was correct, reset game state
alert( `Correct! And after ${ score } guesses.` );
score = 0;
setRandomSong();
});
Note, this code is untested, but should clearly define a suitable approach to your problem. Please feel free to engage further within the comments as needed.
Original Answer
The addEventListener method expects a function as the second argument. Look closely at your code:
submitButton.addEventListener("click", guessingGame(randomSong.song_path))
Note that you're executing guessingGame, rather than referencing it. Instead, you'd want to provide another function:
submitButton.addEventListener("click", function () {
guessingGame( randomSong.song_path );
});
Now, when the submitButton is clicked, our anonymous function will be called, which in turn will pass randomSong.song_path to guessingGame.

hello, i wan to know how to use PresenceUpdate but its execute every 5 Minutes - Discord.js

i want to make so my codes only executed every 5 mins:
client.on('presenceUpdate', async (oldPresence, newPresence) => {
const guild = client.guilds.cache.get('707085819839512628')
const rolee = guild.roles.cache.get("707416808835252245")
if(oldPresence.member.user.bot || newPresence.member.user.bot) return;
let oldState = oldPresence.activities[0]?.state
let newState = newPresence.activities[0]?.state
if(oldState === newState) return;
if(newState.includes("https://discord.gg/indos")) {
newPresence.member.roles.add(rolee)
}
})
}, 60000);
example
Good afternoon, what need do you have to execute that code every X seconds? The "Client.on (Event)" function captures all the events related to your search at the moment they are executed...
The error for which the role is not granted may be because you do not have a specific Intent enabled, so make sure to activate them and rerun the code by eliminating the function that runs every X seconds.
client.on('presenceUpdate', async (oldPresence, newPresence) => {
const guild = client.guilds.cache.get('707085819839512628')
const rolee = guild.roles.cache.get("707416808835252245")
if(oldPresence.member.user.bot || newPresence.member.user.bot) return;
let oldState = oldPresence.activities[0]?.state
let newState = newPresence.activities[0]?.state
if(oldState === newState) return;
if(newState.includes("https://discord.gg/url")) {
newPresence.member.roles.add(rolee)
}
})

Discord.js interval is not cleared

I'm using my Discord bot to give members money by updating the database when they enter the voice channel. But even if they leave the voice channel, my bot still runs the function to give them more money. Although I'm using clearInterval, the interval is not cancelled.
client.on('voiceStateUpdate', (oldState, newState) => {
if (!oldState.channelID && newState.channelID) {
oldState.member.roles.add("845279222590472253")
var interval = setInterval(() => {
db2.add(`para_${newState.member.user.id}`, 60)
}, 5000);
}
else if (oldState.channelID && !newState.channelID) {
oldState.member.roles.remove("845279222590472253");
clearInterval(interval)
}
});
The problem is, var is scoped to the function and the variable interval is only available inside the function it's created in.
On every voiceStateUpdate you're calling the callback function that defines a new variable. It means, if someone connects, you start a new interval, the variable interval is only available inside that function. If the same member disconnects, a new voiceStateUpdate event is fired with a new callback function and a new (undefined) interval variable.
Check out the snippet below:
function gimmeMoney(oldState, newState) {
if (!oldState && newState) {
var interval = setInterval(() => console.log('Add money'), 2000)
console.log('Interval started to add money', {
interval
})
} else if (oldState && !newState) {
console.log('Clearing', {
interval
})
// as interval is undefined, you can't clear it
clearInterval(interval)
}
}
console.log('Connect to voice channel')
gimmeMoney(false, true)
console.log('Wait for 6 seconds before we disconnect...')
let timeLeftBeforeClear = 6
const countdown = setInterval(() => {
timeLeftBeforeClear -= 1
console.log()
if (timeLeftBeforeClear <= 0) {
clearInterval(countdown)
console.log('Time to disconnect...')
return gimmeMoney(true, false)
}
}, 1000)
If you run the snippet above, you could see that the interval ID is undefined when you want to clear the interval, so it doesn't do anything and the interval keeps running.
To solve this, you need to store the interval ID outside of the function. You can store these IDs in an object, a map, or a Discord Collection. If you use a collection, you can add a new interval ID to the collection with the member's ID as the key when someone connects. When the same member disconnects, you can get their interval ID by using their member ID.
Check out the working code below:
// create a new collection to store the interval IDs
const intervals = new Discord.Collection();
client.on('voiceStateUpdate', (oldState, newState) => {
if (!oldState.channelID && newState.channelID) {
oldState.member.roles.add('845279222590472253').catch(console.error);
// set up a new interval and grab the returned ID
const interval = setInterval(() => {
db2.add(`para_${newState.member.user.id}`, 60);
}, 5000);
// add a new element in the collection with the member's ID as the key
intervals.set(oldState.member.id, interval);
} else if (oldState.channelID && !newState.channelID) {
oldState.member.roles.remove('845279222590472253').catch(console.error);
// get the interval ID from the collection by the member's ID
const interval = intervals.get(oldState.member.id);
clearInterval(interval);
// don't forget to remove it from the collection too
intervals.delete(oldState.member.id);
}
});

botpress - increment vlaue

I am trying to get a custom action running to simply incrementing a value on passing a specific node on the flow.
My custom actions looks like this:
function action(bp: typeof sdk, event: sdk.IO.IncomingEvent, args: any, { user, temp, session } = event.state) {
/** Your code starts below */
let i = undefined
const p = new Promise((resolve, reject) => {
if (i === undefined) {
resolve((i = 0))
} else if (i >= 0) {
resolve(i + 1)
} else {
reject('i cannot be < 0')
}
})
const runCount = async () => {
try {
const counter = await p
i = counter
return (session.count = counter)
} catch (err) {
console.log(err)
}
}
return runCount()
/** Your code ends here */
}
When I runCount() variable i will be set to 0. But then, after in rerun runCount() it does not increment further.
What do I need to do to save the variable so it increments on every runCount() call.
Greetings
Lorenz
I just managed to solve the problem.
I had to declare i = session.count at the beginning.
Now it gets the value out of the session state and increments the state on every call.
Maybe someone gets some help out of this.
Lorenz

Categories