Reputation:
My current code:
const fetch = require("node-fetch");
const data = await fetch(
`https://pokemonrevolution.net/spawns/land_spawns.json`
).then((res) => res.json());
const filterFromPoke = data.filter((p) => p.Pokemon === "Pikachu");
const filteredMap = filterFromPoke
.map((s) =>
`${s.Map} Land Tier ${s.Tier} ${s.MinLVL}-${s.MaxLVL} ${s.MemberOnly} ${s.Item}`
.replace("null", "-")
.replace("false", "No")
.replace("true", "Yes")
)
.reduce((spw, spnxt) => {
spw = spw + "\n";
return spw + spnxt;
});
const mssg = `\`\`\`md\n#Map Area Rarity Levels MS Time Item\n${filteredMap}\`\`\``;
message.channel.send(mssg);
Returns: Image link
I want it to return something like this click here
Could someone please help me out to sort that clean like the example? Thanks
Upvotes: 0
Views: 792
Reputation: 23189
First, I thought that you could do it with embeds, but as Discord only displays three columns, so this one didn't work as expected. I'm just leaving it here, because if someone has only three columns max, it works fine.
client.on('message', async (message) => {
if (message.author.bot) return;
const res = await fetch('https://pokemonrevolution.net/spawns/land_spawns.json');
const data = await res.json();
const filteredData = data.filter((p) => p.Pokemon === 'Pikachu');
const embed = new MessageEmbed().setTitle('Pokemons');
const obj = { map: '', area: '', tier: '', levels: '', ms: '', item: '' };
filteredData.forEach((spawn) => {
obj.map += `\n${spawn.Map}`;
obj.area += `\nLand`;
obj.tier += `\n${spawn.Tier}`;
obj.levels += `\n${spawn.MinLVL}-${spawn.MaxLVL}`;
obj.ms += `\n${spawn.MemberOnly ? 'Yes' : 'No'}`;
obj.item += `\n${spawn.Item ? spawn.Item : '-'}`;
});
embed.addFields(
{ name: '#Map', value: obj.map, inline: true },
{ name: 'Area', value: obj.area, inline: true },
{ name: 'Tier', value: obj.tier, inline: true },
{ name: 'Levels', value: obj.levels, inline: true },
{ name: 'MS', value: obj.ms, inline: true },
{ name: 'Item', value: obj.item, inline: true },
);
message.channel.send(embed);
});
The result looked like this:
Endothermic_Dragon's solution was a bit closer to what you wanted, so I made an improved version of theirs. You can find it below:
client.on('message', async (message) => {
if (message.author.bot) return;
const res = await fetch('https://pokemonrevolution.net/spawns/land_spawns.json');
const data = await res.json();
const filteredData = data.filter((p) => p.Pokemon === 'Pikachu');
// number of empty characters between columns
const padding = 3;
const lengths = filteredData.reduce(
(acc, curr) => {
const level = `${curr.MinLVL}-${curr.MaxLVL}`;
const tier = curr.Tier.toString();
return {
levels: level.length > acc.levels ? level.length : acc.levels,
map: curr.Map.length > acc.map ? curr.Map.length : acc.map,
memberOnly: curr.memberOnly ? 'Yes'.length : 'No'.length,
tier: tier.length > acc.tier ? tier.length : acc.tier,
};
},
{
levels: 0,
map: 0,
memberOnly: 0,
tier: 0,
},
);
const header = [
'#Map'.padEnd(lengths.map + padding),
'Area'.padEnd('Area'.length + padding),
'Rarity'.padEnd(lengths.tier + 'Tier '.length + padding),
'Levels'.padEnd(lengths.levels + padding),
'Members Only'.padEnd('Members Only'.length + padding),
'Item',
].join('');
const table = filteredData.map((d) => [
d.Map.padEnd(lengths.map + padding),
'Land'.padEnd('Land'.length + padding),
`Tier ${`${d.Tier}`.padEnd(lengths.tier + padding)}`,
`${d.MinLVL}-${d.MaxLVL}`.padEnd(lengths.levels + padding),
`${d.MemberOnly ? 'Yes' : 'No'}`.padEnd('Members Only'.length + padding),
d.Item ? d.Item : '-',
].join(''))
.join('\n');
message.channel.send(`\`\`\`md\n${header}\n${table}\`\`\``);
});
It seems to be working as expected:
If you want to fetch from another endpoint if the first one yield no results, you can use the following code. I've made a few other changes and tried to add comments too:
function getDaytimeNames(daytime = []) {
let names = ['M', 'D', 'N'];
return daytime
.reduce((acc, curr, i) => (curr ? [...acc, names[i]] : acc), [])
.join('/');
}
async function fetchData(pokemon) {
let res = await fetch('https://pokemonrevolution.net/spawns/land_spawns.json');
let data = await res.json();
let reducer = (area) => (acc, curr) => curr.Pokemon.toLowerCase() !== pokemon.toLowerCase()
? acc
: [
...acc,
{
area,
daytime: getDaytimeNames(curr.Daytime),
item: curr.Item ? curr.Item : '-',
levels: `${curr.MinLVL}-${curr.MaxLVL}`,
map: curr.Map,
memberOnly: `${curr.MemberOnly ? 'Yes' : 'No'}`,
tier: `Tier ${curr.Tier}`,
},
];
let landReducer = reducer('Land');
let filteredData = data.reduce(landReducer, []);
if (filteredData.length > 0)
return filteredData;
let surfReducer = reducer('Surf');
// If there was no filtered data from land_spawns, try surf_spawns
res = await fetch('https://pokemonrevolution.net/spawns/surf_spawns.json');
data = await res.json();
filteredData = data.reduce(surfReducer, []);
return filteredData;
}
function createTable(data, padding) {
const addPadding = (str, length) => str.padEnd((length || str.length) + padding);
const getMaxLengths = (acc, curr) => {
const getLongest = (prop) => curr[prop].length > acc[prop] ? curr[prop].length : acc[prop];
return {
area: getLongest('area'),
daytime: getLongest('daytime'),
levels: getLongest('levels'),
map: getLongest('map'),
memberOnly: getLongest('memberOnly'),
tier: getLongest('tier'),
};
};
const lengths = data.reduce(getMaxLengths, {
area: 0,
daytime: 0,
levels: 0,
map: 0,
memberOnly: 0,
tier: 0,
});
const headers = [
addPadding('#Map', lengths.map),
addPadding('Area', lengths.area),
addPadding('Daytime'),
addPadding('Rarity', lengths.tier),
addPadding('Levels', lengths.levels),
addPadding('Members Only'),
// No padding needed as it's the last column
'Item',
].join('');
const createRow = (d) => [
addPadding(d.map, lengths.map),
addPadding(d.area, lengths.area),
addPadding(d.daytime, 'Daytime'.length),
addPadding(d.tier, lengths.tier),
addPadding(d.levels, lengths.levels),
addPadding(d.memberOnly, 'Members Only'.length),
d.item,
].join('');
const table = data.map(createRow).join('\n');
return `${headers}\n${table}`;
}
// Create an array of rows with a max length
// making sure it always has complete rows only
function chunkify(str, max) {
let chunks = [];
while (str.length > max) {
let i = str.substr(0, max).lastIndexOf('\n');
chunks.push(str.substr(0, i));
str = str.substr(i + 1, str.length);
}
if (str.length > 0) {
chunks.push(str);
}
return chunks;
}
client.on('message', async (message) => {
if (message.author.bot) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
const pokemon = args[0];
const data = await fetchData(pokemon);
// Number of empty characters between columns
const padding = 2;
// Discord only allows a maximum of 2000 characters for content
const maxLength = 1980;
const table = createTable(data, padding);
chunkify(table, maxLength)
.forEach((chunk) => message.channel.send(`\`\`\`md\n${chunk}\`\`\``));
});
Upvotes: 1
Reputation: 1187
Try this:
fetch(`https://pokemonrevolution.net/spawns/land_spawns.json`)
.then((res) => res.json())
.then(data => data.filter((p) => p.Pokemon === "Pikachu"))
.then(data => {
var mapLength = 0,
tierLength = 0,
minLevelLength = 0,
maxLevelLength = 0,
memberOnlyLength = 0,
itemLength = 0;
data.forEach(dataPoint => {
mapLength = (mapLength > dataPoint.Map.length) ? mapLength : dataPoint.Map.length;
tierLength = (tierLength > dataPoint.Tier.toString().length) ? tierLength : dataPoint.Tier.toString().length;
minLevelLength = (minLevelLength > dataPoint.MinLVL.toString().length) ? minLevelLength : dataPoint.MinLVL.toString().length;
maxLevelLength = (maxLevelLength > dataPoint.MaxLVL.toString().length) ? maxLevelLength : dataPoint.MaxLVL.toString().length;
if (dataPoint.MemberOnly) {
memberOnlyLength = (memberOnlyLength > "Yes") ? memberOnlyLength : 3
} else {
memberOnlyLength = (memberOnlyLength > "No") ? memberOnlyLength : 2
}
})
console.log(mapLength)
console.log(tierLength)
console.log(minLevelLength)
console.log(maxLevelLength)
console.log(memberOnlyLength)
console.log(itemLength)
data.map(dataPoint => {
dataPoint.Map = dataPoint.Map.padEnd(mapLength + 5)
dataPoint.Tier = dataPoint.Tier.toString().padEnd(tierLength + 5)
dataPoint.MinLVL = dataPoint.MinLVL.toString().padEnd(minLevelLength + 5)
dataPoint.MaxLVL = dataPoint.MaxLVL.toString().padEnd(maxLevelLength + 5)
if (dataPoint.MemberOnly) {
dataPoint.MemberOnly = "Yes".padEnd(memberOnlyLength + 5)
} else {
dataPoint.MemberOnly = "No".padEnd(memberOnlyLength + 5)
}
if (dataPoint.Item == null) {
dataPoint.Item = "-"
}
return dataPoint
})
totalString = "#Map".padEnd(mapLength + 5) + "Area " + "Rarity".padEnd(tierLength + 5) + "Min LVL".padEnd(minLevelLength + 5) + "Max LVL".padEnd(maxLevelLength + 5) + "Members Only".padEnd(memberOnlyLength + 5) + "Item" + "\n";
data.forEach(dataPoint => {
totalString += [dataPoint.Map, "Land ", "Tier " + dataPoint.Tier, dataPoint.MinLVL, dataPoint.MaxLVL, dataPoint.MemberOnly, dataPoint.Item].join('') + "\n"
})
console.log(totalString)
})
Note that the JS won't work here because of CORS, but it should work when you actually do it. Here's a screenshot of it working:
Upvotes: 0