diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cleaners/rank.ts | 6 | ||||
-rw-r--r-- | src/cleaners/skyblock/profiles.ts | 4 | ||||
-rw-r--r-- | src/database.ts | 37 | ||||
-rw-r--r-- | src/hypixel.ts | 14 | ||||
-rw-r--r-- | src/hypixelCached.ts | 6 | ||||
-rw-r--r-- | src/index.ts | 2 | ||||
-rw-r--r-- | src/util.ts | 14 |
7 files changed, 59 insertions, 24 deletions
diff --git a/src/cleaners/rank.ts b/src/cleaners/rank.ts index 2ce95c8..a9bc255 100644 --- a/src/cleaners/rank.ts +++ b/src/cleaners/rank.ts @@ -1,7 +1,7 @@ import typedHypixelApi from 'typed-hypixel-api' import { colorCodeFromName, minecraftColorCodes } from '../util.js' -const rankColors: { [name: string]: string } = { +export const RANK_COLORS: { [name: string]: string } = { 'NONE': '7', 'VIP': 'a', 'VIP+': 'a', @@ -69,8 +69,8 @@ export function cleanRank({ } const plusColor = rankPlusColor ? colorCodeFromName(rankPlusColor) : null - color = minecraftColorCodes[rankColors[name]] - let rankColorPrefix = rankColors[name] ? '§' + rankColors[name] : '' + color = minecraftColorCodes[RANK_COLORS[name]] + let rankColorPrefix = RANK_COLORS[name] ? '§' + RANK_COLORS[name] : '' // the text is white, but only in the prefix if (name === 'YOUTUBE') diff --git a/src/cleaners/skyblock/profiles.ts b/src/cleaners/skyblock/profiles.ts index f046e22..519c6d5 100644 --- a/src/cleaners/skyblock/profiles.ts +++ b/src/cleaners/skyblock/profiles.ts @@ -20,7 +20,9 @@ export function cleanPlayerSkyblockProfiles(rawProfiles: HypixelPlayerStatsSkyBl } /** Convert an array of raw profiles into clean profiles */ -export async function cleanSkyblockProfilesResponse(data: typedHypixelApi.SkyBlockProfilesResponse['profiles']): Promise<CleanFullProfile[]> { +export async function cleanSkyblockProfilesResponse(data: typedHypixelApi.SkyBlockProfilesResponse['profiles']): Promise<CleanFullProfile[] | null> { + if (data === null) return null + const promises: Promise<CleanFullProfile | null>[] = [] for (const profile of data) { promises.push(cleanSkyblockProfileResponse(profile)) diff --git a/src/database.ts b/src/database.ts index add5cb9..17b65e7 100644 --- a/src/database.ts +++ b/src/database.ts @@ -7,15 +7,15 @@ import { CleanFullProfile } from './cleaners/skyblock/profile.js' import { SLAYER_TIERS } from './cleaners/skyblock/slayers.js' import { Collection, Db, MongoClient, WithId } from 'mongodb' import { CleanMember } from './cleaners/skyblock/member.js' -import { CleanPlayer } from './cleaners/player.js' import * as cached from './hypixelCached.js' import * as constants from './constants.js' -import { letterFromColorCode, shuffle, sleep } from './util.js' +import { colorCodeFromName, letterFromColorCode, shuffle, sleep } from './util.js' import * as discord from './discord.js' import NodeCache from 'node-cache' import { v4 as uuid4 } from 'uuid' import { debug } from './index.js' import Queue from 'queue-promise' +import { RANK_COLORS } from './cleaners/rank.js' // don't update the user for 3 minutes const recentlyUpdated = new NodeCache({ @@ -69,12 +69,12 @@ interface profileRawLeaderboardItem { } interface MemberLeaderboardItem { - player: CleanPlayer | null + player: LeaderboardBasicPlayer profileUuid: string value: number } interface ProfileLeaderboardItem { - players: CleanPlayer[] + players: LeaderboardBasicPlayer[] profileUuid: string value: number } @@ -517,13 +517,26 @@ interface ProfileLeaderboard { info?: string } +interface LeaderboardBasicPlayer { + uuid: string + username: string + rank: { + color: string + } +} /** Fetch a leaderboard that ranks members, as opposed to profiles */ export async function fetchMemberLeaderboard(name: string): Promise<MemberLeaderboard> { const leaderboardRaw = await fetchMemberLeaderboardRaw(name) const fetchLeaderboardPlayer = async (i: memberRawLeaderboardItem): Promise<MemberLeaderboardItem> => { - const player = await cached.fetchBasicPlayer(i.uuid, false) + const player: LeaderboardBasicPlayer = { + uuid: i.uuid, + username: i.username, + rank: { + color: (i.color ? colorCodeFromName(i.color) : null) ?? colorCodeFromName(RANK_COLORS.NONE)!, + }, + } return { player, @@ -549,9 +562,15 @@ export async function fetchProfileLeaderboard(name: string): Promise<ProfileLead const leaderboardRaw = await fetchProfileLeaderboardRaw(name) const fetchLeaderboardProfile = async (i: profileRawLeaderboardItem): Promise<ProfileLeaderboardItem> => { - const players: CleanPlayer[] = [] + const players: LeaderboardBasicPlayer[] = [] for (const playerUuid of i.players) { - const player = await cached.fetchBasicPlayer(playerUuid) + const player: LeaderboardBasicPlayer = { + uuid: playerUuid, + username: i.usernames[i.players.indexOf(playerUuid)], + rank: { + color: i.colors[i.players.indexOf(playerUuid)] + } + } if (player) players.push(player) } @@ -742,9 +761,9 @@ export async function removeDeletedProfilesFromLeaderboards(memberUuid: string, uuid: memberUuid, profile: leaderboardProfile.profile }) - if (debug) { + if (debug) console.log(`Profile ${leaderboardProfile.profile} (member ${memberUuid}) was deleted but was still in leaderboards database, removed.`) - } + for (const leaderboardName in leaderboardProfile.stats) // we want to refresh the leaderboard so we just remove the cache cachedRawLeaderboards.delete(leaderboardName) diff --git a/src/hypixel.ts b/src/hypixel.ts index d01e699..fb0edb3 100644 --- a/src/hypixel.ts +++ b/src/hypixel.ts @@ -132,13 +132,13 @@ export async function fetchUser({ user, uuid, username }: UserAny, included: Inc delete playerData.profiles } if (includeProfiles) - profilesData = await cached.fetchSkyblockProfiles(uuid) + profilesData = await cached.fetchSkyblockProfiles(uuid) ?? [] let activeProfile: CleanProfile let lastOnline: number = 0 - if (includeProfiles) { - for (const profile of profilesData!) { + if (includeProfiles && profilesData !== undefined) { + for (const profile of profilesData) { const member = profile.members?.find(member => member.uuid === uuid) if (member && member.lastSave && member.lastSave > lastOnline) { lastOnline = member.lastSave @@ -147,7 +147,7 @@ export async function fetchUser({ user, uuid, username }: UserAny, included: Inc } // we don't await so it happens in the background - removeDeletedProfilesFromLeaderboards(uuid, profilesData!.map(p => p.uuid)) + removeDeletedProfilesFromLeaderboards(uuid, profilesData.map(p => p.uuid)) } let websiteAccount: WithId<AccountSchema> | null = null @@ -268,8 +268,8 @@ export async function fetchBasicProfileFromUuidUncached(profileUuid: string): Pr } -export async function fetchMemberProfilesUncached(playerUuid: string): Promise<CleanFullProfile[]> { - const profiles: CleanFullProfile[] = await sendCleanApiRequest( +export async function fetchMemberProfilesUncached(playerUuid: string): Promise<CleanFullProfile[] | null> { + const profiles = await sendCleanApiRequest( 'skyblock/profiles', { uuid: playerUuid }, { @@ -277,6 +277,8 @@ export async function fetchMemberProfilesUncached(playerUuid: string): Promise<C mainMemberUuid: playerUuid } ) + if (profiles === null) + return null for (const profile of profiles) { for (const member of profile.members) { queueUpdateDatabaseMember(member, profile) diff --git a/src/hypixelCached.ts b/src/hypixelCached.ts index e8195fb..aaea7c5 100644 --- a/src/hypixelCached.ts +++ b/src/hypixelCached.ts @@ -222,7 +222,7 @@ export async function fetchBasicPlayer(user: string, includeClaimed: boolean = t return player } -export async function fetchSkyblockProfiles(playerUuid: string): Promise<CleanProfile[]> { +export async function fetchSkyblockProfiles(playerUuid: string): Promise<CleanProfile[] | null> { if (profilesCache.has(playerUuid)) { if (debug) console.debug('Cache hit! fetchSkyblockProfiles', playerUuid) return profilesCache.get(playerUuid)! @@ -230,7 +230,9 @@ export async function fetchSkyblockProfiles(playerUuid: string): Promise<CleanPr if (debug) console.debug('Cache miss: fetchSkyblockProfiles', playerUuid) - const profiles: CleanFullProfile[] = await hypixel.fetchMemberProfilesUncached(playerUuid) + const profiles = await hypixel.fetchMemberProfilesUncached(playerUuid) + if (profiles === null) + return null const basicProfiles: CleanProfile[] = [] diff --git a/src/index.ts b/src/index.ts index 34f941b..cc0b369 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,7 +10,7 @@ import { register } from './metrics.js' const app = express() -export const debug = false +export const debug = true const mainSiteUrl = 'https://skyblock.matdoes.dev' diff --git a/src/util.ts b/src/util.ts index 0d91aba..4d40cc0 100644 --- a/src/util.ts +++ b/src/util.ts @@ -61,20 +61,22 @@ export const minecraftColorCodes: { [key: string]: string } = { * For example: blue -> 9 * @param colorName The name of the color (blue, red, aqua, etc) */ -export function colorCodeFromName(colorName: string): string | undefined { +export function colorCodeFromName(colorName: string): string | null { const hexColor = minecraftColorCodes[colorName.toLowerCase()] for (const key in minecraftColorCodes) { const value = minecraftColorCodes[key] if (key.length === 1 && value === hexColor) return key } + return null } -export function letterFromColorCode(colorCode: string): string | undefined { +export function letterFromColorCode(colorCode: string): string | null { for (const [key, value] of Object.entries(minecraftColorCodes)) { if (value === colorCode) return key } + return null } export async function sleep(ms: number): Promise<void> { @@ -95,3 +97,11 @@ export function levelFromXpTable(xp: number, xpTable: number[]) { const skillLevel = [...xpTable].reverse().findIndex(levelXp => xp >= levelXp) return skillLevel === -1 ? 0 : xpTable.length - skillLevel } + +// https://stackoverflow.com/a/51365037 +export type RecursivePartial<T> = { + [P in keyof T]?: + T[P] extends (infer U)[] ? RecursivePartial<U>[] : + T[P] extends object ? RecursivePartial<T[P]> : + T[P] +}
\ No newline at end of file |