aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cleaners/rank.ts6
-rw-r--r--src/cleaners/skyblock/profiles.ts4
-rw-r--r--src/database.ts37
-rw-r--r--src/hypixel.ts14
-rw-r--r--src/hypixelCached.ts6
-rw-r--r--src/index.ts2
-rw-r--r--src/util.ts14
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