How can I edit a embed message on interval? - javascript

var dateTime = time+' '+date;
const boosterembed = new Discord.RichEmbed()
.setTitle("Boosters")
.setColor('#ff0000')
.setDescription("Last Time updated: " + dateTime)
.setTimestamp()
setInterval(function(){guild.channels.get('740327839177375765').message.channel.fetchMessages('740327893103673466').edit(boosterembed)}, 1000)
Why is this not working? Can't add more (looks like your post is mostly code)

I'm assuming you're using Discord.js v11.
First, fetchMessages is for fetching multiple messages from a channel. You'll want to use fetchMessage instead. Second, you use edit to edit a message. Third, a channel does not have a message property, so guild.channels.get(...).message.channel will throw an error.
setInterval(
() =>
guild.channels.get('740327839177375765').fetchMessage('740327893103673466')
.then(message => message.edit(boosterembed))
// This catches all errors and logs them to stop unhandled promise rejections
.catch(console.error),
1000
)
// Or with async/await:
setInterval(
async () => {
try {
const message = await guild.channels.get('740327839177375765').fetchMessage('740327893103673466')
await message.edit(boosterembed)
} catch (error) {
console.error(error)
}
},
1000
)

This answer is adapted from cherryblossom's answer, make sure you upvote it.
function getDate() {
var today = new Date();
var date = today.getDate()+'/'+(today.getMonth()+1)+'/'+today.getFullYear();
var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
return time + ' ' + date;
}
setInterval(
() =>
bot.channels.get('740327839177375765').fetchMessage('740327893103673466')
.then(message => message.edit(new Discord.RichEmbed(boosterembed).setDescription('Last Time updated: ' + getTime())))
// This catches all errors and logs them to stop unhandled promise rejections
.catch(console.error),
1000
)
// Or with async/await:
setInterval(
async () => {
try {
const message = await bot.channels.get('740327839177375765').fetchMessage('740327893103673466')
await message.edit(new Discord.RichEmbed(boosterembed).setDescription('Last Time updated: ' + getTime()))
} catch (error) {
console.error(error)
}
},
1000
)

Related

Enabling and disabling command in JavaScript discord.js

I'm trying to make an automemes command, I can get it to send memes automatically, but when I try to disable it, it sends the Automemes disabled! command, but it still sends them. Here's the code:
const { SlashCommandBuilder } = require("#discordjs/builders");
const fetch = (...args) => import("node-fetch").then(({default: fetch}) => fetch(...args));
module.exports = {
data: new SlashCommandBuilder()
.setName("automemes")
.setDescription("Sends random memes every 5 minutes (from r/memes)")
.addBooleanOption(option =>
option.setName("enabled")
.setDescription("Set the automemes to on/off")
.setRequired(true)),
async execute(client, interaction, Discord) {
let isEnabled = interaction.options.get("enabled").value;
switch (isEnabled) {
case true: interaction.reply("Automemes enabled! " + ENV.CATKISS)
break;
case false: isEnabled = false;
break;
}
async function sendMemes() {
fetch("https://meme-api.herokuapp.com/gimme/memes")
.then(res => res.json())
.then(async json => {
const Embed = new Discord.MessageEmbed()
.setTitle(json.title)
.setImage(json.url)
if (Embed.title.length > 256) return;
await interaction.channel.send({embeds: [Embed]});
});
}
isEnabled? setInterval(() => sendMemes(), 10000) : interaction.reply("Automemes disabled! " + ENV.CATKISS);
}
}
I see what you're trying to accomplish but, as stated above by #Zsolt Meszaros, your interval is never getting cleared. That means that if that interval gets activated once, it will continue perpetually until your bot shuts down. Try declaring your interval as a constant so you can enable and disable it however you choose.
const myInterval = setInterval(sendMemes, 10000) //declaring interval
async fucntion startInterval() {
myInterval; //function to start interval
}
async function disableInterval() {
clearInterval(myInterval); //function to clear interval
interaction.reply(interaction.reply("Automemes disabled! " + ENV.CATKISS));
}
isEnabled? startInterval() : disableInterval(); //added starter and stopper functions
}
}

Discord Js cannot read property titles of undefined

When creating a random number generator for a discord bot I'm working on whenever someone does +nhr it'll either work or it'll come up with an error message in console saying
TypeError: Cannot read property 'titles' of undefined
and
Unhandled promise rejection. This error originated either by throwing
inside of an async function without a catch block, or by rejecting a
promise which was not handled with .catch(). To terminate the node
process on unhandled promise rejection, use the CLI flag
Does anyone know how to fix this bug?
Code:
if (message.content.startsWith(prefix + 'nhr')) {
//RANDOM PREFIX
var rnumber = Math.floor(Math.random() * 1000000) + 1;
if (message.channel.nsfw) {
api.fetchDoujin(`${rnumber}`).then((doujin) => {
const exampleEmbed = new Discord.MessageEmbed()
.setColor('#ce0606')
.setTitle(doujin.titles.pretty)
.setURL(`https://youtube.com/${rnumber}`)
.addFields(
{ name: 'Digits', value: `${rnumber}` },
{
name: 'Tags',
value: doujin.tags.all.map((tag) => tag.name).join(', '),
},
)
.setImage(doujin.cover.url)
.setFooter('x', 'x');
message.channel.send(exampleEmbed);
});
} else {
const exampleEmbed = new Discord.MessageEmbed()
.setColor('#ffc0cb')
.setTitle('**x**')
.setImage('x');
message.channel.send(exampleEmbed);
}
}
(If anything else is needed within the code please comment)
It seems you're using the nhentai npm package. The problem is you're generating a random number between 1 and 1,000,000 and the current largest ID is something a bit over 360,000. Whenever you're generating a number larger, fetchDoujin() resolves to undefined so you'll need to check if doujin exists.
You should always handle promise rejections. If a method can throw an error you need to catch it. Either use try/catch blocks, or after the .then() method add a .catch() method too.
It's probably a good idea to add a max number that is closer to the last ID.
if (message.content.startsWith(prefix + 'nhr')) {
let LAST_ID = 360000;
//RANDOM PREFIX
let rnumber = Math.floor(Math.random() * LAST_ID) + 1;
if (message.channel.nsfw) {
api
.fetchDoujin(`${rnumber}`)
.then((doujin) => {
if (!doujin)
return message.channel.send(`Oops, the random ID ${rnumber} is not valid...`);
let exampleEmbed = new Discord.MessageEmbed()
.setColor('#ce0606')
.setTitle(doujin.titles.pretty)
.setURL(`https://youtube.com/${rnumber}`)
.addFields(
{ name: 'Digits', value: `${rnumber}` },
{
name: 'Tags',
value: doujin.tags.all.map((tag) => tag.name).join(', '),
},
)
.setImage(doujin.cover.url)
.setFooter('x', 'x');
message.channel.send(exampleEmbed);
})
.catch((err) => {
message.channel.send('Oops, there was an error');
console.log(err);
});
} else {
let exampleEmbed = new Discord.MessageEmbed()
.setColor('#ffc0cb')
.setTitle('**x**')
.setImage('x');
message.channel.send(exampleEmbed);
}
}
If you still want to use the nhentai-js library you used in your other question, make sure you're passing down a string to nhentai.getDoujin() (as numbers don't have a .replace() method):
if (message.content.startsWith(prefix + 'nhr')) {
let LAST_ID = 360000;
let chosenNum = Math.floor(Math.random() * LAST_ID) + 1;
if (message.channel.nsfw) {
try {
const res = await nhentai.getDoujin(chosenNum.toString());
const embed = new MessageEmbed()
.setColor('#ce0606')
.setTitle(res.title)
.setImage(res.pages[0])
.setURL(res.link)
.addField('Pages', res.details.pages[0], true)
.addField('Uploaded', res.details.uploaded[0], true)
.setFooter('x', 'x');
if (res.details.languages)
embed.addField('Languages', res.details.languages.join(', '), true);
if (res.details.characters)
embed.addField(
'Top characters',
res.details.characters.slice(0, 10).join(', '),
true,
);
if (res.details.tags)
embed.addField(
'Top tags',
res.details.tags.slice(0, 10).join(', '),
true,
);
return message.channel.send(embed);
} catch (err) {
console.log(err);
return message.channel.send(
'Oops, there was an error. Maybe try again?!',
);
}
} else {
const embed = new MessageEmbed()
.setColor('#ffc0cb')
.setTitle('**x**');
return message.channel.send(embed);
}
}

Cannot stop setTimeout function using clearTimeout because value is null for some reason

In my react-native app, I'm trying to stop setTimeout using clearTimeout. I save an instance of the setTimeout in a global variable.
let timeoutId:any = null;
const doOtp = ()=>{
if(canSendOtp) {
setCanSendOtp(false);
timeoutId = setTimeout(() => { // it has here a numeric value
showNotificationMessage("You can request OTP again")
setCanSendOtp(true)
}, SEND_OTP_TIME_CONSTRAINTS)
// rest of doOtp logic
}
else {
showNotificationMessage("Please wait " + (SEND_OTP_TIME_CONSTRAINTS / 1000) + " seconds before trying again")
}
}
Then when I want to stop the setTimeout using clearTimeout, I see that the value of timeoutId is null. I don't understand why it's happening.
const doLogin = () => {
issueToken(LOGIN_GRANT_TYPE, LOGIN_CLIENT_ID, LOGIN_CLIENT_SECRET, phoneNumber, otp)
.then(res => {
console.log('timeoutId !== null' + timeoutId !== null)
if(timeoutId !== null) { // value here is null - why?
clearTimeout(timeoutId)
}
store().dispatch(setTokenValidity(res))
})
.catch(err => {
showNotificationMessage('Error, something went wrong check logs.')
console.log("issueToken error: " + JSON.stringify(err))
});
}
PROBLEM
setCanSendOtp(true) updates your state which initializes your timeout to null again.
SOLUTION
Put your timeout in Ref. Ref values are persistent across re-renders and state-updates.
const timeoutId:any = React.useRef(null);
const doOtp = ()=>{
if(canSendOtp) {
setCanSendOtp(false);
timeoutId.current = setTimeout(() => { // it has here a numeric value
showNotificationMessage("You can request OTP again")
setCanSendOtp(true)
}, SEND_OTP_TIME_CONSTRAINTS)
// rest of doOtp logic
}
else {
showNotificationMessage("Please wait " + (SEND_OTP_TIME_CONSTRAINTS / 1000) + " seconds before trying again")
}
}
const doLogin = () => {
issueToken(LOGIN_GRANT_TYPE, LOGIN_CLIENT_ID, LOGIN_CLIENT_SECRET, phoneNumber, otp)
.then(res => {
if(timeoutId.current !== null) {
clearTimeout(timeoutId.current)
}
store().dispatch(setTokenValidity(res))
})
.catch(err => {
showNotificationMessage('Error, something went wrong check logs.')
console.log("issueToken error: " + JSON.stringify(err))
});

Is there a way to send a TimeOut object from a step to an other in a dialog? - botBuilder v4 - Node.js

In one of my bot's dialog steps I'am lanching some operations in a setTimeout() function.
The goal is to clear that TimeOut in an other step in some conditions.
async saveAdults(step) {
if (step.result) {
step.values.adults = step.result;
const convId = step.context.activity.conversation.id;
const format = "dddd DD MMMM YYYY";
// Send partial notification in case of a delay of 5 minutes
const data = {
checkIn: step.values.checkIn,
nights: step.values.nights,
adults: "",
children: ""
};
const timer = await sendPartialNotification(convId, data);
// step.values.timer = timer;
this.notificationProp.set(step.context, timer);
await this.conversationState.saveChanges(step.context);
}
return await step.next();
}
exports.sendPartialNotification = async (convId, data) => {
const interval = 300000;
const timer = setTimeout(() => {
notify(convId, this.id, data, true);
}, interval);
return timer;
};
async notifyClient(step) {
const timer = this.notificationProp.get(step.context);
clearTimeout(timer);
// …
}
Trying to store the TimeOut object in step.values.timer or in the conversation state throws this error that indicates that it is not possible to parse the Timeout Object ...
TypeError: Converting circular structure to JSON
As solution to this, I was thinking about storing the timer in Redis ..
Is there any ideas? Thanks.
Use state, props, or equivalent to pass the value from one step to the next. In my example code below, I include a middle step asking if the client would like to cancel. This is purely for displaying output for the solution.
Initiate the timer in a lead step.
async setTimer(step) {
if (step.result) {
const convId = step.context.activity.conversation.id;
const data = {
value1: someValue1,
value2: someValue2
};
const timer = await sendPartialNotification(convId, data);
this.notificationProp = { step: step.context, timer: timer };
await this.conversationState.saveChanges(step.context);
}
return await step.next();
}
Ask the client, in an intermediary step, if they would like to cancel the timer. I have the timer set for 10 secs.
If the user cancels, the timer is cleared.
If the client declines or fails to respond before 10 secs is up, the timer is unaffected and executes.
async askClient(step) {
const timer = this.notificationProp.timer;
if (timer._idleTimeout > 0) {
const message = MessageFactory.text(
'Cancel the timer?',
null,
'expectingInput'
);
return await step.prompt('confirmPrompt', message);
}
}
Lastly, output results and notify the client.
async notifyClient(step) {
const stepResult = step.result;
step.value = { timer: this.notificationProp.timer };
if (stepResult === true) {
console.log('TIMER PRE-CLEAR ', step.value.timer);
const timer = step.value.timer;
await clearTimeout(timer);
console.log('TIMER POST-CLEAR', timer);
step.context.sendActivity('Cancelling timer');
} else {
step.context.sendActivity('Timer not cancelled');
}
return await step.next();
}
Timer not cancelled and executes:
Timer cancelled:
Hope of help!

Fetch a message (by ID) and edit it

I'm trying to edit a message the bot sent, in a different function.
const msg = message.channel.fetchMessage(msgId);
msg.edit(embed);
Didn't work because msg.edit is not a function.
message.channel.messages.fetch({around: "352292052538753025", limit: 1})
.then(messages => {
messages.first().edit("test");
});
Didn't work because .fetch is not a function.
function update(msgId, time, channelid, prize, winnersInt, message) {
setTimeout(function(){
let gtime = time/3600000 + " hours remaining!";
if(time < 3600000) {
gtime = time/60000 + " minuets remaining!";
}
console.log(gtime + "p: " + prize);
let embed = new Discord.RichEmbed()
.setColor("#7289da")
.setTitle("Giveaway!")
.addField('Prize: ', prize)
.addField('Amount of winners: ', winnersInt)
.addField('Time: ', gtime)
const msg = message.channel.fetchMessage(msgId);
msg.edit(embed);
time - 60000;
if(time > 0) {
update(msgId, time, channel, prize, winnersInt, message);
}
}, 60000);
}
I expect the message to be edited.
Old publication but may help those currently looking for it.
For V.13 it can be used this way:
<#Channel>.messages.fetch('messageID').then(msg => msg.edit('newMessage'))
I tested it that way and it worked perfectly.
Got it working.
Used this:
message.channel.fetchMessages({around: msgId, limit: 1})
.then(msg => {
const fetchedMsg = msg.first();
fetchedMsg.edit(embed);
});

Categories