mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04086f31b9 | ||
|
|
7037aa9c3b |
No files matched your search
@@ -0,0 +1,12 @@
|
|||||||
|
# Blitzkrieg 1.12.4
|
||||||
|
|
||||||
|
Some patch up work
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
- `/clan-event` now is more legible and comes with an approximation warning
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- `/clan-event` now uses a more optimized way of fetching large data
|
||||||
|
- This should fix the issue where too many people using the command broke it
|
||||||
+63
-76
@@ -1,9 +1,16 @@
|
|||||||
import { SlashCommandBuilder } from 'discord.js';
|
import { SlashCommandBuilder } from 'discord.js';
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from 'markdown-escape';
|
||||||
|
import getWargamingResponse from '../core/blitz/getWargamingResponse';
|
||||||
|
import { PlayerHistoriesRaw } from '../core/blitzstars/getPlayerHistories';
|
||||||
|
import addClanChoices from '../core/discord/addClanChoices';
|
||||||
import autocompleteClan from '../core/discord/autocompleteClan';
|
import autocompleteClan from '../core/discord/autocompleteClan';
|
||||||
import embedInfo from '../core/discord/embedInfo';
|
import embedWarning from '../core/discord/embedWarning';
|
||||||
|
import resolveClanFromCommand from '../core/discord/resolveClanFromCommand';
|
||||||
import { secrets } from '../core/node/secrets';
|
import { secrets } from '../core/node/secrets';
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import { CommandRegistry } from '../events/interactionCreate';
|
||||||
|
import { AccountAchievements } from '../types/accountAchievements';
|
||||||
|
import { AccountInfo } from '../types/accountInfo';
|
||||||
|
import { ClanInfo } from '../types/clanInfo';
|
||||||
|
|
||||||
const DEFAULT_THRESHOLD = 7;
|
const DEFAULT_THRESHOLD = 7;
|
||||||
|
|
||||||
@@ -15,92 +22,72 @@ export const clanEventCommand: CommandRegistry = {
|
|||||||
command: new SlashCommandBuilder()
|
command: new SlashCommandBuilder()
|
||||||
.setName('clan-event')
|
.setName('clan-event')
|
||||||
.setDescription('Lists all inactive players')
|
.setDescription('Lists all inactive players')
|
||||||
.addStringOption((option) =>
|
.addStringOption(addClanChoices),
|
||||||
option
|
|
||||||
.setName('clan')
|
|
||||||
.setDescription('The clan name or tag you are checking')
|
|
||||||
.setRequired(true),
|
|
||||||
),
|
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const REGION = 'com';
|
const { region, id } = await resolveClanFromCommand(interaction);
|
||||||
const CLAN_SEARCH = interaction.options.getString('clan', true);
|
const clan = (
|
||||||
|
await getWargamingResponse<ClanInfo>(
|
||||||
const {
|
`https://api.wotblitz.${region}/wotb/clans/info/?application_id=${secrets.WARGAMING_APPLICATION_ID}&clan_id=${id}`,
|
||||||
clan_id,
|
|
||||||
name: clan_name,
|
|
||||||
tag: clan_tag,
|
|
||||||
} = await fetch(
|
|
||||||
`https://api.wotblitz.${REGION}/wotb/clans/list/?application_id=${secrets.WARGAMING_APPLICATION_ID}&search=${CLAN_SEARCH}`,
|
|
||||||
)
|
)
|
||||||
.then((response) => response.json())
|
)[id];
|
||||||
.then(({ data }) => data[0]);
|
const memberIds = clan.members_ids.join(',');
|
||||||
const memebers = await fetch(
|
const [players, achievements, previousJointVictories] = await Promise.all([
|
||||||
`https://api.wotblitz.${REGION}/wotb/clans/info/?application_id=${secrets.WARGAMING_APPLICATION_ID}&clan_id=${clan_id}`,
|
getWargamingResponse<AccountInfo>(
|
||||||
)
|
`https://api.wotblitz.${region}/wotb/account/info/?application_id=${secrets.WARGAMING_APPLICATION_ID}&account_id=${memberIds}`,
|
||||||
.then((response) => response.json())
|
),
|
||||||
.then(({ data }) => data[clan_id].members_ids);
|
getWargamingResponse<AccountAchievements>(
|
||||||
const stats = await Promise.all(
|
`https://api.wotblitz.${region}/wotb/account/achievements/?application_id=${secrets.WARGAMING_APPLICATION_ID}&account_id=${memberIds}`,
|
||||||
memebers.map(async (id, index) => {
|
),
|
||||||
await new Promise((resolve) => setTimeout(resolve, index * 200));
|
Promise.all(
|
||||||
|
clan.members_ids.map((id) =>
|
||||||
const [yesterdayPlatoonWins, name, todayPlatoonWins] =
|
|
||||||
await Promise.all([
|
|
||||||
fetch(`https://www.blitzstars.com/api/playerstats/${id}`)
|
fetch(`https://www.blitzstars.com/api/playerstats/${id}`)
|
||||||
.then((response) => response.json())
|
.then((response) => response.json() as Promise<PlayerHistoriesRaw>)
|
||||||
.then((data) => data[0]?.achievements.jointVictoryCount),
|
.then((data) => ({
|
||||||
fetch(
|
|
||||||
`https://api.wotblitz.${REGION}/wotb/account/info/?application_id=${secrets.WARGAMING_APPLICATION_ID}&account_id=${id}`,
|
|
||||||
)
|
|
||||||
.then((response) => response.json())
|
|
||||||
.then(({ data }) => data[id].nickname),
|
|
||||||
fetch(
|
|
||||||
`https://api.wotblitz.${REGION}/wotb/account/achievements/?application_id=${secrets.WARGAMING_APPLICATION_ID}&account_id=${id}`,
|
|
||||||
)
|
|
||||||
.then((response) => response.json())
|
|
||||||
.then(({ data }) => data[id].max_series.jointVictory),
|
|
||||||
]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
id,
|
id,
|
||||||
name,
|
jointVictory: data[0]?.achievements.jointVictoryCount as
|
||||||
yesterdayPlatoonWins,
|
| number
|
||||||
todayPlatoonWins,
|
| undefined,
|
||||||
};
|
})),
|
||||||
|
),
|
||||||
|
).then((data) =>
|
||||||
|
data.reduce<Record<number, number | undefined>>(
|
||||||
|
(accumulator, value) => ({
|
||||||
|
...accumulator,
|
||||||
|
[value.id]: value.jointVictory,
|
||||||
}),
|
}),
|
||||||
);
|
{},
|
||||||
|
),
|
||||||
return embedInfo(
|
),
|
||||||
`Estimation of ${clan_name} [${clan_tag}]'s total platoon wins today: ${(
|
]);
|
||||||
stats.reduce(
|
const jointVictories = clan.members_ids.map((id) => ({
|
||||||
(accumulator, player) =>
|
id,
|
||||||
accumulator +
|
joinVictory:
|
||||||
(player.yesterdayPlatoonWins === undefined
|
previousJointVictories[id] === undefined
|
||||||
? 0
|
? 0
|
||||||
: player.todayPlatoonWins - player.yesterdayPlatoonWins),
|
: achievements[id].max_series.jointVictory -
|
||||||
|
previousJointVictories[id]!,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return [
|
||||||
|
`# ${clan.name} [${clan.tag}]'s platoon wins today: ${(
|
||||||
|
jointVictories.reduce(
|
||||||
|
(accumulator, { joinVictory }) => accumulator + joinVictory,
|
||||||
0,
|
0,
|
||||||
) / 2
|
) / 2
|
||||||
).toFixed(0)}`,
|
).toFixed(0)}\n${jointVictories
|
||||||
stats
|
.sort((a, b) => b.joinVictory - a.joinVictory)
|
||||||
.sort(
|
|
||||||
(playerA, playerB) =>
|
|
||||||
(playerB.yesterdayPlatoonWins === undefined
|
|
||||||
? 0
|
|
||||||
: playerB.todayPlatoonWins - playerB.yesterdayPlatoonWins) -
|
|
||||||
(playerA.yesterdayPlatoonWins === undefined
|
|
||||||
? 0
|
|
||||||
: playerA.todayPlatoonWins - playerA.yesterdayPlatoonWins),
|
|
||||||
)
|
|
||||||
.map(
|
.map(
|
||||||
(player) =>
|
({ id, joinVictory }) =>
|
||||||
`${markdownEscape(player.name)}: ${
|
`- ${markdownEscape(players[id].nickname)}: ${joinVictory}`,
|
||||||
player.yesterdayPlatoonWins === undefined
|
|
||||||
? 0
|
|
||||||
: player.todayPlatoonWins - player.yesterdayPlatoonWins
|
|
||||||
}`,
|
|
||||||
)
|
)
|
||||||
.join('\n'),
|
.join('\n')}`,
|
||||||
);
|
|
||||||
|
embedWarning(
|
||||||
|
'This is an approximation!',
|
||||||
|
'Wargaming provides use with little to no information about platoons. Platooning with mixed clans may inflate the number and platooning in non-regular battles may deflate.',
|
||||||
|
),
|
||||||
|
];
|
||||||
},
|
},
|
||||||
|
|
||||||
autocomplete: autocompleteClan,
|
autocomplete: autocompleteClan,
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ import GenericStats from '../components/GenericStats';
|
|||||||
import NoData, { NoDataType } from '../components/NoData';
|
import NoData, { NoDataType } from '../components/NoData';
|
||||||
import TitleBar from '../components/TitleBar';
|
import TitleBar from '../components/TitleBar';
|
||||||
import Wrapper from '../components/Wrapper';
|
import Wrapper from '../components/Wrapper';
|
||||||
import getBlitzClan from '../core/blitz/getBlitzClan';
|
|
||||||
import getWargamingResponse from '../core/blitz/getWargamingResponse';
|
import getWargamingResponse from '../core/blitz/getWargamingResponse';
|
||||||
import addClanChoices from '../core/discord/addClanChoices';
|
import addClanChoices from '../core/discord/addClanChoices';
|
||||||
import autocompleteClan from '../core/discord/autocompleteClan';
|
import autocompleteClan from '../core/discord/autocompleteClan';
|
||||||
|
import resolveClanFromCommand from '../core/discord/resolveClanFromCommand';
|
||||||
import { secrets } from '../core/node/secrets';
|
import { secrets } from '../core/node/secrets';
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import { CommandRegistry } from '../events/interactionCreate';
|
||||||
import { AccountInfo } from '../types/accountInfo';
|
import { AccountInfo } from '../types/accountInfo';
|
||||||
@@ -33,19 +33,18 @@ export const inactiveCommand: CommandRegistry = {
|
|||||||
),
|
),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const clanName = interaction.options.getString('clan')!;
|
const { region, id } = await resolveClanFromCommand(interaction);
|
||||||
const { server, id } = await getBlitzClan(clanName);
|
|
||||||
const threshold =
|
const threshold =
|
||||||
interaction.options.getNumber('threshold')! ?? DEFAULT_THRESHOLD;
|
interaction.options.getNumber('threshold')! ?? DEFAULT_THRESHOLD;
|
||||||
const time = new Date().getTime() / 1000;
|
const time = new Date().getTime() / 1000;
|
||||||
const clanData = (
|
const clanData = (
|
||||||
await getWargamingResponse<ClanInfo>(
|
await getWargamingResponse<ClanInfo>(
|
||||||
`https://api.wotblitz.${server}/wotb/clans/info/?application_id=${secrets.WARGAMING_APPLICATION_ID}&clan_id=${id}`,
|
`https://api.wotblitz.${region}/wotb/clans/info/?application_id=${secrets.WARGAMING_APPLICATION_ID}&clan_id=${id}`,
|
||||||
)
|
)
|
||||||
)[id];
|
)[id];
|
||||||
const memberIds = clanData.members_ids;
|
const memberIds = clanData.members_ids;
|
||||||
const accounts = await getWargamingResponse<AccountInfo>(
|
const accounts = await getWargamingResponse<AccountInfo>(
|
||||||
`https://api.wotblitz.${server}/wotb/account/info/?application_id=${
|
`https://api.wotblitz.${region}/wotb/account/info/?application_id=${
|
||||||
secrets.WARGAMING_APPLICATION_ID
|
secrets.WARGAMING_APPLICATION_ID
|
||||||
}&account_id=${memberIds.join(',')}`,
|
}&account_id=${memberIds.join(',')}`,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
import { Region } from '../../constants/regions';
|
|
||||||
import { serverAndIdPattern } from '../discord/resolvePlayerFromCommand';
|
|
||||||
import throwError from '../node/throwError';
|
|
||||||
import listClans from './listClans';
|
|
||||||
|
|
||||||
export default async function getBlitzClan(clan: string) {
|
|
||||||
if (serverAndIdPattern.test(clan)) {
|
|
||||||
const [server, accountId] = clan.split('/');
|
|
||||||
return { server: server as Region, id: Number(accountId) };
|
|
||||||
} else {
|
|
||||||
const accounts = await listClans(clan);
|
|
||||||
|
|
||||||
if (accounts[0]) {
|
|
||||||
return { server: accounts[0].server, id: accounts[0].clan_id };
|
|
||||||
} else {
|
|
||||||
throw throwError(
|
|
||||||
'Could not find clan',
|
|
||||||
`I couldn't find clan \`${clan}\`. Try selecting a username from the search result.`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,8 +3,8 @@ import { Clan, ClanList } from '../../types/clanList';
|
|||||||
import { secrets } from '../node/secrets';
|
import { secrets } from '../node/secrets';
|
||||||
import getWargamingResponse from './getWargamingResponse';
|
import getWargamingResponse from './getWargamingResponse';
|
||||||
|
|
||||||
export type ClanListWithServer = (Clan & {
|
export type ClanListWithRegion = (Clan & {
|
||||||
server: 'com' | 'eu' | 'asia';
|
region: 'com' | 'eu' | 'asia';
|
||||||
})[];
|
})[];
|
||||||
|
|
||||||
export default async function listClans(search: string, limit = 9) {
|
export default async function listClans(search: string, limit = 9) {
|
||||||
@@ -21,7 +21,7 @@ export default async function listClans(search: string, limit = 9) {
|
|||||||
value &&
|
value &&
|
||||||
value.map((account) => ({
|
value.map((account) => ({
|
||||||
...account,
|
...account,
|
||||||
server: 'com' as Region,
|
region: 'com' as Region,
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
getWargamingResponse<ClanList>(
|
getWargamingResponse<ClanList>(
|
||||||
@@ -31,7 +31,7 @@ export default async function listClans(search: string, limit = 9) {
|
|||||||
value &&
|
value &&
|
||||||
value.map((account) => ({
|
value.map((account) => ({
|
||||||
...account,
|
...account,
|
||||||
server: 'eu' as Region,
|
region: 'eu' as Region,
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
getWargamingResponse<ClanList>(
|
getWargamingResponse<ClanList>(
|
||||||
@@ -41,7 +41,7 @@ export default async function listClans(search: string, limit = 9) {
|
|||||||
value &&
|
value &&
|
||||||
value.map((account) => ({
|
value.map((account) => ({
|
||||||
...account,
|
...account,
|
||||||
server: 'asia' as Region,
|
region: 'asia' as Region,
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ export default async function autocompleteClan(
|
|||||||
? players.map(
|
? players.map(
|
||||||
(player) =>
|
(player) =>
|
||||||
({
|
({
|
||||||
name: `${player.name} (${REGION_NAMES[player.server]})`,
|
name: `${player.name} (${REGION_NAMES[player.region]})`,
|
||||||
value: `${player.server}/${player.clan_id}`,
|
value: `${player.region}/${player.clan_id}`,
|
||||||
}) satisfies ApplicationCommandOptionChoiceData<string>,
|
}) satisfies ApplicationCommandOptionChoiceData<string>,
|
||||||
)
|
)
|
||||||
: [],
|
: [],
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { ChatInputCommandInteraction } from 'discord.js';
|
||||||
|
import { Region } from '../../constants/regions';
|
||||||
|
import listClans from '../blitz/listClans';
|
||||||
|
import throwError from '../node/throwError';
|
||||||
|
import { serverAndIdPattern } from './resolvePlayerFromCommand';
|
||||||
|
|
||||||
|
export default async function resolveClanFromCommand(
|
||||||
|
interaction: ChatInputCommandInteraction,
|
||||||
|
) {
|
||||||
|
const clan = interaction.options.getString('clan', true);
|
||||||
|
|
||||||
|
if (serverAndIdPattern.test(clan)) {
|
||||||
|
const [server, accountId] = clan.split('/');
|
||||||
|
return { region: server as Region, id: Number(accountId) };
|
||||||
|
} else {
|
||||||
|
const accounts = await listClans(clan);
|
||||||
|
|
||||||
|
if (accounts[0]) {
|
||||||
|
return { region: accounts[0].region, id: accounts[0].clan_id };
|
||||||
|
} else {
|
||||||
|
throw throwError(
|
||||||
|
'Could not find clan',
|
||||||
|
`I couldn't find clan \`${clan}\`. Try selecting a username from the search result.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user