diff options
-rw-r--r-- | .gitpod.yml | 2 | ||||
-rw-r--r-- | src/cleaners/skyblock/itemList.ts | 60 | ||||
-rw-r--r-- | src/cleaners/skyblock/pets.ts | 10 | ||||
-rw-r--r-- | src/hypixel.ts | 39 | ||||
-rw-r--r-- | src/index.ts | 13 |
5 files changed, 118 insertions, 6 deletions
diff --git a/.gitpod.yml b/.gitpod.yml index 92eee2d..f9a34b3 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -11,5 +11,5 @@ tasks: ports: - port: 8080 - onOpen: open-browser + onOpen: ignore diff --git a/src/cleaners/skyblock/itemList.ts b/src/cleaners/skyblock/itemList.ts new file mode 100644 index 0000000..a534628 --- /dev/null +++ b/src/cleaners/skyblock/itemList.ts @@ -0,0 +1,60 @@ +import typedHypixelApi from 'typed-hypixel-api' + +export interface ItemRequirement { + // idk what these do + // they'll probably be renamed at some point + dungeon: { + type: string + level: number + } +} + +// based on Item from inventory.ts +export interface ItemListItem { + id: string + vanillaId: string + tier: string | null + display: { + name: string + glint: boolean + } + npc_sell_price: number | null + requirements: ItemRequirement | null +} + +export interface ItemListData { + lastUpdated: number + list: ItemListItem[] +} + +function cleanItemRequirements(data: typedHypixelApi.SkyBlockItemsResponse['items'][number]['requirements'] & typedHypixelApi.SkyBlockItemsResponse['items'][number]['catacombs_requirements']): ItemRequirement | null { + if (!data || !data.dungeon) return null + return { + dungeon: { + type: data.dungeon.type, + level: data.dungeon.level + } + } +} + +function cleanItemListItem(item: typedHypixelApi.SkyBlockItemsResponse['items'][number]): ItemListItem { + const vanillaId = item.material.toLowerCase() + return { + id: item.id, + vanillaId: item.durability ? `${vanillaId}:${item.durability}` : vanillaId, + tier: item.tier ?? null, + display: { + name: item.name, + glint: item.glowing ?? false + }, + npc_sell_price: item.npc_sell_price ?? null, + requirements: cleanItemRequirements(item.catacombs_requirements ?? item.requirements) + } +} + +export async function cleanItemListResponse(data: typedHypixelApi.SkyBlockItemsResponse): Promise<ItemListData> { + return { + lastUpdated: data.lastUpdated, + list: data.items.map(cleanItemListItem) + } +}
\ No newline at end of file diff --git a/src/cleaners/skyblock/pets.ts b/src/cleaners/skyblock/pets.ts index d6265e5..4c0fe4a 100644 --- a/src/cleaners/skyblock/pets.ts +++ b/src/cleaners/skyblock/pets.ts @@ -1,6 +1,8 @@ import typedHypixelApi from 'typed-hypixel-api' -import { fetchPets } from '../../constants.js' +import { fetchItemList } from '../../hypixel.js' import { levelFromXpTable } from '../../util.js' +import { fetchPets } from '../../constants.js' +import { ItemListItem } from './itemList.js' // https://hypixel-skyblock.fandom.com/wiki/Module:Pet/LevelingData?action=edit @@ -43,7 +45,7 @@ export interface Pet { level: number tier: typedHypixelApi.Pet['tier'] skin: string | null - item: string | null + item: ItemListItem | null } export interface PetsData { @@ -59,6 +61,8 @@ export async function cleanPets(data: typedHypixelApi.SkyBlockProfileMember): Pr const allPetIds = await fetchPets() const obtainedPetIds: string[] = [] + const itemList = await fetchItemList() + for (const petData of data.pets ?? []) { const xpTable = RARITY_XP_TABLES[petData.tier] const level = levelFromXpTable(petData.exp, xpTable) @@ -69,7 +73,7 @@ export async function cleanPets(data: typedHypixelApi.SkyBlockProfileMember): Pr level, tier: petData.tier, skin: petData.skin ?? null, - item: petData.heldItem + item: petData.heldItem ? (itemList.list.find(i => i.id === petData.heldItem) ?? null) : null } obtainedPetIds.push(pet.id) obtainedPets.push(pet) diff --git a/src/hypixel.ts b/src/hypixel.ts index 30a9f9b..80c73b1 100644 --- a/src/hypixel.ts +++ b/src/hypixel.ts @@ -25,6 +25,7 @@ import typedHypixelApi from 'typed-hypixel-api' import * as cached from './hypixelCached.js' import { debug } from './index.js' import { WithId } from 'mongodb' +import { cleanItemListResponse, ItemListData } from './cleaners/skyblock/itemList.js' export type Included = 'profiles' | 'player' | 'stats' | 'inventories' | undefined @@ -56,7 +57,8 @@ const cleanResponseFunctions = { 'player': (data, options) => cleanPlayerResponse(data.player), 'skyblock/profile': (data: typedHypixelApi.SkyBlockProfileResponse, options) => cleanSkyblockProfileResponse(data.profile, options), 'skyblock/profiles': (data, options) => cleanSkyblockProfilesResponse(data.profiles), - 'resources/skyblock/election': (data, options) => cleanElectionResponse(data) + 'resources/skyblock/election': (data, options) => cleanElectionResponse(data), + 'resources/skyblock/items': (data, options) => cleanItemListResponse(data) } as const @@ -310,3 +312,38 @@ export async function fetchElection(): Promise<ElectionData> { return election } + +let isFetchingItemList = false +let cachedItemListData: ItemListData | null = null +let nextItemListUpdate: Date = new Date(0) + +export async function fetchItemList() { + if (cachedItemListData && nextItemListUpdate > new Date()) + return cachedItemListData + + // if it's currently fetching the election data and it doesn't have it, + // wait until we do have the election data + if (isFetchingItemList && !cachedItemListData) { + await new Promise(resolve => { + const interval = setInterval(() => { + if (cachedItemListData) { + clearInterval(interval) + resolve(cachedItemListData) + } + }, 100) + }) + } + + isFetchingItemList = true + const itemList: ItemListData = await sendCleanApiRequest( + 'resources/skyblock/items', + {} + ) + isFetchingItemList = false + + cachedItemListData = itemList + // updates every 60 minutes + nextElectionUpdate = new Date((itemList.lastUpdated + 60 * 60) * 1000) + return itemList +} + diff --git a/src/index.ts b/src/index.ts index 4464ca7..460fec3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ import { createSession, fetchAccountFromDiscord, fetchAllLeaderboardsCategorized, fetchLeaderboard, fetchMemberLeaderboardSpots, fetchSession, finishedCachingRawLeaderboards, leaderboardUpdateMemberQueue, leaderboardUpdateProfileQueue, updateAccount, fetchServerStatus, deleteSession } from './database.js' -import { fetchElection, fetchMemberProfile, fetchUser } from './hypixel.js' +import { fetchElection, fetchItemList, fetchMemberProfile, fetchUser } from './hypixel.js' import rateLimit from 'express-rate-limit' import * as constants from './constants.js' import * as discord from './discord.js' @@ -153,6 +153,17 @@ app.get('/election', async (req, res) => { } }) +app.get('/items', async (req, res) => { + try { + res.json( + await fetchItemList() + ) + } catch (err) { + console.error(err) + res.json({ ok: false }) + } +}) + app.post('/accounts/createsession', async (req, res) => { try { const { code } = req.body |