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);
}
}
Related
The code below adds a document into the current user's friends collection and the target user's friends collection. This part is working fine, but I'm having an issue with returning a value to the client. I've ensured that the client code is working fine, but I don't quite yet understand Typescript well enough to know what I'm doing wrong here.
What the code currently does:
The code returns 69 and the current user's uid.
What the code needs to do:
The code needs to return the appropriate return values based on wherever it ends up. In the Firebase console, I see that the code executes all the way up to the line console.log('_addFriend Finished adding friend.'). The two lines after that assign return values 1 and Friend request sent!, but the client doesn't receive these values. Why isn't the code returning these?
exports.addFriend = functions.https.onCall(async (data, context) => {
console.log('_addFriend: ');
const uid1 = context?.auth?.uid as string //current user
const targetUser = data.targetUser
var username1: string = ''
var returnVal: number = 69
var returnMsg: string = uid1
if (uid1) {
var uid2: string;
const currentUsersFriendsColl = 'friends_' + uid1
await TS_doesUserExist(targetUser)
.then(result => {
if (result[0] == 1) {
console.log('_addFriend: targetUser ', targetUser, ' exists.')
uid2 = result[1]
const targetUsersFriendsColl = 'friends_' + uid2
TS_getUserInfo('uid', uid1, 'username')
.then(getUserInfo_result => {
console.log('_addFriend getUserInfo_result is about to be evaluated')
console.log('_addFriend getUserInfo_result[0]: ', getUserInfo_result[0])
if (getUserInfo_result[0] == 1) {
console.log('_addFriend getUserInfo_result[0]=1')
username1 = getUserInfo_result[1]
//Insert into current user's friends list
const currentUserDoc = admin.firestore().collection(currentUsersFriendsColl).doc();
currentUserDoc.set({
createDate: admin.firestore.FieldValue.serverTimestamp(),
modifiedDate: admin.firestore.FieldValue.serverTimestamp(),
stat: 2, //pending
friendUID: uid2,
friendUsername: targetUser,
})
.then(() => {
console.log('_addFriend: About to insert into target users friends collection')
//Insert into target user's friends list
const friendsDoc = admin.firestore().collection(targetUsersFriendsColl).doc();
friendsDoc.set({
createDate: admin.firestore.FieldValue.serverTimestamp(),
modifiedDate: admin.firestore.FieldValue.serverTimestamp(),
stat: 2, //pending
friendUID: uid1,
friendUsername: username1,
})
.then(() => {
console.log('_addFriend Finished adding friend.')
returnVal = 1
returnMsg = 'Friend request sent!'
})
.catch((error) => {
console.log('_addFriend error adding to target users friends collec: ', error)
returnVal = 0
returnMsg = 'Error all the way inside: ' + error
})
})
.catch(error => {
console.log('_addFriend error: ', error)
returnVal = 0
returnMsg = 'Error1: ' + error
})
} else {
console.log('_addFriend: In else, result was 0.')
returnVal = 0
returnMsg = 'Current user does not exist.'
}
})
.catch(error => {
console.log('_TS_getUserInfo error: ', error)
returnVal = 0
returnMsg = 'Could not find current user info.'
})
} else {
console.log('_TS_doesUserExist: targetUser ', targetUser, ' does not exist.')
returnVal = result[0]
returnMsg = result[2]
}
})
.catch(error => {
console.log('_TS_doesUserExist error: ', error)
returnVal = 0
returnMsg = 'Error2: ' + error
});
}
else {
console.log('_addFriend error: User is not authorized');
returnVal = 0
returnMsg = 'User is not authorized.'
}
return {result: returnVal, message: returnMsg}
});
A question I have in regards to what you are seeing on your end, does the console statement happen AFTER the client gets the 69 and other values?
I believe at the location where you are calling TS_getUserInfo inside the TS_doesUserExist then might be where your problem is. You'll need to return that promise chain if you want it to be awaited by the await for TS_doesUserExist.
Then just to explain what I believe I am seeing, if I am reading the nesting right, is that you are:
Calling await on TS_doesUserExist
The main block stops there. Waits for TS_doesUserExist to process
It then enters the then block and invokes your TS_getUserInfo function
After invoking the TS_getUserInfo function the original promise from TS_doesUserExist resolves
Main block continues and sends the message to the client
Main block finishes allows event loop to loop back around to TS_getUserInfo
TS_getUserInfo resolves, enters then block prints your log and assigns values
So from that, returning TS_getUserInfo should allow it to be awaited your original await as it will then become part of the TS_doesUserExist promise chain and resolve your console and values prior to sending the message to the client.
Abbreviated code example of what I believe needs to happen:
exports.addFriend = functions.https.onCall(async (data, context) => {
const targetUser = data.targetUser;
var returnVal: number = 69;
var returnMsg: string = uid1;
if (uid1) {
await TS_doesUserExist(targetUser)
.then(result => {
//...other code you want to process before calling TS_getUserInfo...
// This is where I believe you need your return
return TS_getUserInfo('uid', uid1, 'username')
.then(() => {
console.log('_addFriend Finished adding friend.')
returnVal = 1
returnMsg = 'Friend request sent!'
});
});
}
return {result: returnVal, message: returnMsg}
});
Documentation from MDN on the promise.then function: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
The chaining section there should give some more insight into that functionality as well.
EDIT
I doubt if you can find a correct answer below since this question is too general. And the answer posted by me will most likely only work for that cmd handler and the version this was written for is v12
--Original Question--
how do I make the options like ?d and ? f optional and the order want matter but it will create the embed on the given options
'example: .embed ?d description: this will create an embed with only a description'
I have already tried but I messed up here is the code [Removed for private reasons]
but this outputs this : [removed]
What you need to do is : go in your main file(like index.js) and set in top of code this :
const Discord = require('discord.js');
Then where command 'embed' is you need to set this :
if(command === 'embed'){
client.commands.get('embed').execute(message, args, Discord);
Then in your command folder you will make a file named embed.js . In embed.js you need to set this code:
module.exports = {
name: 'embed',
description: 'Embed Test',
execute(message, args, Discord){
const newEmbed = new Discord.MessageEmbed()
.setTitle('Your Title')
.setColor('RANDOM')
.setFooter('Some Footer here', 'another footer here' )
.setDescription('> ?testa\n' + '> ?testb\n' + '> testc');
message.delete();
message.channel.send(newEmbed);
}
});
And you get only the description after command and message with command ([prefix]embed) will delete after you post it !
Okay i fixed it my self : )
i splited the args by (?) and went through each value to see if the args have the needed options
here is what I did for future reference :
let text = args.join(' ')
const Embed = new Discord.MessageEmbed()
let errrors = []
if(!text) return message.channel.send('Error')
let tex = text.split('?')
tex.forEach(async e => { .........
if(e.toLowerCase().startsWith('d')) {
let description = e.replace('d', '')
if(description.length == 0) {
return await errrors.push('Description option was given but no description was given!!')
} else {
await Embed.setDescription(description)
}
} else if(e.toLowerCase().startsWith('t')) ........
}
// then
if(errrors.length > 0) {
let errr = errrors
Embed.setTitle('Following errors occured while constructing your embed')
Embed.setDescription(errr)
return message.channel.send(Embed)
} else {
message.channel.send(Embed)
}
My code works fine if i create the database entry myself, however when I get someone else to try the entry isnt created (even though i used a .ensure to check)
Previously it created some entries automatically but im not sure what changed and then it stopped creating them, i've tried to change the code around but the only solution seems to be creating the entries manually.
The error usually occurs when calling the +elo command
const Discord = require('discord.js')
const client = new Discord.Client()
const Enmap = require("enmap");
client.elo = new Enmap({name: "elo"});
gameVar = 0;
client.on('ready', () => {
console.log("Connected as " + client.user.tag)
// List servers the bot is connected to
console.log("Servers:")
client.guilds.forEach((guild) => {
console.log(" - " + guild.name)
var generalChannel = client.channels.get("602976588543426596") // Replace with known channel ID
generalChannel.send("--10 Man Bot--")
generalChannel.send("To begin a game, type +join")
generalChannel.send("")
})
})
client.on('message', (receivedMessage) => {
if (receivedMessage.author == client.user) { // Prevent bot from responding to its own messages
return
}
if (receivedMessage.content.startsWith("+")) {
processCommand(receivedMessage)
}
if (receivedMessage.guild) {
client.elo.ensure(`${receivedMessage.guild.id}-${receivedMessage.author.id}`, {
user: receivedMessage.author.id,
guild: receivedMessage.guild.id,
elo: 0,
console.log("entry created")
});
}
})
function processCommand(receivedMessage) {
let fullCommand = receivedMessage.content.substr(1) // Remove the leading exclamation mark
let splitCommand = fullCommand.split(" ") // Split the message up in to pieces for each space
let primaryCommand = splitCommand[0] // The first word directly after the exclamation is the command
let arguments = splitCommand.slice(1) // All other words are arguments/parameters/options for the command
console.log("Command received: " + primaryCommand)
if (primaryCommand == "elo") {
const key = `${receivedMessage.guild.id}-${receivedMessage.author.id}`;
return receivedMessage.channel.send(`ELO: ${client.elo.get(key, "elo")}`);
}
bot_secret_token =
client.login(bot_secret_token)
Here is the error message:
C:\Users\retski\node_modules\enmap\src\index.js:945
if (!this.has(key)) throw new Err(`The key "${key}" does not exist in the enmap "${this.name}"`, 'EnmapPathError');
^
EnmapPathError: The key "546829579290017793-269522297105285121" does not exist in the enmap "elo"
at Map.[check] (C:\Users\retski\node_modules\enmap\src\index.js:945:31)
at Map.get (C:\Users\retski\node_modules\enmap\src\index.js:227:19)
at processCommand (C:\Users\retski\Desktop\10 man leffy\10man.js:69:60)
at Client.client.on (C:\Users\retski\Desktop\10 man leffy\10man.js:29:9)
at Client.emit (events.js:198:13)
at MessageCreateHandler.handle (C:\Users\retski\node_modules\discord.js\src\client\websocket\packets\handlers\MessageCreate.js:9:34)
at WebSocketPacketManager.handle (C:\Users\retski\node_modules\discord.js\src\client\websocket\packets\WebSocketPacketManager.js:105:65)
at WebSocketConnection.onPacket (C:\Users\retski\node_modules\discord.js\src\client\websocket\WebSocketConnection.js:333:35)
at WebSocketConnection.onMessage (C:\Users\retski\node_modules\discord.js\src\client\websocket\WebSocketConnection.js:296:17)
at WebSocket.onMessage (C:\Users\retski\node_modules\ws\lib\event-target.js:120:16)```
You are calling processCommand(receivedMessage) before the ensure.
Try it like:
client.on('message', (receivedMessage) => {
if (receivedMessage.author == client.user) { // Prevent bot from responding to its own messages
return;
}
if (receivedMessage.guild) {
client.elo.ensure(`${receivedMessage.guild.id}-${receivedMessage.author.id}`, {
user: receivedMessage.author.id,
guild: receivedMessage.guild.id,
elo: 0,
});
console.log('entry created');
}
if (receivedMessage.content.startsWith('+')) {
processCommand(receivedMessage);
}
});
I am extremely new to Javascript and Discord.js, meaning that I copy most of my code online and try to understand them. I tried this google search command. However, my bot does not send anything. The only thing it sends is "Need Input" when I type .google. When I do input a search, it does not complete the task. It does not give me an error in my command prompt. Have I done something wrong? Do you have a completely different code? PS. My code is from https://github.com/OblivionSan/discord-googlebot/blob/master/commands/general/google.js
I have installed npm i google, but it sends me a lot of errors when I do.
const google = require('google');
const Discord = require(`discord.js`);
exports.run = (client, message) => {
if (!suffix) {
message.channel.send({
embed: {
color: 0xff2727,
description: `:warning: **${message.author.username}**, You didn't give me anything to search. {.google \`input\`}`,
}
});
}
google.resultsPerPage = 5;
google(suffix, function (err, res) {
if (err) message.channel.send({
embed: {
color: 0xff2727,
description: `:warning: **${message.author.username}**, ${err}`,
footer: {
text: 'API Lantancy is ' + `${Date.now() - message.createdTimestamp}` + ' ms',
}
}
});
for (var i = 0; i < res.links.length; ++i) {
var link = res.links[i];
if (!link.href) {
res.next;
} else {
let embed = new Discord.RichEmbed()
.setColor(`#ffffff`)
.setAuthor(`Result for "${suffix}"`, `https://upload.wikimedia.org/wikipedia/commons/thumb/5/53/Google_%22G%22_Logo.svg/2000px-Google_%22G%22_Logo.svg.png`)
.setDescription(`**Link**: [${link.title}](${link.href})\n**Description**:\n${link.description}`)
.setTimestamp()
.setFooter('API Lantancy is ' + `${Date.now() - message.createdTimestamp}` + ' ms', message.author.displayAvatarURL);
return message.channel.send({
embed: embed
});
} return message.react("👌");
}
});
};
I expect a google search but get basically nothing. I get left on read :/
That module is not working as of now, as far as I can tell. I'm using the GoogleIt module for my bot, and here's the code that I'm using for a sample:
const googleIt = require('google-it')
const Discord = require(`discord.js`);
exports.run = (bot, message, args) => {
const embed = new Discord.RichEmbed()
.setTitle("Google Search Results")
.setColor(3426654)
.setTimestamp()
googleIt({'query': args.join(' ')}).then(results => {
results.forEach(function(item, index) {
embed.addField((index + 1) + ": " + item.title, "<" + item.link + ">");
});
message.channel.send(embed);
}).catch(e => {
// any possible errors that might have occurred (like no Internet connection)
});
};
module.exports.help = {
name: 'google',
aliases: []
}
Check what I have below and see if that works. I usually use an object for the embed. You can generate / see one here => https://leovoel.github.io/embed-visualizer/ when you click the generate button and select discord.js
// this config option doesn't really need to be in your method / function
google.resultsPerPage = 5;
client.on('message', (message) => {
// Using !search as a suffix in a regex
if (/!search/.test(message.content))) {
// remove the suffix
const search = message.content.replace('!search ', '');
google('node.js best practices', (err, res) => {
if (err) console.error(err)
for (var i = 0; i < res.links.length; ++i) {
var link = res.links[i];
// At this point, you should see your data and just have to format your embed
console.log(link.title + ' - ' + link.href)
console.log(link.description + "\n")
}
}
}
});
Im creating a trading bot on Javascript (I got no prior experience with this language). The way the trailing stoploss function runs is:
Websocket receives current market price
"active" is a boolean variable, if true, run the code
If price rises a %, cancel old stoploss and add a new one higher.
The problem I am getting is the code doesn't run in the right order.
If you look at the picture, I don't understand why the blue box still executes if active is false. And because the program runs in the wrong order at times, the websocket stops or acts how it isn't supposed to.
This is my trailing stoploss websocket code:
function binanceTrailingSLOrder(symbol, orderId, quantity, oldPrice, percentage, active) {
const clean_trade = client.ws.trades([symbol], trade => { //run websocket
var livePrice = parseFloat(binance_symbols[symbol]["close"]); //set new price to live price
if (active == true) {
binanceCheckOrderStatus(symbol, orderId).then(r => {
switch (r.status) {
case "PENDING":
if (livePrice >= (oldPrice * ((100 + percentage) / 100)) && active == true) {
active = false;
binanceCancelOrder(symbol, orderId).then((r4) => { //Cancel previous SL
var newSL = livePrice * ((100 - percentage) / 100);
binanceStopOrder(symbol, 'SELL', r4.origQty, newSL, newSL).then((r5) => { //Set new SL
orderId = r5.orderId; quantity = r5.origQty; oldPrice = r5.price;
active = true;
}).catch((err) => {
console.log(err);
});
});
}
break;
default:
break;
}
});
}
});
}
Check order status function:
//Get specific order status
function binanceCheckOrderStatus(symbol, orderId) {
if(!orderId){
console.log("order Id not found");
return false;
} else {
var client = loadBinanceKeys2();
return client.getOrder({
symbol: symbol,
orderId: orderId,
recvWindow: 1000000
}).then((order) => {
return order;
}).catch((err) => {
console.log(err);
});
}
}
Javascript is asynchronous in nature. The function binanceCheckOrderStatus() returns a promise. The execution engine will call this function, and then move on to the next line. The code block after .then(r => only executes after the binanceCheckOrderStatus's getOrder() is completed. Now in this time period, the active may have become false in other .then() requests. It may be confusing for new developers. Since you are using lot of .then() in your code, you have to understand that the .then() part is only executed after the function before .then() completes the execution. So the function taking less time will execute it's .then() part before the others. So in short, you CANNOT control the order in this scenario unless you know how much time every function will take, which is probably impossible to confirm. For overcoming this problem, you have to use async/await. Or, you need to change your logic so it is less dependent on that deep level promises.
I am not very sure about what you are trying to achieve here, but here is the idea about how you can solve the ordering problem. It is just a reference code, I have not tested it. Just an idea on how you can hold your threads to make sure your code runs in an order using async/await.
async function binanceTrailingSLOrder(symbol, orderId, quantity, oldPrice, percentage, active) {
const clean_trade = client.ws.trades([symbol], async trade => { //run websocket
var livePrice = parseFloat(binance_symbols[symbol]["close"]); //set new price to live price
if (active == true) {
try {
const order = await binanceCheckOrderStatus(symbol, orderId);
if (!order) {
throw new Error('order not found')
}
switch (order.status) {
case "PENDING":
if (livePrice >= (oldPrice * ((100 + percentage) / 100)) && active == true) {
active = false;
const r4 = await binanceCancelOrder(symbol, orderId);
if (r4) {
var newSL = livePrice * ((100 - percentage) / 100);
var r5 = binanceStopOrder(symbol, 'SELL', r4.origQty, newSL, newSL);
if (r5) {
orderId = r5.orderId; quantity = r5.origQty; oldPrice = r5.price;
active = true;
}
}
}
break;
default:
break;
}
}
catch(error) {
console.log('error found: ', error);
}
}
});
}
async function binanceCheckOrderStatus(symbol, orderId) {
if(!orderId){
console.log("order Id not found");
return false;
} else {
var client = loadBinanceKeys2();
return new Promise((resolve, reject) => {
client.getOrder({
symbol: symbol,
orderId: orderId,
recvWindow: 1000000
}).then((order) => {
resolve(order);
}).catch((err) => {
reject(err);
});
});
}
}