import axios from 'axios'; import { WebhookClient, EmbedBuilder, Embed } from 'discord.js'; import { Worker } from 'worker_threads'; import { asyncInterval, addNotation } from './src/helperFunctions'; import { string } from 'prismarine-nbt'; import { loadConfig } from './src/configLoader'; const config = loadConfig(); let thread_count = config.data['thread_count/speed'] ?? 1; let lastUpdated = 0; let doneWorkers = 0; let startingTime; let maxPrice = 0; let itemDatas = {}; const workers: Worker[] = []; const webhookRegex = /https:\/\/discord.com\/api\/webhooks\/(.+)\/(.+)/; const bazaarPrice = { RECOMBOBULATOR_3000: 0, HOT_POTATO_BOOK: 0, FUMING_POTATO_BOOK: 0, }; async function initialize() { const matches = process.env.WEBHOOK_URL.match(webhookRegex); if (!matches) return console.log(`[Main thread] Couldn't parse Webhook URL`); const webhook = new WebhookClient({ id: matches[1], token: matches[2] }); await getBzData(); await getMoulberry(); await getLBINs(); for (let j = 0; j < thread_count; j++) { workers[j] = new Worker('/app/dist/AuctionHandler.worker.js', { workerData: { itemDatas: itemDatas, bazaarData: bazaarPrice, workerNumber: j, maxPrice: maxPrice, }, }); workers[j].on('message', async (result) => { if (result.itemData !== undefined) { let averagePrice = itemDatas[result.itemData.id]?.cleanPrice || 'N/A'; if ( result.auctionData.lbin - result.auctionData.price >= config.data.minSnipeProfit && averagePrice - result.auctionData.price >= config.data.minAvgProfit ) { let mustBuyMessage = ''; const embed = new EmbedBuilder() .setTitle(`**${result.itemData.name.replace(/ยง./g, '')}**`) .setColor('#2e3137') .setThumbnail(`https://sky.shiiyu.moe/item/${result.itemData.id}`) .setDescription( `${mustBuyMessage}\nAuction: \`\`\`/viewauction ${result.auctionData.auctionID}\`\`\` \nProfit: \`${addNotation( 'oneLetters', result.auctionData.profit )} (${result.auctionData.percentProfit}%)\` \nCost: \`${addNotation('oneLetters', result.auctionData.price)}\` \nLBIN: \`${addNotation('oneLetters', result.auctionData.lbin)}\` \nSales/Day: \`${addNotation( 'oneLetters', result.auctionData.sales )}\` \nType: \`${result.auctionData.ahType}\` \nAverage Price: \`${addNotation('oneLetters', averagePrice)}\`` ); await webhook.send({ username: process.env.WEBHOOK_NAME, avatarURL: process.env.WEBHOOK_PROFILE_PICTURE, embeds: [embed], }); } } else if (result === 'finished') { doneWorkers++; if (doneWorkers === thread_count) { doneWorkers = 0; console.log( `Completed in ${(Date.now() - startingTime) / 1000} seconds` ); startingTime = 0; workers[0].emit('done'); } } }); } asyncInterval( async () => { await getLBINs(); workers.forEach((worker) => { worker.postMessage({ type: 'moulberry', data: itemDatas }); }); }, 'lbin', 60000 ); asyncInterval( async () => { await getMoulberry(); workers.forEach((worker) => { worker.postMessage({ type: 'moulberry', data: itemDatas }); }); }, 'avg', 60e5 ); asyncInterval( async () => { return new Promise(async (resolve) => { const ahFirstPage = await axios.get( 'https://api.hypixel.net/skyblock/auctions?page=0' ); const totalPages = ahFirstPage.data.totalPages; if (ahFirstPage.data.lastUpdated === lastUpdated) { resolve(); } else { lastUpdated = ahFirstPage.data.lastUpdated; startingTime = Date.now(); console.log('Getting auctions..'); workers.forEach((worker) => { worker.postMessage({ type: 'pageCount', data: totalPages }); }); workers[0].once('done', () => { resolve(); }); } }); }, 'check', 0 ); } async function getLBINs(): Promise { const lbins = await axios.get('https://moulberry.codes/lowestbin.json'); const lbinData = lbins.data; for (const item of Object.keys(lbinData)) { if (!itemDatas[item]) itemDatas[item] = {}; itemDatas[item].lbin = lbinData[item]; } } async function getMoulberry(): Promise { const moulberryAvgs = await axios.get( 'https://moulberry.codes/auction_averages/3day.json' ); const avgData = moulberryAvgs.data; const cleanPriceAvgs = await axios.get( 'https://moulberry.codes/auction_averages_lbin/1day.json' ); const cleanPriceData = cleanPriceAvgs.data; for (const item of Object.keys(avgData)) { if (!itemDatas[item]) itemDatas[item] = {}; const itemInfo = avgData[item]; itemDatas[item].sales = itemInfo.sales !== undefined ? itemInfo.sales : 0; itemDatas[item].cleanPrice = cleanPriceData[item] !== undefined ? Math.round(cleanPriceData[item]) : itemInfo.clean_price !== undefined ? itemInfo.clean_price : itemInfo.price; } } async function getBzData(): Promise { const bzData = await axios.get('https://api.hypixel.net/skyblock/bazaar'); bazaarPrice['RECOMBOBULATOR_3000'] = bzData.data.products.RECOMBOBULATOR_3000.quick_status.buyPrice; bazaarPrice['HOT_POTATO_BOOK'] = bzData.data.products.HOT_POTATO_BOOK.quick_status.buyPrice; bazaarPrice['FUMING_POTATO_BOOK'] = bzData.data.products.FUMING_POTATO_BOOK.quick_status.buyPrice; } initialize();