How can I send a random image? - discord.js

I am trying to post a random dog picture when someone says toggledoggo. Every time I try to run the command, it gives me an error message in the terminal, and does nothing.
Here is my code:
const Discord = require('discord.js');
const client = new Discord.Client();
client.on("message", message => {
var prefix = 'toggle';
var doggos = ['dog1', 'dog2'];
var dog1 = message.channel.send({ files: ['dog1.jpg'] });
var dog2 = message.channel.send({ files: ['dog2.jpg'] });
if (message.content.startsWith(prefix + 'doggo')) {
Math.floor(Math.random() * doggos.length);
};
});
client.login('token');

If you want a truly random picture (pseudo-random but still) use an api. I use dog.ceo. Heres a code that, while big, gives a user plenty of options to choose from.
if(msg.split(' ')[0] === prefix + "doggo"){
let breeds = []; // Initializing an array to use later
let breeds2 = []; // Due to the size, we need to split it.
request('https://dog.ceo/api/breeds/list/all', async function (error, response, body) { // Begin a request to list all breeds.
if (!error && response.statusCode == 200) {
var importedJSON = JSON.parse(body);
for(var name in importedJSON.message){ // looping through every breed and pushing it into the array made earlier
breeds.push(name)
if(importedJSON.message[name].length != 0){
for(var i = 0; i < importedJSON.message[name].length; i++){
breeds.push("- " + importedJSON.message[name][i]) // Pushing sub-breeds into the array too
}
}
}
for(var j = 0; j < breeds.length/2; j++){ // Halving the previous array because it's too big for one message.
let toArray = breeds.shift()
breeds2.push(toArray)
}
}
})
let args = msg.split(' ').slice(1)
if(!args[0]){ // if no breed, then send a random image
request('https://dog.ceo/api/breeds/image/random', async function (error, response, body) {
if (!error && response.statusCode == 200) {
var importedJSON = JSON.parse(body);
return await message.channel.send(importedJSON.message)
}
})
}
if(args[0] === "breeds"){ // Command to list the breeds.
setTimeout(async function(){
let m = breeds2.map(name => name.charAt(0).toUpperCase() + name.slice(1)) // Creating a map of the arrays earlier to send as a message
let m2 = breeds.map(name => name.charAt(0).toUpperCase() + name.slice(1))
await message.channel.send(m)
return await message.channel.send(m2)
}, 1000);
}
if(args[0]){
setTimeout(async function(){
for(var i = 0; i < breeds.length; i++){ // Looping through every breed in the array to see if it matches the input
if(args[0] == breeds[i]){
let input = breeds[i]
args.shift() // This is to check for a sub breed input, which is taken into account in the else statement of this if statement
if(!args[0] || args[0] == undefined){
request(`https://dog.ceo/api/breed/${input}/images/random`, async function (error, response, body) {
if (!error && response.statusCode == 200) {
var importedJSON = JSON.parse(body);
return await message.channel.send(importedJSON.message)
}else{
await message.channel.send(`You must have typed something wrong, do ${prefix}doggo breeds for a list of breeds.`)
return
}
})
return
}else{
request(`https://dog.ceo/api/breed/${input}/${args[0]}/images/random`, async function (error, response, body) { // requesting a dog of a certain breed and sub breed
if (!error && response.statusCode == 200) {
var importedJSON = JSON.parse(body);
return await message.channel.send(importedJSON.message)
}else{
await message.channel.send(`You must have typed something wrong, do ${prefix}doggo breeds for a list of breeds.`)
return
}
})
return
}
}
}
for(var i = 0; i < breeds2.length; i++){ // This is identical to the above, but with the other array
if(args[0] == breeds2[i]){
let input = breeds2[i]
args.shift()
if(!args[0] || args[0] == undefined){
request(`https://dog.ceo/api/breed/${input}/images/random`, async function (error, response, body) {
if (!error && response.statusCode == 200) {
var importedJSON = JSON.parse(body);
return await message.channel.send(importedJSON.message)
}else{
await message.channel.send(`You must have typed something wrong, do ${prefix}doggo breeds for a list of breeds.`)
return
}
})
return
}else{
request(`https://dog.ceo/api/breed/${input}/${args[0]}/images/random`, async function (error, response, body) {
if (!error && response.statusCode == 200) {
var importedJSON = JSON.parse(body);
return await message.channel.send(importedJSON.message)
}else{
await message.channel.send(`You must have typed something wrong, do ${prefix}doggo breeds for a list of breeds.`)
return
}
})
return
}
}
}
}, 1000);
}
};
The acceptable command for this are: (prefix)doggo, (prefix)doggo breeds, (prefix)doggo (breed), (prefix)doggo (breed) (sub breed)
You will need the "request" module you can read up on it here: https://www.npmjs.com/package/request. Hopefully the comments I put in the code are enough to explain whats going on if not, ask for clarification. If you just wanted a small command for 2 pictures then you can also tell me and I'll delete this post entirely.

Related

Discord.js - How to send YouTube url after searching for a video

So basically, my idea for a new command for my discord bot is a "link searcher", which will be a searching command that sends the url of the video that is chosen by the user. Something like in the image attached.
What I already have made is a searching command with embed, but im not quite sure how to send the video url that gets chosen via reaction. Any ideas/solutions?
I have found a solution after some tries, so here's the final code.
//////CONFIG LOAD///////////
////////////////////////////
const ytsr = require("youtube-sr")
const { Client, Collection, MessageEmbed } = require("discord.js");
const { attentionembed } = require("../util/attentionembed"); //attentionembed is an embed i pre-made for errors/attention cases for when the user gets one
const { approveemoji, denyemoji, PREFIX, } = require(`../config.json`); //my config contains the definitions for "yes" and "no" emojis, together with the bot token
////////////////////////////
//////COMMAND BEGIN/////////
////////////////////////////
module.exports = {
name: "linkfor",
aliases: ["searchlink","findlink","link","lf"], //optional
cooldown: 3, //optional
async execute(message, args, client) {
//if its not in a guild return
if (!message.guild) return;
//react with approve emoji
message.react(approveemoji).catch(console.error);
//if the argslength is null return error
if (!args.length)
return attentionembed(message, `Usage: ${message.client.prefix}${module.exports.name} <Video Name>`)
//if there is already a search return error
if (message.channel.activeCollector)
return attentionembed(message, "There is a search active!");
//define search
const search = args.join(" ");
//define a temporary Loading Embed
let temEmbed = new MessageEmbed()
.setAuthor("Searching...", "put a gif link here if you want")
.setColor("#F0EAD6")
//define the Result Embed
let resultsEmbed = new MessageEmbed()
.setTitle("Results for ")
.setDescription(`\`${search}\``)
.setColor("#F0EAD6")
.setAuthor("Search results:", "put a gif link here if you want")
.setFooter("Respond with the right number", "put a gif link here if you want")
//try to find top 9 results
try {
//find them
const results = await ytsr.search(search, { limit: 9 });
//map them and sort them and add a Field to the ResultEmbed
results.map((video, index) => resultsEmbed.addField(video.url, `${index + 1}. ${video.title}`));
//send the temporary embed aka Loading... embed
const resultsMessage = await message.channel.send(temEmbed)
//react with 9 Numbers
await resultsMessage.react("1️⃣");
await resultsMessage.react("2️⃣");
await resultsMessage.react("3️⃣");
await resultsMessage.react("4️⃣");
await resultsMessage.react("5️⃣");
await resultsMessage.react("6️⃣");
await resultsMessage.react("7️⃣");
await resultsMessage.react("8️⃣");
await resultsMessage.react("9️⃣");
//edit the resultmessage to the resultembed (you can also try deleting and sending the new one, if you need to)
await resultsMessage.edit(resultsEmbed)
//set the collector to true
message.channel.activeCollector = true;
//wait for a response
let response;
await resultsMessage.awaitReactions((reaction, user) => user.id == message.author.id,
{ max: 1, time: 60000, errors: ['time'], }).then(collected => {
//if its one of the emoji set them to 1 / 2 / 3 / 4 / ...
if (collected.first().emoji.name == "1️⃣") { return response = 1; }
if (collected.first().emoji.name == "2️⃣") { return response = 2; }
if (collected.first().emoji.name == "3️⃣") { return response = 3; }
if (collected.first().emoji.name == "4️⃣") { return response = 4; }
if (collected.first().emoji.name == "5️⃣") { return response = 5; }
if (collected.first().emoji.name == "6️⃣") { return response = 6; }
if (collected.first().emoji.name == "7️⃣") { return response = 7; }
if (collected.first().emoji.name == "8️⃣") { return response = 8; }
if (collected.first().emoji.name == "9️⃣") { return response = 9; }
//otherwise set it to error
else {
response = "error";
}
});
//if response is error return error
if (response === "error") {
//send error message
attentionembed(message, "Please use the right emoji symbol.");
//try to delete the message
return resultsMessage.delete().catch(console.error);
}
//get the response link
const URL = resultsEmbed.fields[parseInt(response) - 1].name;
//set collector to false aka off
message.channel.activeCollector = false;
//send the collected url
message.channel.send(URL);
//delete the search embed (optional, for better displaying)
resultsMessage.delete().catch(console.error);
//catch any errors while searching
} catch (error) {
//log them
console.error(error);
//set collector false, just incase its still true
message.channel.activeCollector = false;
}
}
};

dealing with an array of objects with promises

I am trying to make a node express app where I fetch data from different url's making a call to node-fetch to pull the body of some pages and other information about certain url endpoints. I want to then render a html table to display this data through an array of information. I am having trouble with the call to render the information as all the functions are asynchronous making it difficult to make sure all the promise calls have been resolved before making my call to render the page. I have been looking into using bluebird and other promise calls of .finally() and .all() but they don't seem to work on my data as it is not an array of promise calls, but an array of objects. Each object was 4 promise calls to fetch data relating to a column of my table all in one row. Is there a function or specific way to render the page after all promises are resolved?
var express = require('express');
var fetch = require('node-fetch');
fetch.Promise = require('bluebird');
var router = express.Router();
const client = require('../platform-support-tools');
function makeArray() {
var registry = client.getDirectory();
var data_arr = [];
for (var i = 0; i < registry.length; i++) {
var firstUp = 0;
for (var j = 0; i < registry[i]; j++) {
if (registry[i][j]['status'] == 'UP') {
firstUp = j;
break;
}
}
var object = registry[i][firstUp];
data_arr.push({
'name': object['app'],
'status': object['status'],
'swagUrl': object['homePageUrl'] + 'swagger-ui.html',
'swag': getSwag(object),
'version': getVersion(object['statusPageUrl']),
'timestamp': getTimestamp(object['statusPageUrl']),
'description': getDescription(object['healthCheckUrl'])
});
}
return data_arr;
}
function getSwag(object_in) {
var homeUrl = object_in['homePageUrl'];
if (homeUrl[homeUrl.length - 1] != '/'){
homeUrl += '/';
}
var datum = fetch(homeUrl + 'swagger-ui.html')
.then(function (res) {
return res.ok;
}).catch(function (err) {
return 'none';
});
return datum;
}
function getVersion(url_in) {
var version = fetch(url_in)
.then(function(res) {
return res.json();
}).then(function(body) {
return body['version'];
}).catch(function (error) {
return 'none';
});
return version;
}
function getTimestamp(url_in) {
var timestamp = fetch(url_in)
.then(function(res) {
return res.json();
}).then(function(body) {
return body['timestamp'];
}).then(function (res) {
return body['version'];
}).catch(function (error) {
return 'none';
});
return timestamp;
}
function getDescription(url_in) {
var des = fetch(url_in)
.then(function(res) {
return res.json();
}).then(function(body) {
return body['description'];
}).catch(function (error) {
return 'none';
});
return des;
}
/* GET home page. */
router.get('/', function (req, res, next) {
var data_arr = makeArray();
Promise.all(data_arr)
.then(function (response) {
//sorting by app name alphabetically
response.sort(function (a, b) {
return (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0);
});
res.render('registry', {title: 'Service Registry', arr: response})
}).catch(function (err) {
console.log('There was an error loading the page: '+err);
});
});
To wait on all those promises, you will have to put them into an array so you can use Promise.all() on them. You can do that like this:
let promises = [];
for (item of data_arr) {
promises.push(item.swag);
promises.push(item.version);
promises.push(item.timestamp);
promises.push(item.description);
}
Promise.all(promises).then(function(results) {
// all promises done here
})
If you want the values from all those promises, back into the object that's a bit more work.
let promises = [];
for (item of data_arr) {
promises.push(item.swag);
promises.push(item.version);
promises.push(item.timestamp);
promises.push(item.description);
}
Promise.all(promises).then(function(results) {
// replace promises with their resolved values
let index = 0;
for (let i = 0; i < results.length; i += 4) {
data_arr[index].swag = results[i];
data_arr[index].version = results[i + 1];
data_arr[index].timestamp = results[i + 2];
data_arr[index].description = results[i + 3];
++index;
});
return data_arr;
}).then(function(data_arr) {
// process results here in the array of objects
});
If you had to do this more often that just this once, you could remove the hard coding of property names and could iterate all the properties, collect the property names that contain promises and automatically process just those.
And, here's a more general version that takes an array of objects where some properties on the objects are promises. This implementation modifies the promise properties on the objects in place (it does not copy the array of the objects).
function promiseAllProps(arrayOfObjects) {
let datum = [];
let promises = [];
arrayOfObjects.forEach(function(obj, index) {
Object.keys(obj).forEach(function(prop) {
let val = obj[prop];
// if it smells like a promise, lets track it
if (val && val.then) {
promises.push(val);
// and keep track of where it came from
datum.push({obj: obj, prop: prop});
}
});
});
return Promise.all(promises).then(function(results) {
// now put all the results back in original arrayOfObjects in place of the promises
// so now instead of promises, the actaul values are there
results.forEach(function(val, index) {
// get the info for this index
let info = datum[index];
// use that info to know which object and which property this value belongs to
info.obj[info.prop] = val;
});
// make resolved value be our original (now modified) array of objects
return arrayOfObjects;
});
}
You would use this like this:
// data_arr is array of objects where some properties are promises
promiseAllProps(data_arr).then(function(r) {
// r is a modified data_arr where all promises in the
// array of objects were replaced with their resolved values
}).catch(function(err) {
// handle error
});
Using the Bluebird promise library, you can make use of both Promise.map() and Promise.props() and the above function would simply be this:
function promiseAllProps(arrayOfObjects) {
return Promise.map(arrayOfObjects, function(obj) {
return Promise.props(obj);
});
}
Promise.props() iterates an object to find all properties that have promises as values and uses Promise.all() to await all those promises and it returns a new object with all the original properties, but the promises replaced by the resolved values. Since we have an array of objects, we use Promise.map() to iterate and await the whole array of those.

Looping in Angular with promises and http calls

my goal is to populate an array via for loop. and then send that array in HTTP POST call,
i.e: first upload all the files, then push each file details in array.
// For multiple files
for (let i = 0; i < projectRefFilesForUploading.length; i++) {
this.postSingleFile([] = projectRefFilesForUploading[i].file, projectDir).then(uploadedFiles => {
let filePath = uploadedFiles['projectRefFiles'][0].fd;
filePath = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.lastIndexOf("."));
let filename = uploadedFiles['projectRefFiles'][0].filename;
let size = uploadedFiles['projectRefFiles'][0].size;
let type = uploadedFiles['projectRefFiles'][0].type;
let status = uploadedFiles['projectRefFiles'][0].status; // finished
let fileNote = projectRefFilesForUploading[i].fileNote;
projectRefFilesDataArray.push({fileName: filename, filePath: filePath, size: size, type: type, fileNote: fileNote});
});
}
i.e: now post the array in http post call.
let body = {
projectId: projectId,
projectRefFiles: projectRefFilesDataArray
}
let headers = new Headers();
let options: RequestOptionsArgs = { headers: headers, withCredentials: true }
return new Promise((resolve, reject) => {
this.http.post( this.apiEndpoint + "/add/all", body, options).toPromise()
.then(response => {
let jsonData = response.json();
if (jsonData.apiStatus == 1) {
resolve(jsonData);
}
else reject(jsonData.message);
})
.catch(reason => reject(reason.statusText));
});
the problem is due to async function calls, http call post its data in parallel to loop execution. so it sends an empty array in http call. if I put the call method inside the loop then it works. but it created too much http call along with looping.
please help me how to detect, loop finishes it execution then after http call
try this :
let promise = new Promise((resolve, reject) => {
let count = 0;
for (let i = 0; i < projectRefFilesForUploading.length; i++) {
this.postSingleFile([] = projectRefFilesForUploading[i].file, projectDir).then(uploadedFiles => {
count++;
let filePath = uploadedFiles['projectRefFiles'][0].fd;
filePath = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.lastIndexOf("."));
let filename = uploadedFiles['projectRefFiles'][0].filename;
let size = uploadedFiles['projectRefFiles'][0].size;
let type = uploadedFiles['projectRefFiles'][0].type;
let status = uploadedFiles['projectRefFiles'][0].status; // finished
let fileNote = projectRefFilesForUploading[i].fileNote;
projectRefFilesDataArray.push({fileName: filename, filePath: filePath, size: size, type: type, fileNote: fileNote});
if(count === projectRefFilesForUploading.length){
resolve(projectRefFilesForUploading);
}
});
}
});
promise.then(function(projectRefFilesDataArray){
let body = {
projectId: projectId,
projectRefFiles: projectRefFilesDataArray
}
let headers = new Headers();
let options: RequestOptionsArgs = { headers: headers, withCredentials: true }
return new Promise((resolve, reject) => {
this.http.post( this.apiEndpoint + "/add/all", body, options).toPromise()
.then(response => {
let jsonData = response.json();
if (jsonData.apiStatus == 1) {
resolve(jsonData);
}
else reject(jsonData.message);
})
.catch(reason => reject(reason.statusText));
});
});

how to remove a value from an array in database using nodejs and mongoose

I'm trying to remove a value from an array in my database which I get from url.
I use the code below but I get nothing. It doesn't go to the for loop.
app.get('/remove/:medid/:tokenid', function(req, res) {
var medid = req.params.medid;
var token = req.params.tokenid;
var query = { tokenid: token, mediaid !== 'undefined' && mediaid.length > 0 }
user.find(query).exec(function(err, result) {
if (err) {
res.send('erooooooor')
}
if (!result) {
res.send('whooops, you dont have any media yet :)')
} else {
console.log('its here')
for (var i in result.mediaid) {
console.log(i)
if (i == medid) {
user.update({ tokenid: token }, { $pull: { mediaid: medid } }, function(err, result2) {
if (err) {
res.send('an error happened')
} else {
console.log('deleted')
//res.send('your tokenid is '+ token)
}
})
} else {
res.send('media id didnt match')
}
}
}
});
});
My database has 3 objects userid and tokenid which are strings and mediaid which is an array.
Also, I want to check if my mediaid array is null or not and exist is this code
mediaid !== 'undefined' && mediaid.length > 0
You have got your json syntax incorrect in following line
var query = {tokenid: token, mediaid !== 'undefined' && mediaid.length > 0}
You should probably just let your query be based on token id.
var query = {tokenid: token};
Also when you write for(var i in result.mediaid), for each iteration of loop, the variable 'i' is assigned the index of current element, not its value. So your if condition should be modified to check result.mediaid[i] == medid instead of i == medid. Modified loop should look something like:
for(var i in result.mediaid){
console.log(i);
if(result.mediaid[i] === medid){
user.update({tokenid: token}, {$pull: {mediaid: medid}},function(err, result2){
if (err){
res.send('an error happened');
}
else{
console.log('deleted');
//res.send('your tokenid is '+ token)
}
});
}
}
Please, you can replace to:
app.get('/remove/:mediaid/:tokenid', function(req, res){
var medid = req.params.mediaid;
var token = req.params.tokenid;
var query = {tokenid: token, mediaid !== 'undefined' && mediaid.length > 0}
UPDATED:
I recommended that print after console.log(medid, token);
I hoped help you - Jose Carlos Ramos

NodeJS callback: How to make the call wait for mongodb query result

I have a registration dialog where when the user enters username and password I need to check the DB whether the user is present
or not. But when I am validation for the same my call does not hold back until I get the results from the server.
After searching for a while I got to know about callbacks. So I have added a call back inside this.isUser method.
And it is successful. But now doRegistration method is not synchronous with the isUser method.
How to make all my calls synchronous?
this.doRegistration = function(uname, pwd, confirmPwd) {
if(this.isUser(uname)) {
return "USER_EXISTS";
} else {
saveUser(uname, pwd);
return "SUCCESS";
}
};
this.isUser = function(username) {
var users = new Array();
getAllUsers('param', function(response) {
users = response;
console.log(users.length);
for(i = 0; i < users.length; i++) {
if(users[i].username === username) {
return true;
}
}
return false;
});
};
function getAllUsers(param, callback) {
loginFactory.AllUsers.query(function(response) {
if(response != undefined && response.length > 0) {
callback(response);
}
});
}
You may rewrite the code like following:
this.doRegistration = function(uname, pwd, confirmPwd, callBack) {
this.isUser(uname,function(flag) {
if(flag){
callBack("USER_EXISTS");
}
else {
saveUser(uname, pwd, function(err,result){
if(err){
callBack("SAVING_FAILED");
}
else {
callBack("SUCCESS");
}
});
}
});
};
this.isUser = function(username,callBack) {
var users = new Array();
getAllUsers('param', function(response) {
users = response;
console.log(users.length);
for(i = 0; i < users.length; i++) {
if(users[i].username === username) {
callBack(true);
}
}
callBack(false);
});
};
function saveUser(userName, pwd, callBack){
//code to save user
//chek for error in saving
if(err){
callBack(err,null)
}
else {
callBack(null, "success")
}
}
function getAllUsers(param, callback) {
loginFactory.AllUsers.query(function(response) {
if(response != undefined && response.length > 0) {
callback(response);
}
});
}
You may also define saveUser as a function with callback. Here it wont wait for saveUser method to complete.

Resources