diff options
Diffstat (limited to 'src/commands/utilities/price.ts')
-rw-r--r-- | src/commands/utilities/price.ts | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/src/commands/utilities/price.ts b/src/commands/utilities/price.ts new file mode 100644 index 0000000..231930c --- /dev/null +++ b/src/commands/utilities/price.ts @@ -0,0 +1,220 @@ +import { Constants } from 'discord-akairo'; +import { ColorResolvable, MessageEmbed } from 'discord.js'; +import Fuse from 'fuse.js'; +import got from 'got'; +import { BushCommand, BushMessage } from '../../lib'; + +interface Summary { + amount: number; + pricePerUnit: number; + orders: number; +} + +interface Bazaar { + success: boolean; + lastUpdated: number; + products: { + [key: string]: { + product_id: string; + sell_summary: Summary[]; + buy_summary: Summary[]; + quick_status: { + productId: string; + sellPrice: number; + sellVolume: number; + sellMovingWeek: number; + sellOrders: number; + buyPrice: number; + buyVolume: number; + buyMovingWeek: number; + buyOrders: number; + }; + }; + }; +} + +interface LowestBIN { + [key: string]: number; +} + +interface AuctionAverages { + [key: string]: { + price?: number; + count?: number; + sales?: number; + clean_price?: number; + clean_sales?: number; + }; +} + +export default class PriceCommand extends BushCommand { + public constructor() { + super('price', { + aliases: ['price'], + category: 'utilities', + clientPermissions: ['EMBED_LINKS', 'SEND_MESSAGES'], + description: { + usage: 'price <item id>', + examples: ['price ASPECT_OF_THE_END'], + content: 'Finds the price information of an item.' + }, + ratelimit: 4, + cooldown: 4000, + typing: true, + args: [ + { + id: 'item', + match: Constants.ArgumentMatches.CONTENT, + type: Constants.ArgumentTypes.STRING, + prompt: { + start: 'What item would you like to find the price of?', + retry: '{error} Choose a valid item.' + } + }, + { + id: 'strict', + match: Constants.ArgumentMatches.FLAG, + flag: '--strict', + default: false + } + ], + slash: true, + slashOptions: [ + { + name: 'item', + description: 'The item that you would you like to find the price of.', + type: 'STRING', + required: true + }, + { + name: 'strict', + description: 'Whether or not to bypass the fuzzy search.', + type: 'BOOLEAN', + required: false + } + ] + }); + } + + public async exec(message: BushMessage, { item, strict }: { item: string; strict: boolean }): Promise<unknown> { + const errors = new Array<string>(); + const bazaar: Bazaar = await get('https://api.hypixel.net/skyblock/bazaar').catch(() => errors.push('bazaar')); + const currentLowestBIN: LowestBIN = await get('https://moulberry.codes/lowestbin.json').catch(() => + errors.push('current lowest BIN') + ); + const averageLowestBIN: LowestBIN = await get('https://moulberry.codes/auction_averages_lbin/3day.json').catch(() => + errors.push('average Lowest BIN') + ); + const auctionAverages: AuctionAverages = await get('https://moulberry.codes/auction_averages/3day.json').catch(() => + errors.push('auction average') + ); + // adds _ to item name + let parsedItem = item.toString().toUpperCase().replace(/ /g, '_').replace(/'S/g, ''); + const priceEmbed = new MessageEmbed(); + + if (errors?.length) { + priceEmbed.setFooter; + } + + //combines all the item names from each + const itemNames = Array.from( + new Set( + (averageLowestBIN ? Object.keys(averageLowestBIN) : []).concat( + currentLowestBIN ? Object.keys(currentLowestBIN) : [], + auctionAverages ? Object.keys(auctionAverages) : [], + bazaar?.products ? Object.keys(bazaar.products) : [] + ) + ) + ); + + // fuzzy search + if (!strict) { + parsedItem = new Fuse(itemNames)?.search(parsedItem)[0]?.item; + } + + // If bazaar item then it there should not be any ah data + if (bazaar['products'][parsedItem]) { + const bazaarPriceEmbed = new MessageEmbed() + .setColor( + errors?.length + ? (this.client.util.emojis.warn as ColorResolvable) + : (this.client.util.colors.success as ColorResolvable) + ) + .setTitle(`Bazaar Information for \`${parsedItem}\``) + .addField('Sell Price', Bazaar('sellPrice', 2, true)) + .addField('Buy Price', Bazaar('buyPrice', 2, true)) + .addField('Margin', (Number(Bazaar('buyPrice', 2, false)) - Number(Bazaar('sellPrice', 2, false))).toLocaleString()) + .addField('Current Sell Orders', Bazaar('sellOrders', 0, true)) + .addField('Current Buy Orders', Bazaar('buyOrders', 0, true)); + return await message.util.reply({ embeds: [bazaarPriceEmbed] }); + } + + // Checks if the item exists in any of the action information otherwise it is not a valid item + if (currentLowestBIN?.[parsedItem] || averageLowestBIN?.[parsedItem] || auctionAverages?.[parsedItem]) { + priceEmbed + .setColor(this.client.util.colors.success) + .setTitle(`Price Information for \`${parsedItem}\``) + .setFooter('All information is based on the last 3 days.'); + } else { + const errorEmbed = new MessageEmbed(); + errorEmbed + .setColor(this.client.util.colors.error) + .setDescription( + `${this.client.util.emojis.error} \`${parsedItem}\` is not a valid item id, or it has no auction data.` + ); + return await message.util.reply({ embeds: [errorEmbed] }); + } + + if (currentLowestBIN?.[parsedItem]) { + const currentLowestBINPrice = currentLowestBIN[parsedItem].toLocaleString(); + priceEmbed.addField('Current Lowest BIN', currentLowestBINPrice); + } + if (averageLowestBIN?.[parsedItem]) { + const averageLowestBINPrice = averageLowestBIN[parsedItem].toLocaleString(); + priceEmbed.addField('Average Lowest BIN', averageLowestBINPrice); + } + if (auctionAverages?.[parsedItem]?.price) { + const auctionAveragesPrice = auctionAverages[parsedItem].price.toLocaleString(); + priceEmbed.addField('Average Auction Price', auctionAveragesPrice); + } + if (auctionAverages?.[parsedItem]?.count) { + const auctionAveragesCountPrice = auctionAverages[parsedItem].count.toLocaleString(); + priceEmbed.addField('Average Auction Count', auctionAveragesCountPrice); + } + if (auctionAverages?.[parsedItem]?.sales) { + const auctionAveragesSalesPrice = auctionAverages[parsedItem].sales.toLocaleString(); + priceEmbed.addField('Average Auction Sales', auctionAveragesSalesPrice); + } + if (auctionAverages?.[parsedItem]?.clean_price) { + const auctionAveragesCleanPrice = auctionAverages[parsedItem].clean_price.toLocaleString(); + priceEmbed.addField('Average Auction Clean Price', auctionAveragesCleanPrice); + } + if (auctionAverages?.[parsedItem]?.clean_sales) { + const auctionAveragesCleanSales = auctionAverages[parsedItem].clean_sales.toLocaleString(); + priceEmbed.addField('Average Auction Clean Sales', auctionAveragesCleanSales); + } + return await message.util.reply({ embeds: [priceEmbed] }); + + //Helper functions + function Bazaar(Information: string, digits: number, commas: boolean): string { + const price = bazaar?.products[parsedItem]?.quick_status?.[Information]; + const a = Number(Number(price).toFixed(digits)); + return commas ? a?.toLocaleString() : a?.toString(); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + async function get(url: string): Promise<any> { + const data = await got.get(url).catch((error) => { + this.client.console.warn('PriceCommand', `There was an problem fetching data from <<${url}>> with error:\n${error}`); + throw 'Error Fetching price data'; + }); + try { + const json = JSON.parse(data.body); + return json; + } catch (error) { + this.client.console.warn('PriceCommand', `There was an problem parsing data from <<${url}>> with error:\n${error}`); + throw 'json error'; + } + } + } +} |