feat: data driven latest archived season number

This commit is contained in:
TrèsAbhi committed 2023-10-31 12:35:32 -05:00
1 parent d1ebb79432
commit f02db2a2d8
13 files changed
+144 -95

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());
}
+4 -4
View File
@@ -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,7 +27,7 @@ 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);
+30 -72
View File
@@ -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;
}
+2 -2
View File
@@ -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;
}
@@ -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,
) { ) {
+1 -1
View File
@@ -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) => {
+1 -1
View File
@@ -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),
); );