mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 11:39:50 +02:00
feat: data driven latest archived season number
This commit is contained in:
1 parent
d1ebb79432
commit
f02db2a2d8
13 files changed
+145
-96
No files matched your search
@@ -0,0 +1,12 @@
|
|||||||
|
import { NextResponse } from 'next/server';
|
||||||
|
import { Region } from '../../../../../../constants/regions';
|
||||||
|
import { getArchivedRatingsLeaderboard } from '../../../../../../core/blitzkrieg/getArchivedRatingsLeaderboard';
|
||||||
|
|
||||||
|
export async function GET(
|
||||||
|
request: Request,
|
||||||
|
{ params }: { params: { region: Region; season: number } },
|
||||||
|
) {
|
||||||
|
return NextResponse.json(
|
||||||
|
await getArchivedRatingsLeaderboard(params.region, params.season),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { NextResponse } from 'next/server';
|
||||||
|
import { getArchivedLatestSeasonNumber } from '../../../../core/blitzkrieg/getArchivedLatestSeasonNumber';
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
return NextResponse.json(await getArchivedLatestSeasonNumber());
|
||||||
|
}
|
||||||
@@ -7,11 +7,11 @@ import { useEffect, useState } from 'react';
|
|||||||
import { RatingsInfo } from '../../../commands/ratings';
|
import { RatingsInfo } from '../../../commands/ratings';
|
||||||
import PageWrapper from '../../../components/PageWrapper';
|
import PageWrapper from '../../../components/PageWrapper';
|
||||||
import { REGIONS, REGION_NAMES, Region } from '../../../constants/regions';
|
import { REGIONS, REGION_NAMES, Region } from '../../../constants/regions';
|
||||||
|
import getRatingsInfo from '../../../core/blitz/getRatingsInfo';
|
||||||
import {
|
import {
|
||||||
FIRST_ARCHIVED_RATINGS_SEASON,
|
FIRST_ARCHIVED_RATINGS_SEASON,
|
||||||
getLatestArchivedSeasonNumber,
|
getArchivedLatestSeasonNumberAPI,
|
||||||
} from '../../../core/blitz/getLatestArchivedSeasonNumber';
|
} from '../../../core/blitzkrieg/getArchivedLatestSeasonNumberAPI';
|
||||||
import getRatingsInfo from '../../../core/blitz/getRatingsInfo';
|
|
||||||
import { useRatings } from '../../../stores/ratings';
|
import { useRatings } from '../../../stores/ratings';
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
@@ -27,8 +27,8 @@ export default function Page() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const [newRatingsInfo, newLatestArchivedSeasonNumber] = await Promise.all(
|
const [newRatingsInfo, newLatestArchivedSeasonNumber] = await Promise.all(
|
||||||
[getRatingsInfo(ratings.region), getLatestArchivedSeasonNumber()],
|
[getRatingsInfo(ratings.region), getArchivedLatestSeasonNumberAPI()],
|
||||||
);
|
);
|
||||||
|
|
||||||
setRatingsInfo(newRatingsInfo);
|
setRatingsInfo(newRatingsInfo);
|
||||||
setLatestArchivedSeasonNumber(newLatestArchivedSeasonNumber);
|
setLatestArchivedSeasonNumber(newLatestArchivedSeasonNumber);
|
||||||
|
|||||||
+30
-72
@@ -4,6 +4,7 @@ import {
|
|||||||
SlashCommandSubcommandBuilder,
|
SlashCommandSubcommandBuilder,
|
||||||
SlashCommandSubcommandGroupBuilder,
|
SlashCommandSubcommandGroupBuilder,
|
||||||
} from 'discord.js';
|
} from 'discord.js';
|
||||||
|
import { range } from 'lodash';
|
||||||
import { BlitzkriegRatingsLeaderboard } from '../../scripts/buildRatingsLeaderboard';
|
import { BlitzkriegRatingsLeaderboard } from '../../scripts/buildRatingsLeaderboard';
|
||||||
import * as Leaderboard from '../components/Leaderboard';
|
import * as Leaderboard from '../components/Leaderboard';
|
||||||
import TitleBar from '../components/TitleBar';
|
import TitleBar from '../components/TitleBar';
|
||||||
@@ -13,11 +14,11 @@ import { getAccountInfo } from '../core/blitz/getAccountInfo';
|
|||||||
import { getClanAccountInfo } from '../core/blitz/getClanAccountInfo';
|
import { getClanAccountInfo } from '../core/blitz/getClanAccountInfo';
|
||||||
import getRatingsInfo from '../core/blitz/getRatingsInfo';
|
import getRatingsInfo from '../core/blitz/getRatingsInfo';
|
||||||
import regionToRegionSubdomain from '../core/blitz/regionToRegionSubdomain';
|
import regionToRegionSubdomain from '../core/blitz/regionToRegionSubdomain';
|
||||||
|
import { getArchivedLatestSeasonNumber } from '../core/blitzkrieg/getArchivedLatestSeasonNumber';
|
||||||
|
import { FIRST_ARCHIVED_RATINGS_SEASON } from '../core/blitzkrieg/getArchivedLatestSeasonNumberAPI';
|
||||||
import getArchivedRatingsInfo from '../core/blitzkrieg/getArchivedRatingsInfo';
|
import getArchivedRatingsInfo from '../core/blitzkrieg/getArchivedRatingsInfo';
|
||||||
import getMidnightLeaderboard, {
|
import { getArchivedRatingsLeaderboard } from '../core/blitzkrieg/getArchivedRatingsLeaderboard';
|
||||||
DATABASE_REPO,
|
import getArchivedRatingsMidnightLeaderboard from '../core/blitzkrieg/getArchivedRatingsMidnightLeaderboard';
|
||||||
} from '../core/blitzkrieg/getMidnightLeaderboard';
|
|
||||||
import { octokit } from '../core/blitzkrieg/octokit';
|
|
||||||
import { UserError } from '../core/blitzkrieg/userError';
|
import { UserError } from '../core/blitzkrieg/userError';
|
||||||
import addRegionChoices from '../core/discord/addRegionChoices';
|
import addRegionChoices from '../core/discord/addRegionChoices';
|
||||||
import addUsernameChoices from '../core/discord/addUsernameChoices';
|
import addUsernameChoices from '../core/discord/addUsernameChoices';
|
||||||
@@ -178,23 +179,17 @@ const noOngoingSeason = embedNegative(
|
|||||||
|
|
||||||
export const ratingsCommand = new Promise<CommandRegistryRaw>(
|
export const ratingsCommand = new Promise<CommandRegistryRaw>(
|
||||||
async (resolve) => {
|
async (resolve) => {
|
||||||
const seasonChoices = await octokit.repos
|
const latestArchivedSeasonNumber = await getArchivedLatestSeasonNumber();
|
||||||
.getContent({
|
const seasonChoices = range(
|
||||||
...DATABASE_REPO,
|
FIRST_ARCHIVED_RATINGS_SEASON,
|
||||||
path: 'com/ratings',
|
latestArchivedSeasonNumber + 1,
|
||||||
})
|
).map(
|
||||||
.then(({ data }) => {
|
(number) =>
|
||||||
if (!Array.isArray(data)) {
|
({
|
||||||
throw new Error('Archived ratings data is malformed');
|
name: `Season ${number}`,
|
||||||
}
|
value: `${number}`,
|
||||||
return data.map(
|
}) satisfies APIApplicationCommandOptionChoice<string>,
|
||||||
(folder) =>
|
);
|
||||||
({
|
|
||||||
name: `Season ${folder.name}`,
|
|
||||||
value: folder.name,
|
|
||||||
}) satisfies APIApplicationCommandOptionChoice<string>,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const command = new SlashCommandBuilder()
|
const command = new SlashCommandBuilder()
|
||||||
.setName('ratings')
|
.setName('ratings')
|
||||||
@@ -262,7 +257,7 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
|
|||||||
const region = interaction.options.getString('region') as Region;
|
const region = interaction.options.getString('region') as Region;
|
||||||
regionRatingsInfo = await (subcommandGroup === 'current'
|
regionRatingsInfo = await (subcommandGroup === 'current'
|
||||||
? getRatingsInfo(region)
|
? getRatingsInfo(region)
|
||||||
: getArchivedRatingsInfo(season!, region));
|
: getArchivedRatingsInfo(region, season!));
|
||||||
|
|
||||||
if (regionRatingsInfo.detail !== undefined) return noOngoingSeason;
|
if (regionRatingsInfo.detail !== undefined) return noOngoingSeason;
|
||||||
|
|
||||||
@@ -285,19 +280,8 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
|
|||||||
}) satisfies SimplifiedPlayer,
|
}) satisfies SimplifiedPlayer,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: await octokit.repos
|
: await getArchivedRatingsLeaderboard(region, season!).then(
|
||||||
.getContent({
|
async (players) => {
|
||||||
...DATABASE_REPO,
|
|
||||||
path: `${region}/ratings/${season}/latest.json`,
|
|
||||||
})
|
|
||||||
.then(async ({ data }) => {
|
|
||||||
if (Array.isArray(data) || data.type !== 'file') {
|
|
||||||
throw new Error('Archived ratings data is malformed');
|
|
||||||
}
|
|
||||||
|
|
||||||
const players = (await fetch(data.download_url!).then(
|
|
||||||
(response) => response.json(),
|
|
||||||
)) as BlitzkriegRatingsLeaderboard;
|
|
||||||
const firstPlayerIndex =
|
const firstPlayerIndex =
|
||||||
leagueIndex === 0
|
leagueIndex === 0
|
||||||
? 0
|
? 0
|
||||||
@@ -328,15 +312,16 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
|
|||||||
`Unknown Player ${player.id}`,
|
`Unknown Player ${player.id}`,
|
||||||
}) satisfies SimplifiedPlayer,
|
}) satisfies SimplifiedPlayer,
|
||||||
);
|
);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
const leagueInfo = regionRatingsInfo.leagues[leagueIndex];
|
const leagueInfo = regionRatingsInfo.leagues[leagueIndex];
|
||||||
midnightLeaderboard =
|
midnightLeaderboard =
|
||||||
subcommandGroup === 'current'
|
subcommandGroup === 'current'
|
||||||
? await getMidnightLeaderboard(
|
? await getArchivedRatingsMidnightLeaderboard(
|
||||||
region,
|
region,
|
||||||
regionRatingsInfo.current_season,
|
regionRatingsInfo.current_season,
|
||||||
)
|
)
|
||||||
: await getMidnightLeaderboard(region, season!);
|
: await getArchivedRatingsMidnightLeaderboard(region, season!);
|
||||||
|
|
||||||
players = result;
|
players = result;
|
||||||
playersBefore = result ? result[0].position - 1 : 0;
|
playersBefore = result ? result[0].position - 1 : 0;
|
||||||
@@ -354,21 +339,7 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
|
|||||||
regionRatingsInfo =
|
regionRatingsInfo =
|
||||||
subcommandGroup === 'current'
|
subcommandGroup === 'current'
|
||||||
? await getRatingsInfo(region)
|
? await getRatingsInfo(region)
|
||||||
: await octokit.repos
|
: await getArchivedRatingsInfo(region, season!);
|
||||||
.getContent({
|
|
||||||
...DATABASE_REPO,
|
|
||||||
path: `${region}/ratings/${season}/info.json`,
|
|
||||||
})
|
|
||||||
.then(async ({ data }) => {
|
|
||||||
if (Array.isArray(data) || data.type !== 'file') {
|
|
||||||
throw new Error('Archived ratings info is malformed');
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = fetch(data.download_url!);
|
|
||||||
return (await response.then((response) =>
|
|
||||||
response.json(),
|
|
||||||
)) as RatingsInfo;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (regionRatingsInfo.detail !== undefined) return noOngoingSeason;
|
if (regionRatingsInfo.detail !== undefined) return noOngoingSeason;
|
||||||
|
|
||||||
@@ -397,22 +368,8 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
|
|||||||
}) satisfies SimplifiedPlayer,
|
}) satisfies SimplifiedPlayer,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: await octokit.repos
|
: await getArchivedRatingsLeaderboard(region, season!).then(
|
||||||
.getContent({
|
async (players) => {
|
||||||
...DATABASE_REPO,
|
|
||||||
path: `${region}/ratings/${season}/latest.json`,
|
|
||||||
})
|
|
||||||
.then(async ({ data }) => {
|
|
||||||
if (Array.isArray(data) || data.type !== 'file') {
|
|
||||||
throw new Error(
|
|
||||||
'Archived ratings latest data is malformed',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = fetch(data.download_url!);
|
|
||||||
const players = (await response.then((response) =>
|
|
||||||
response.json(),
|
|
||||||
)) as BlitzkriegRatingsLeaderboard;
|
|
||||||
const playerIndex = players.findIndex(
|
const playerIndex = players.findIndex(
|
||||||
(player) => player.id === id,
|
(player) => player.id === id,
|
||||||
);
|
);
|
||||||
@@ -445,14 +402,15 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
|
|||||||
clan: clanData[player.id]!.clan?.tag,
|
clan: clanData[player.id]!.clan?.tag,
|
||||||
nickname: clanData[player.id]!.account_name,
|
nickname: clanData[player.id]!.account_name,
|
||||||
}));
|
}));
|
||||||
});
|
},
|
||||||
|
);
|
||||||
midnightLeaderboard =
|
midnightLeaderboard =
|
||||||
subcommandGroup === 'current'
|
subcommandGroup === 'current'
|
||||||
? await getMidnightLeaderboard(
|
? await getArchivedRatingsMidnightLeaderboard(
|
||||||
region,
|
region,
|
||||||
regionRatingsInfo.current_season,
|
regionRatingsInfo.current_season,
|
||||||
)
|
)
|
||||||
: await getMidnightLeaderboard(region, season!);
|
: await getArchivedRatingsMidnightLeaderboard(region, season!);
|
||||||
|
|
||||||
if (clan && neighbors) titleNameDiscriminator = `[${clan.tag}]`;
|
if (clan && neighbors) titleNameDiscriminator = `[${clan.tag}]`;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
/**
|
|
||||||
* The first every season that Blitzkrieg tracked :)
|
|
||||||
*/
|
|
||||||
export const FIRST_ARCHIVED_RATINGS_SEASON = 49;
|
|
||||||
|
|
||||||
export async function getLatestArchivedSeasonNumber() {
|
|
||||||
return 51;
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
type Context = 'website' | 'bot';
|
type Context = 'website' | 'server';
|
||||||
|
|
||||||
export const context: Context =
|
export const context: Context =
|
||||||
typeof window === 'undefined' ? 'bot' : 'website';
|
typeof window === 'undefined' ? 'server' : 'website';
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { DATABASE_REPO } from './getArchivedRatingsMidnightLeaderboard';
|
||||||
|
import { octokit } from './octokit';
|
||||||
|
|
||||||
|
let cachedLatestArchivedSeasonNumber: number | null = null;
|
||||||
|
|
||||||
|
export async function getArchivedLatestSeasonNumber() {
|
||||||
|
if (cachedLatestArchivedSeasonNumber) {
|
||||||
|
return cachedLatestArchivedSeasonNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data } = await octokit.repos.getContent({
|
||||||
|
...DATABASE_REPO,
|
||||||
|
path: 'com/ratings',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!Array.isArray(data)) {
|
||||||
|
throw new Error('Archived ratings data is malformed');
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedLatestArchivedSeasonNumber = Math.max(
|
||||||
|
...data.map(({ name }) => parseInt(name)),
|
||||||
|
);
|
||||||
|
|
||||||
|
return cachedLatestArchivedSeasonNumber;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
let cachedLatestArchivedSeasonNumber: number | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first every season that Blitzkrieg tracked :)
|
||||||
|
*/
|
||||||
|
export const FIRST_ARCHIVED_RATINGS_SEASON = 49;
|
||||||
|
|
||||||
|
export async function getArchivedLatestSeasonNumberAPI() {
|
||||||
|
if (cachedLatestArchivedSeasonNumber) {
|
||||||
|
return cachedLatestArchivedSeasonNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(`/api/ratings/latest-archived-season-number`);
|
||||||
|
const number = parseInt(await response.text());
|
||||||
|
cachedLatestArchivedSeasonNumber = number;
|
||||||
|
|
||||||
|
return cachedLatestArchivedSeasonNumber;
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { RatingsInfo } from '../../commands/ratings';
|
import { RatingsInfo } from '../../commands/ratings';
|
||||||
import { Region } from '../../constants/regions';
|
import { Region } from '../../constants/regions';
|
||||||
import { DATABASE_REPO } from './getMidnightLeaderboard';
|
import { DATABASE_REPO } from './getArchivedRatingsMidnightLeaderboard';
|
||||||
import { octokit } from './octokit';
|
import { octokit } from './octokit';
|
||||||
|
|
||||||
const ARCHIVED_RATINGS_CACHE: Record<
|
const INFO_CACHE: Record<
|
||||||
Region,
|
Region,
|
||||||
Record<
|
Record<
|
||||||
number,
|
number,
|
||||||
@@ -18,11 +18,11 @@ const ARCHIVED_RATINGS_CACHE: Record<
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function getArchivedRatingsInfo(
|
export default async function getArchivedRatingsInfo(
|
||||||
season: number,
|
|
||||||
region: Region,
|
region: Region,
|
||||||
|
season: number,
|
||||||
) {
|
) {
|
||||||
if (ARCHIVED_RATINGS_CACHE[region][season]) {
|
if (INFO_CACHE[region][season]) {
|
||||||
return ARCHIVED_RATINGS_CACHE[region][season];
|
return INFO_CACHE[region][season];
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data } = await octokit.repos.getContent({
|
const { data } = await octokit.repos.getContent({
|
||||||
@@ -38,7 +38,7 @@ export default async function getArchivedRatingsInfo(
|
|||||||
detail: undefined;
|
detail: undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
ARCHIVED_RATINGS_CACHE[region][season] = jsonContent;
|
INFO_CACHE[region][season] = jsonContent;
|
||||||
|
|
||||||
return jsonContent;
|
return jsonContent;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { BlitzkriegRatingsLeaderboard } from '../../../scripts/buildRatingsLeaderboard';
|
||||||
|
import { Region } from '../../constants/regions';
|
||||||
|
import { DATABASE_REPO } from './getArchivedRatingsMidnightLeaderboard';
|
||||||
|
import { octokit } from './octokit';
|
||||||
|
|
||||||
|
const LEADERBOARD_CACHE: Record<
|
||||||
|
Region,
|
||||||
|
Record<number, BlitzkriegRatingsLeaderboard>
|
||||||
|
> = {
|
||||||
|
asia: {},
|
||||||
|
eu: {},
|
||||||
|
com: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function getArchivedRatingsLeaderboard(
|
||||||
|
region: Region,
|
||||||
|
season: number,
|
||||||
|
) {
|
||||||
|
if (LEADERBOARD_CACHE[region][season]) {
|
||||||
|
return LEADERBOARD_CACHE[region][season];
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data } = await octokit.repos.getContent({
|
||||||
|
...DATABASE_REPO,
|
||||||
|
path: `${region}/ratings/${season}/latest.json`,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Array.isArray(data) || data.type !== 'file') {
|
||||||
|
throw new Error('Archived ratings data is malformed');
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(data.download_url!);
|
||||||
|
const json = (await response.json()) as BlitzkriegRatingsLeaderboard;
|
||||||
|
|
||||||
|
LEADERBOARD_CACHE[region][season] = json;
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
+1
-1
@@ -13,7 +13,7 @@ const MIDNIGHT_LEADERBOARD_CACHE: Record<
|
|||||||
asia: {},
|
asia: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function getMidnightLeaderboard(
|
export default async function getArchivedRatingsMidnightLeaderboard(
|
||||||
region: Region,
|
region: Region,
|
||||||
season: number,
|
season: number,
|
||||||
) {
|
) {
|
||||||
@@ -90,7 +90,7 @@ export const tankAverages = fetch(
|
|||||||
)
|
)
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
if (context === 'bot') {
|
if (context === 'server') {
|
||||||
const partialTankAverages: TankAverages = {};
|
const partialTankAverages: TankAverages = {};
|
||||||
|
|
||||||
(json as IndividualTankAverage[]).forEach((individualTankAverage) => {
|
(json as IndividualTankAverage[]).forEach((individualTankAverage) => {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export const tankopedia = fetch(
|
|||||||
)
|
)
|
||||||
.then(async (response) => response.json())
|
.then(async (response) => response.json())
|
||||||
.then((wrapperTankopedia) =>
|
.then((wrapperTankopedia) =>
|
||||||
context === 'bot'
|
context === 'server'
|
||||||
? (wrapperTankopedia as { data: Tankopedia }).data
|
? (wrapperTankopedia as { data: Tankopedia }).data
|
||||||
: (wrapperTankopedia as Tankopedia),
|
: (wrapperTankopedia as Tankopedia),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in new issue
Block a user