feat: simplified /ratings command

This commit is contained in:
TrèsAbhi committed 2024-01-19 16:02:03 -06:00
1 parent ff9bda29cf
commit 890a4d142b
3 files changed
+78 -92

No files matched your search

+64 -91
View File
@@ -2,7 +2,6 @@ import {
APIApplicationCommandOptionChoice, APIApplicationCommandOptionChoice,
SlashCommandBuilder, SlashCommandBuilder,
SlashCommandSubcommandBuilder, SlashCommandSubcommandBuilder,
SlashCommandSubcommandGroupBuilder,
} from 'discord.js'; } from 'discord.js';
import { range } from 'lodash'; import { range } from 'lodash';
import { BlitzkriegRatingsLeaderboard } from '../../scripts/buildRatingsLeaderboard'; import { BlitzkriegRatingsLeaderboard } from '../../scripts/buildRatingsLeaderboard';
@@ -17,13 +16,13 @@ import { getClanAccountInfo } from '../core/blitz/getClanAccountInfo';
import getRatingsInfo from '../core/blitz/getRatingsInfo'; import getRatingsInfo from '../core/blitz/getRatingsInfo';
import { getRatingsLeague } from '../core/blitz/getRatingsLeague'; import { getRatingsLeague } from '../core/blitz/getRatingsLeague';
import { getRatingsNeighbors } from '../core/blitz/getRatingsNeighbors'; import { getRatingsNeighbors } from '../core/blitz/getRatingsNeighbors';
import { isOnGoingRatingsSeason } from '../core/blitz/isOnGoingRatingsSeason';
import { getArchivedLatestSeasonNumber } from '../core/blitzkrieg/getArchivedLatestSeasonNumber'; import { getArchivedLatestSeasonNumber } from '../core/blitzkrieg/getArchivedLatestSeasonNumber';
import getArchivedRatingsInfo from '../core/blitzkrieg/getArchivedRatingsInfo'; import getArchivedRatingsInfo from '../core/blitzkrieg/getArchivedRatingsInfo';
import { getArchivedRatingsLeaderboard } from '../core/blitzkrieg/getArchivedRatingsLeaderboard'; import { getArchivedRatingsLeaderboard } from '../core/blitzkrieg/getArchivedRatingsLeaderboard';
import getArchivedRatingsMidnightLeaderboard from '../core/blitzkrieg/getArchivedRatingsMidnightLeaderboard'; import getArchivedRatingsMidnightLeaderboard from '../core/blitzkrieg/getArchivedRatingsMidnightLeaderboard';
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 autocompleteUsername from '../core/discord/autocompleteUsername'; import autocompleteUsername from '../core/discord/autocompleteUsername';
import embedNegative from '../core/discord/embedNegative'; import embedNegative from '../core/discord/embedNegative';
import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand';
@@ -116,18 +115,22 @@ export interface RatingsNeighbors {
neighbors: RatingsPlayer[]; neighbors: RatingsPlayer[];
} }
function addSubcommands( const noOngoingSeason = embedNegative(
option: SlashCommandSubcommandGroupBuilder, 'No ongoing season',
addOptions = (option: SlashCommandSubcommandBuilder) => option, "Wargaming didn't provide any data for this season.",
) { );
export const ratingsCommand = new Promise<CommandRegistryRaw>(
async (resolve) => {
const latestArchivedSeasonNumber = await getArchivedLatestSeasonNumber();
const onGoingSeason = await isOnGoingRatingsSeason();
const seasonNumbers = range(
FIRST_ARCHIVED_RATINGS_SEASON,
latestArchivedSeasonNumber + (onGoingSeason ? 1 : 0) + 1,
);
function addSubcommands(option: SlashCommandSubcommandBuilder) {
return option return option
.addSubcommand((option) =>
addOptions(
option
.setName('neighbors')
.setDescription('Your position and neighbors'),
)
.addStringOption(addUsernameChoices)
.addIntegerOption((option) => .addIntegerOption((option) =>
option option
.setName('limit') .setName('limit')
@@ -135,10 +138,42 @@ function addSubcommands(
.setRequired(false) .setRequired(false)
.setMinValue(5) .setMinValue(5)
.setMaxValue(30), .setMaxValue(30),
)
.addStringOption((option) =>
option
.setName('season')
.setDescription('Season number')
.setRequired(false)
.addChoices(
...seasonNumbers
.map(
(number, index) =>
({
name: `${number}${index === seasonNumbers.length - 1 && onGoingSeason ? ' (current)' : ''}`,
value: `${number}`,
}) satisfies APIApplicationCommandOptionChoice<string>,
)
.reverse(),
),
);
}
const command = new SlashCommandBuilder()
.setName('ratings')
.setDescription('Ratings battles statistics')
.addSubcommand((option) =>
addSubcommands(
option
.setName('neighbors')
.setDescription('Shows neighboring players on the leaderboard'),
), ),
) )
.addSubcommand((option) => .addSubcommand((option) =>
addOptions(option.setName('league').setDescription('Top league players')) addSubcommands(
option
.setName('league')
.setDescription('Shows top players from a league')
.addStringOption(addRegionChoices)
.addStringOption((option) => .addStringOption((option) =>
option option
.setName('league') .setName('league')
@@ -153,59 +188,7 @@ function addSubcommands(
), ),
) )
.setRequired(true), .setRequired(true),
)
.addStringOption(addRegionChoices)
.addIntegerOption((option) =>
option
.setName('limit')
.setDescription('How many rows to display (default: 10)')
.setRequired(false)
.setMinValue(5)
.setMaxValue(30),
), ),
);
}
const noOngoingSeason = embedNegative(
'No ongoing season',
"Wargaming didn't provide any data for this season.",
);
export const ratingsCommand = new Promise<CommandRegistryRaw>(
async (resolve) => {
const latestArchivedSeasonNumber = await getArchivedLatestSeasonNumber();
const seasonChoices = range(
FIRST_ARCHIVED_RATINGS_SEASON,
latestArchivedSeasonNumber + 1,
).map(
(number) =>
({
name: `Season ${number}`,
value: `${number}`,
}) satisfies APIApplicationCommandOptionChoice<string>,
);
const command = new SlashCommandBuilder()
.setName('ratings')
.setDescription('Ratings battles statistics')
.addSubcommandGroup((option) =>
addSubcommands(
option.setName('archive').setDescription('Any previous season'),
(option) =>
option.addStringOption((option) =>
option
.setName('season')
.setDescription('The season number')
.setChoices(...seasonChoices)
.setRequired(true),
),
),
)
.addSubcommandGroup((option) =>
addSubcommands(
option
.setName('current')
.setDescription('The current running Ratings season'),
), ),
); );
@@ -224,18 +207,19 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
nickname: string; nickname: string;
} }
const subcommandGroup = interaction.options.getSubcommandGroup(true) as
| 'archive'
| 'current';
const subcommand = interaction.options.getSubcommand(true) as const subcommand = interaction.options.getSubcommand(true) as
| 'league' | 'league'
| 'neighbors'; | 'neighbors';
const limit = interaction.options.getInteger('limit') ?? 10; const limit = interaction.options.getInteger('limit') ?? 10;
const seasonOption = interaction.options.getString('season'); const seasonOption = interaction.options.getString('season');
const season = seasonOption ? parseInt(seasonOption) : undefined; const season = seasonOption
? parseInt(seasonOption)
: onGoingSeason
? latestArchivedSeasonNumber + 1
: latestArchivedSeasonNumber;
const isCurrentSeason = season === latestArchivedSeasonNumber + 1;
let titleName: string; let titleName: string;
let titleImage: string | undefined; let titleImage: string | undefined;
let titleNameDiscriminator: string | undefined;
let titleDescription: string; let titleDescription: string;
let playersBefore: number; let playersBefore: number;
let playersAfter: number; let playersAfter: number;
@@ -249,16 +233,14 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
interaction.options.getString('league')!, interaction.options.getString('league')!,
); );
const region = interaction.options.getString('region') as Region; const region = interaction.options.getString('region') as Region;
regionRatingsInfo = await (subcommandGroup === 'current' regionRatingsInfo = await (isCurrentSeason
? getRatingsInfo(region) ? getRatingsInfo(region)
: getArchivedRatingsInfo(region, season!)); : getArchivedRatingsInfo(region, season!));
if (regionRatingsInfo.detail !== undefined) return noOngoingSeason; if (regionRatingsInfo.detail !== undefined) return noOngoingSeason;
const result = const result = isCurrentSeason
subcommandGroup === 'current' ? await getRatingsLeague(region, leagueIndex).then(async (result) =>
? await getRatingsLeague(region, leagueIndex).then(
async (result) =>
result.slice(0, limit).map( result.slice(0, limit).map(
(player) => (player) =>
({ ({
@@ -305,8 +287,7 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
}, },
); );
const leagueInfo = regionRatingsInfo.leagues[leagueIndex]; const leagueInfo = regionRatingsInfo.leagues[leagueIndex];
midnightLeaderboard = midnightLeaderboard = isCurrentSeason
subcommandGroup === 'current'
? await getArchivedRatingsMidnightLeaderboard( ? await getArchivedRatingsMidnightLeaderboard(
region, region,
regionRatingsInfo.current_season, regionRatingsInfo.current_season,
@@ -326,8 +307,7 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
titleDescription = `Top ${limit} players`; titleDescription = `Top ${limit} players`;
} else { } else {
const { region, id } = await resolvePlayerFromCommand(interaction); const { region, id } = await resolvePlayerFromCommand(interaction);
regionRatingsInfo = regionRatingsInfo = isCurrentSeason
subcommandGroup === 'current'
? await getRatingsInfo(region) ? await getRatingsInfo(region)
: await getArchivedRatingsInfo(region, season!); : await getArchivedRatingsInfo(region, season!);
@@ -335,13 +315,9 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
const accountInfo = await getAccountInfo(region, id); const accountInfo = await getAccountInfo(region, id);
const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan; const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan;
const neighbors = const neighbors = isCurrentSeason
subcommandGroup === 'current' ? await getRatingsNeighbors(region, id, Math.round(limit / 2)).then(
? await getRatingsNeighbors( (players) =>
region,
id,
Math.round(limit / 2),
).then((players) =>
players.neighbors.map( players.neighbors.map(
(player) => (player) =>
({ ({
@@ -391,16 +367,13 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
})); }));
}, },
); );
midnightLeaderboard = midnightLeaderboard = isCurrentSeason
subcommandGroup === 'current'
? await getArchivedRatingsMidnightLeaderboard( ? await getArchivedRatingsMidnightLeaderboard(
region, region,
regionRatingsInfo.current_season, regionRatingsInfo.current_season,
) )
: await getArchivedRatingsMidnightLeaderboard(region, season!); : await getArchivedRatingsMidnightLeaderboard(region, season!);
if (clan && neighbors) titleNameDiscriminator = `[${clan.tag}]`;
players = neighbors; players = neighbors;
titleImage = clan titleImage = clan
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png` ? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png`
+8 -1
View File
@@ -4,7 +4,11 @@ import { context } from '../blitzkrieg/context';
import { patientFetch } from '../blitzkrieg/patientFetch'; import { patientFetch } from '../blitzkrieg/patientFetch';
import regionToRegionSubdomain from './regionToRegionSubdomain'; import regionToRegionSubdomain from './regionToRegionSubdomain';
const ratingsInfoCache: Partial<Record<Region, RatingsInfo>> = {};
export default async function getRatingsInfo(region: Region) { export default async function getRatingsInfo(region: Region) {
if (ratingsInfoCache[region]) return ratingsInfoCache[region]!;
const response = await patientFetch( const response = await patientFetch(
context === 'website' context === 'website'
? `/api/${region}/ratings/current/info` ? `/api/${region}/ratings/current/info`
@@ -14,6 +18,9 @@ export default async function getRatingsInfo(region: Region) {
undefined, undefined,
{ cache: 'no-store' }, { cache: 'no-store' },
); );
const data = (await response.json()) as RatingsInfo;
return (await response.json()) as Promise<RatingsInfo>; ratingsInfoCache[region] = data;
return data;
} }
+6
View File
@@ -0,0 +1,6 @@
import getRatingsInfo from './getRatingsInfo';
export async function isOnGoingRatingsSeason() {
const ratingsInfo = await getRatingsInfo('com');
return ratingsInfo.detail === undefined;
}