Caching custom emojis from another shard - javascript

im trying to get a larger discord bot of mine to save all custom emojis it grabs from another shard to a cache so I can serve better response times for each shard. To give a theoretical example, my bot spawns 4 shards and only one shard serves the guild that contains all the custom emojis that I want to use across all shards. I am using this function to grab the emojis, but I need to await each one, and it can make my response times up to 15 seconds as there are many emojis I need to grab:
function findEmoji(id) {
const temp = this.emojis.get(id);
if (!temp) return null;
const emoji = Object.assign({}, temp);
if (emoji.guild) emoji.guild = emoji.guild.id;
emoji.require_colons = emoji.requiresColons;
return emoji;
}
async function grabEmoji(emojiID) {
const emojiArray = await client.shard.broadcastEval(`(${findEmoji}).call(this, '${emojiID}')`);
const foundEmoji = emojiArray.find(emoji => emoji);
if (!foundEmoji) return;
const raw = await client.rest.makeRequest('get', Discord.Constants.Endpoints.Guild(foundEmoji.guild).toString(), true);
const guild = new Discord.Guild(client, raw);
const emoji = new Discord.Emoji(guild, foundEmoji);
return await emoji;
}
// then when I send the message, I call the function with the said ID of the emoji I want:
await grabEmoji("530800350656200705");
On the other hand, when I remove await, it will give me listener errors (maxListeners reached) or whatever, and then display "null".
Here is what I have tried, but I havent been able to get it to work.
const emojiMap = new Map();
createMap();
async function createMap() {
let woodenPick = await grabEmoji("601256699629797379"),
stonePick = await grabEmoji("601256431076769803"),
ironPick= await grabEmoji("601257055285673987"),
goldPick = await grabEmoji("601256566670491658"),
diamondPick= await grabEmoji("601256973798998016"),
emeraldPick = await grabEmoji("601256896577404938"),
rubyPick = await grabEmoji("601256312696733696"),
ultimatePick= await grabEmoji("629817042954092545"),
sandstonePick = await grabEmoji("629817043142705152"),
aquaPick = await grabEmoji("629817733902761985"),
techPick = await grabEmoji("502940161085014046"),
stone = await grabEmoji("502940717883064321"),
coal = await grabEmoji("502940528149659649"),
iron =await grabEmoji("502940160942669824"),
gold = await grabEmoji("493801062856392705"),
diamond= await grabEmoji("493805522466766849"),
obsidian =await grabEmoji("493801062671581184"),
emerald = await grabEmoji("630846535025819649"),
ruby =await grabEmoji("502940161001259018"),
lapis = await grabEmoji("502940160988807188"),
redstone= await grabEmoji("632411168601931822"),
silver = await grabEmoji("632413243503149087"),
neonite = await grabEmoji("632413243708801024"),
pulsatingStar= await grabEmoji("632404511759138816"),
sapphire = await grabEmoji("642799734192341013"),
developerBadge = await grabEmoji("642799734209118221"),
staffBadge = await grabEmoji("642799734209118221"),
donatorBadge = await grabEmoji("642799734247129089"),
contributorBadge = await grabEmoji("642799734247129089");
emojiMap.set(['woodenPick', woodenPick])
emojiMap.set(['stonePick', stonePick])
emojiMap.set(['ironPick', ironPick])
emojiMap.set(['goldPick', goldPick])
emojiMap.set(['diamondPick', diamondPick])
emojiMap.set(['emeraldPick', emeraldPick])
emojiMap.set(['rubyPick', rubyPick])
emojiMap.set(['ultimatePick', ultimatePick])
emojiMap.set(['sandstonePick', sandstonePick])
emojiMap.set(['aquaPick', aquaPick])
emojiMap.set(['techPick', techPick])
emojiMap.set(['stone', stone])
emojiMap.set(['coal', coal])
emojiMap.set(['iron', iron])
emojiMap.set(['gold', gold])
emojiMap.set(['diamond', diamond])
emojiMap.set(['obsidian', obsidian])
emojiMap.set(['emerald', emerald])
emojiMap.set(['ruby', ruby])
emojiMap.set(['lapis', lapis])
emojiMap.set(['redstone', redstone])
emojiMap.set(['silver', silver])
emojiMap.set(['neonite', neonite])
emojiMap.set(['pulsatingStar', pulsatingStar])
emojiMap.set(['sapphire', sapphire])
emojiMap.set(['developerBadge', developerBadge])
emojiMap.set(['staffBadge', staffBadge])
emojiMap.set(['donatorBadge', donatorBadge])
emojiMap.set(['contributorBadge', contributorBadge])
}
client.on('message', ... //rest of the code continues for my command handler.
//grab emojis
let woodenPick = emojiMap.get('woodenPick')
let stonePick = emojiMap.get('stonePick')
let ironPick = emojiMap.get('ironPick')
let goldPick = emojiMap.get('goldPick')
let diamondPick = emojiMap.get('diamondPick')
let emeraldPick = emojiMap.get('emeraldPick')
let rubyPick = emojiMap.get('rubyPick')
let ultimatePick = emojiMap.get('ultimatePick')
let sandstonePick = emojiMap.get('sandstonePick')
let aquaPick = emojiMap.get('aquaPick')
let techPick = emojiMap.get('techPick')
let stone = emojiMap.get('stone')
let coal = emojiMap.get('coal')
let iron = emojiMap.get('iron')
let gold = emojiMap.get('gold')
let diamond = emojiMap.get('diamond')
let obsidian = emojiMap.get('obsidian')
let emerald = emojiMap.get('emerald')
let ruby = emojiMap.get('ruby')
let lapis = emojiMap.get('lapis')
let redstone = emojiMap.get('redstone')
let silver = emojiMap.get('silver')
let neonite = emojiMap.get('neonite')
let pulsatingStar = emojiMap.get('pulsatingStar')
let sapphire = emojiMap.get('sapphire')
let developerBadge= emojiMap.get('developerBadge')
let staffBadge = emojiMap.get('staffBadge')
let donatorBadge = emojiMap.get('donatorBadge')
let contributorBadge = emojiMap.get('contributorBadge')
Doing that returns undefined as seen here:
Does anyone have any ideas? I'm directly saving the emoji object to the map thinking I can just use it later.

Getting discord.js's abstraction of an Emoji object in order to display it in a message is extremely unnecessary, but I can't blame you as discord.js tends to nudge its users towards these kinds of practices.
You already know the emoji names and IDs. There is no other information that you need to get from your other shards that your bot doesn't already have. In Discord messages, custom emoji are represented like this:
Custom Emoji - <:NAME:ID> -> <:mmLol:216154654256398347>
Custom Emoji (Animated) - <a:NAME:ID> -> <a:b1nzy:392938283556143104>
source: discord api docs reference
Hence, you don't need to make any requests, any broadcast evals, or anything of the sort: you only need static data. Like this:
let emojiMap = {
woodenPick: "601256699629797379",
stonePick: "601256431076769803",
//etc
};
I recommend a util function for putting the emoji in a message:
function getEmoji(name) {
return `<:${name}:${emojiMap[name]}>`;
}
Use it like this:
await msg.react(emojiMap.woodenPick); //might need to be :name:id
//etc, probably use an array for that (or Object.keys(emojiMap))
//make embed
let description = `${getEmoji("woodenPick")} --> Wooden Pickaxe\netc...`;

Related

So I made a meme command for my discord.js bot

const embed = new Discord.MessageEmbed();
got('https://www.reddit.com/r/memes/random/.json')
.then(response => {
const [list] = JSON.parse(response.body);
const [post] = list.data.children;
const permalink = post.data.permalink;
const memeUrl = `https://reddit.com${permalink}`;
const memeImage = post.data.url;
const memeTitle = post.data.title;
const memeUpvotes = post.data.ups;
const memeNumComments = post.data.num_comments;
embed.setTitle(`${memeTitle}`);
embed.setURL(`${memeUrl}`);
embed.setColor('BLACK');
embed.setImage(memeImage);
embed.setFooter(`👍 ${memeUpvotes} | 💬 ${memeNumComments}`);
message.channel.send(embed);
})
Here's the code. What I want it to do is to only show memes with more than 4k upvotes, how can I achieve it?
You may apply a really simple approach , add an if statement
if(parseInt(post.data.ups) > 4000) {
// Code here
}
parseInt() is a function that returns an integral value you can work with, rest seems self explanatory 😄.

FETCH API - Cannot access property from JSON response in api Request - Array is Empty

I've been trying to run a script that basically:
Loops thru a list of SellerIDs and identify how many records (which are product offers) each one has. Then, it creates an object with the Seller ID, Total Number of Pages and Total Number of Records.
Loop thru each ID in this newly created object and fetches all offers from each sellers. It fetches in batches of 50, because the API limit = 50.
Later on, I want to save these records to a database. But, to do that, Im going to save specific properties from each offer.
As I fetched them in batches, I need to access the single offers that are laying in the results property, inside each object. response.results.
For some reason, the results field always return as an empty array and Im unable to reach any of its properties.
If anyone has any idea what could be causing this issue, it's be a great help!
I've been trying to figure out and reading a lot, but still couldn`t find out.
Im a noob newly starting coding enthusiast, so sometimes I make dumb mistakes :X
Here's the code:
// node --max-old-space-size=8192 '.\2. CheckNeededPagination.js'
const express = require('express');
const mysql = require('mysql');
let listOfSellerIds = require('./1. list_of_seller_ids');
const request = require('request-promise');
const fetch = require('node-fetch');
const Request = require('request');
// IDs do app no Mercado Livre
var meli = require('mercadolibre-nodejs-sdk');
const mlToken = "hidden for security purposese";
const mlAppID = 'hidden for security purposese';
const mlSecretKey = 'hidden for security purposese';
const mlRedirectURI = 'https://localhost:3001/index'
const authURL = `http://auth.mercadolivre.com.br/authorization?response_type=code&client_id=${mlAppID}&redirect_uri=${mlRedirectURI}`
const endpoint = 'https://api.mercadolibre.com/sites/MLB/search?seller_id='
const reqHeaders = {method: "GET", headers: {'Authorization': mlToken}};
// -----------------------------------------------------------------------------------------------------
const myCode = (()=>{
const myPaginationNeeds = [];
// MODULE 1: Get Pagination Need from All sellers and return them as an object
async function makeRequest(){
for (s=0; listOfSellerIds[s]; s++){
const res = await fetch(`https://api.mercadolibre.com/sites/MLB/search?seller_id=${listOfSellerIds[s]}&offset=0&limit=1`, {method: "GET", headers: {'Authorization': mlToken}});
const data = await res.json();
myPaginationNeeds.push({'SellerID': listOfSellerIds[s],'RecordsNum': await data.paging.total, 'NumOfPages': await Math.ceil(data.paging.total/50)});
// myPaginationNeeds.push(await data);
}
console.log(myPaginationNeeds); // Uncomment to test object with seller pagination needs
}; // End of MODULE 1
//MODULE 2 -> Get All Offers From Sellers
async function getOffers (){
allOffers = [];
for (s=0; listOfSellerIds.length > s; s++){ //Loop thru sellers
curSellerID = listOfSellerIds[s];
console.log(`We're on seller ${listOfSellerIds[s]}! There are ${listOfSellerIds.length - s} sellers left to go...` )
for (i =0; 2 > i; i++){ //myPaginationNeeds[s].NumOfPages
console.log(`We're on page number ${i} of ${myPaginationNeeds[s].NumOfPages}! There are ${myPaginationNeeds[s].NumOfPages - i} pages left to go...` )
const response = await fetch(`https://api.mercadolibre.com/sites/MLB/search?seller_id=${listOfSellerIds[s]}&offset=${myPaginationNeeds[s].NumOfPages*50}&limit=50`, {method: "GET", headers: {'Authorization': mlToken}})
const resData = await response.json();
allOffers.push({'SellerInfo': await resData.seller,'SellerPaging': await resData.paging,'SellerResults': await resData.results});
const myResults = await resData.results[0];
console.log(await myResults);
}; // End of loop thru offset
} // End of loop thru sellers
// console.log(await allOffers);
//console.log(allOffers);
} // end of GetOffers
async function fetchIt () {
await makeRequest();
await getOffers();
console.log(allOffers.length);
//console.log(allOffers[0].SellerResults[0]);
};
fetchIt();
}); // End of myCode
myCode();

Web Scrape with Puppeteer within a table

I am trying to scrape this page.
https://www.psacard.com/Pop/GetItemTable?headingID=172510&categoryID=20019&isPSADNA=false&pf=0&_=1583525404214
I want to be able to find the grade count for PSA 9 and 10. If we look at the HTML of the page, you will notice that PSA does a very bad job (IMO) at displaying the data. Every TR is a player. And the first TD is a card number. Let's just say I want to get Card Number 1 which in this case is Kevin Garnett.
There are a total of four cards, so those are the only four cards I want to display.
Here is the code I have.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto("https://www.psacard.com/Pop/GetItemTable?headingID=172510&categoryID=20019&isPSADNA=false&pf=0&_=1583525404214");
const tr = await page.evaluate(() => {
const tds = Array.from(document.querySelectorAll('table tr'))
return tds.map(td => td.innerHTML)
});
const getName = tr.map(name => {
//const thename = Array.from(name.querySelectorAll('td.card-num'))
console.log("\n\n"+name+"\n\n");
})
await browser.close();
})();
I will get each TR printed, but I can't seem to dive into those TRs. You can see I have a line commented out, I tried to do this but get an error. As of right now, I am not getting it by the player dynamically... The easiest way I would think is to create a function that would think about getting the specific card would be doing something where the select the TR -> TD.card-num == 1 for Kevin.
Any help with this would be amazing.
Thanks
Short answer: You can just copy and paste that into Excel and it pastes perfectly.
Long answer: If I'm understanding this correctly, you'll need to map over all of the td elements and then, within each td, map each tr. I use cheerio as a helper. To complete it with puppeteer just do: html = await page.content() and then pass html into the cleaner I've written below:
const cheerio = require("cheerio")
const fs = require("fs");
const test = (html) => {
// const data = fs.readFileSync("./test.html");
// const html = data.toString();
const $ = cheerio.load(html);
const array = $("tr").map((index, element)=> {
const card_num = $(element).find(".card-num").text().trim()
const player = $(element).find("strong").text()
const mini_array = $(element).find("td").map((ind, elem)=> {
const hello = $(elem).find("span").text().trim()
return hello
})
return {
card_num,
player,
column_nine: mini_array[13],
column_ten: mini_array[14],
total:mini_array[15]
}
})
console.log(array[2])
}
test()
The code above will output the following:
{
card_num: '1',
player: 'Kevin Garnett',
column_nine: '1-0',
column_ten: '0--',
total: '100'
}

How can I use google sheets api data in discord.js embed?

I'm setting up my first discord bot, which will be able to take data from a Google Spreadsheet, from the official API and bring it as a embed message in discord. The problem is at the level of the .addField(), where I can not enter the value of the cell. How can I do this?
const { Client, RichEmbed } = require('discord.js');
const client= new Client();
const GoogleSpreadsheet = require('google-spreadsheet');
const {promisify} = require('util');
const creds = require('./client_secret.json');
client.on('message', message => {
if (message.content === '!bot'){
async function accessSpreadsheet() {
const doc = new GoogleSpreadsheet('1qA11t460-ceILmwu6RtfiPGb_n9MUD_7z6Ld7I_Z6yc');
await promisify(doc.useServiceAccountAuth)(creds);
const info = await promisify(doc.getInfo)();
var sheet = info.worksheets[0];
var cells = await promisify(sheet.getCells)({
'min-row': 2,
'max-row': 5,
'min-col': 3,
'max-col': 3,
'return-empty': true,
})
for (var cell of cells) {
message.author.send(cell.value)
}
}
accessSpreadsheet();
const embede = new RichEmbed()
.setColor('#0099ff')
.setTitle("My Title")
.addBlankField()
.setDescription('Some description')
.addBlankField()
.addField('Name', '•'+ cell[1].value , true)
.setTimestamp();
message.author.send(embede) }
})
client.login('xxx')
I expect the output "Terrassycup 3", but the actual output is "ReferenceError: cell is not defined" in console.log
A few issues I see with your code:
accessSpreadsheet() doesn't return any values it accesses.
accessSpreadhseet() returns a Promise since it's declared as async, but it's never awaited.
The scope of cell is within the for...of loop inside the accessSpreadsheet() function, yet you try to use it well outside of it.
Instead of sending each individual value to the user, you can add them as fields to the embed (the limit is 25) within the function you declare.
async function accessSpreadsheet(embed) {
// Insert the code already being used up to the for loop.
for (let i = 0; i < 25 && cells[i]; i++) embed.addField('Name', `•${cells[i].value}`, true);
}
var embed = new RichEmbed()
.setColor('#0099ff')
.setTitle('**Spreadsheet Info**')
.setDescription('Showing as many values as possible...');
accessSpreadsheet(embed)
.then(() => message.author.send(embed))
.catch(console.error);

Register 2 senderIds in JavaScript FCM

On a web page, I'm trying to create 2 firebase apps, with different names, each one associated with a different senderId.
I'm basically doing this:
const init = async ()=>{
const senderId1 = "SENDERID_1";
const senderId2 = "SENDERID_2";
const firebase1 = firebase.initializeApp({"messagingSenderId": senderId1},`name${senderId1}`);
const firebase2 = firebase.initializeApp({"messagingSenderId": senderId2},`name${senderId2}`);
const messaging1 = firebase1.messaging();
const messaging2 = firebase2.messaging();
await messaging1.requestPermission();
await messaging2.requestPermission();
const token1 = await messaging1.getToken(senderId1,"FCM");
const token2 = await messaging2.getToken(senderId2,"FCM");
document.querySelector("#token1").innerHTML = token1;
document.querySelector("#token2").innerHTML = token2;
document.querySelector("#areTheSame").innerHTML = (token1 == token2);
};
init();
Here's a page that exemplifies this behaviour.
The code doesn't generate any errors but token1 is always the same as token2. Obviously I need them to be different. Seems like a caching issue?
Does anyone have any idea if there's a workaround for this?
Thanks in advance

Categories

Resources