mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f883670cbc | ||
|
|
cdac43fa5f | ||
|
|
8c4afa73f8 | ||
|
|
6db3ccdb40 | ||
|
|
90e012319a | ||
|
|
18de9cbaab | ||
|
|
42a76cbd38 | ||
|
|
eb95634801 | ||
|
|
de8bfff47f | ||
|
|
07c18911df | ||
|
|
cc769cc330 | ||
|
|
9794f58936 | ||
|
|
a44fcff3b1 | ||
|
|
7e4a3e88b9 | ||
|
|
8fd45e2205 | ||
|
|
7d235057e8 | ||
|
|
63a8a67771 | ||
|
|
bac39ca176 | ||
|
|
626b1e8601 | ||
|
|
04086f31b9 | ||
|
|
7037aa9c3b | ||
|
|
ee44b1b1d8 | ||
|
|
d0f91df95b | ||
|
|
dc1c49da6a | ||
|
|
eb4cb1fbfe |
No files matched your search
@@ -22,11 +22,11 @@ jobs:
|
||||
- name: Download release assets
|
||||
run: |
|
||||
DOWNLOAD_URL=$(curl -s https://api.github.com/repos/tresabhi/blitzkrieg/releases/latest \
|
||||
| grep "browser_download_url.*dist.zip" \
|
||||
| grep "browser_download_url.*bot.zip" \
|
||||
| cut -d : -f 2,3 \
|
||||
| tr -d \")
|
||||
curl -L -o dist.zip $DOWNLOAD_URL
|
||||
unzip dist.zip
|
||||
curl -L -o bot.zip $DOWNLOAD_URL
|
||||
unzip bot.zip
|
||||
|
||||
- name: Run bot
|
||||
run: NODE_ENV=production GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} WARGAMING_APPLICATION_ID=${{ secrets.WARGAMING_APPLICATION_ID }} node --enable-source-maps --trace-warnings bot.cjs
|
||||
run: NODE_ENV=production GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} WARGAMING_APPLICATION_ID=${{ secrets.WARGAMING_APPLICATION_ID }} node --enable-source-maps --trace-warnings bot/index.cjs
|
||||
+3
-1
@@ -9,6 +9,8 @@ dist.*
|
||||
yarn-error.log
|
||||
commands.txt
|
||||
/test.*
|
||||
test.*
|
||||
/docs/.vitepress/dist
|
||||
/docs/.vitepress/cache
|
||||
servers.csv
|
||||
servers.csv
|
||||
.next/
|
||||
@@ -0,0 +1,12 @@
|
||||
# Blitzkrieg 1.12.5
|
||||
|
||||
Some patch up work
|
||||
|
||||
## Changes
|
||||
|
||||
- `/clan-event` now is more legible and comes with an approximation warning
|
||||
|
||||
## Fixes
|
||||
|
||||
- `/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
|
||||
@@ -0,0 +1,12 @@
|
||||
# Blitzkrieg 1.12.6
|
||||
|
||||
Stops making the bot lie!
|
||||
|
||||
## Changes
|
||||
|
||||
- The approximation warning for `/clan-event` has been made more concise
|
||||
- Players with `0` wins are now omitted
|
||||
|
||||
## Fixes
|
||||
|
||||
- Players who haven't player within the current day are now omitted
|
||||
@@ -0,0 +1,13 @@
|
||||
# Blitzkrieg 1.12.7
|
||||
|
||||
A few fixes and clarifications
|
||||
|
||||
## Changes
|
||||
|
||||
- `/clan-event`
|
||||
- Made statement about the limited publicly available data
|
||||
- Added a statement about reset times
|
||||
|
||||
## Fixes
|
||||
|
||||
- Commands with images now once again work
|
||||
@@ -0,0 +1,7 @@
|
||||
# Blitzkrieg 1.12.8
|
||||
|
||||
Blitzkrieg is a completely free service and I earn no revenue from it. To keep it sustainable, I have to rely on free services. Unfortunately for embeds, seems like I have exceeded my limits. Before this service starts charging me, I have shut down embeds. They'll hopefully be back in 1.13 alongside the website! Only the future will tell...
|
||||
|
||||
## Changes
|
||||
|
||||
- Removed all embed buttons
|
||||
@@ -0,0 +1,7 @@
|
||||
# Blitzkrieg 1.12.9
|
||||
|
||||
Now that the clan event is over, we don't need `/clan-event`. This command may be reintroduced in the future as a part of a different command/feature and will definitely be re-enabled during the next clan event.
|
||||
|
||||
## Changes
|
||||
|
||||
- Disabled the `/clan-event` command
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
@@ -0,0 +1,7 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
/* config options here */
|
||||
distDir: 'dist/website',
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
+20
-14
@@ -1,24 +1,28 @@
|
||||
{
|
||||
"name": "blitzkrieg",
|
||||
"version": "1.12.1",
|
||||
"version": "1.12.9",
|
||||
"description": "🎉 All-in-one Discord bot for everything World of Tanks Blitz",
|
||||
"main": "src/server.ts",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "node scripts/build && yarn build:website",
|
||||
"build:bot": "node scripts/build --build=bot",
|
||||
"build:server": "node scripts/build --build=server",
|
||||
"build:website": "next build",
|
||||
"build:docs": "vitepress build docs",
|
||||
"build:ratingsleaderboard": "vite-node --script scripts/buildRatingsLeaderboard",
|
||||
"build": "node scripts/build --build=all",
|
||||
"dev:bot": "yarn build:bot --dev && yarn start:bot",
|
||||
"dev:server": "yarn build:server --dev && yarn start:server",
|
||||
"dev:bot": "yarn build:bot && yarn start:bot",
|
||||
"dev:server": "yarn build:server && yarn start:server",
|
||||
"dev:docs": "vitepress dev docs",
|
||||
"start:bot": "node --enable-source-maps --trace-warnings dist/bot.cjs",
|
||||
"start:server": "node --enable-source-maps --trace-warnings dist/server.cjs",
|
||||
"dev:website": "next dev",
|
||||
"start:bot": "node --enable-source-maps --trace-warnings dist/bot/index.cjs",
|
||||
"start:server": "node --enable-source-maps --trace-warnings dist/server/index.cjs",
|
||||
"start:website": "next start",
|
||||
"host:docs": "vitepress preview docs",
|
||||
"publish:ratingsleaderboard": "vite-node --script scripts/buildRatingsLeaderboard --publish",
|
||||
"zip": "zip -r dist.zip dist",
|
||||
"lint": "npx tsc",
|
||||
"lint:website": "next lint",
|
||||
"format": "prettier --write \"**/*.@(json|js|jsx|css|md|ts|tsx|html|xml|yml|gltf)\"",
|
||||
"knip": "knip",
|
||||
"update": "yarn upgrade --latest"
|
||||
@@ -35,23 +39,25 @@
|
||||
"fuzzysort": "^2.0.4",
|
||||
"lodash": "^4.17.21",
|
||||
"markdown-escape": "^2.0.0",
|
||||
"next": "^13.4.19",
|
||||
"react": "^18.2.0",
|
||||
"satori": "^0.10.3",
|
||||
"vite-node": "^0.34.2",
|
||||
"react-dom": "^18.2.0",
|
||||
"satori": "^0.10.4",
|
||||
"vite-node": "^0.34.4",
|
||||
"vitepress-plugin-auto-sidebar": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@total-typescript/ts-reset": "^0.5.1",
|
||||
"@types/escape-html": "^1.0.2",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/lodash": "^4.14.197",
|
||||
"@types/lodash": "^4.14.198",
|
||||
"@types/markdown-escape": "^1.1.0",
|
||||
"@types/node": "^20.5.3",
|
||||
"@types/node": "^20.6.0",
|
||||
"@types/react": "^18.2.21",
|
||||
"compare-versions": "^6.1.0",
|
||||
"knip": "^2.19.9",
|
||||
"prettier": "^3.0.2",
|
||||
"typescript": "^5.0.4",
|
||||
"vitepress": "^1.0.0-rc.4"
|
||||
"knip": "^2.22.0",
|
||||
"prettier": "^3.0.3",
|
||||
"typescript": "^5.2.2",
|
||||
"vitepress": "^1.0.0-rc.10"
|
||||
}
|
||||
}
|
||||
+24
-54
@@ -1,63 +1,33 @@
|
||||
import { build } from 'esbuild';
|
||||
import { copyFile, mkdirSync, rmSync } from 'fs';
|
||||
import { argv } from 'process';
|
||||
|
||||
const isProd = !argv.includes('--dev');
|
||||
const buildAll = argv.includes('--build=all');
|
||||
const buildBot = argv.includes('--build=bot') || buildAll;
|
||||
const buildServer = argv.includes('--build=server') || buildAll;
|
||||
const targetFile = argv
|
||||
.find((arg) => arg.startsWith('--build='))
|
||||
?.split('=')[1];
|
||||
const files = targetFile ? [targetFile] : ['bot', 'server'];
|
||||
|
||||
if (isProd) {
|
||||
// only remove in production to ensure no time is wasted in dev
|
||||
console.log('Removing dist...');
|
||||
rmSync('dist', { recursive: true, force: true });
|
||||
console.log('Dist removed');
|
||||
files.forEach(async (file) => {
|
||||
console.log(`Building ${file}...`);
|
||||
|
||||
console.log('Creating dist...');
|
||||
mkdirSync('dist');
|
||||
console.log('Dist created');
|
||||
await build({
|
||||
entryPoints: [`src/${file}.ts`],
|
||||
outfile: `dist/${file}/index.cjs`,
|
||||
|
||||
console.log('Copying package.json...');
|
||||
copyFile('package.dist.json', 'dist/package.json', () =>
|
||||
console.log('package.json copied'),
|
||||
);
|
||||
}
|
||||
platform: 'node',
|
||||
loader: {
|
||||
'.node': 'copy',
|
||||
'.ttf': 'file',
|
||||
},
|
||||
format: 'cjs',
|
||||
|
||||
const commonOptions = {
|
||||
platform: 'node',
|
||||
loader: {
|
||||
'.node': 'copy',
|
||||
'.ttf': 'file',
|
||||
},
|
||||
format: 'cjs',
|
||||
bundle: true,
|
||||
sourcemap: true,
|
||||
minifyIdentifiers: false, // cause goofy errors
|
||||
minifySyntax: true,
|
||||
minifyWhitespace: true,
|
||||
|
||||
bundle: true,
|
||||
sourcemap: true,
|
||||
minifyIdentifiers: false, // causes errors
|
||||
minifySyntax: isProd,
|
||||
minifyWhitespace: isProd,
|
||||
|
||||
logLevel: isProd ? 'info' : 'silent',
|
||||
};
|
||||
|
||||
if (buildBot) {
|
||||
console.log('Building bot...');
|
||||
build({
|
||||
...commonOptions,
|
||||
|
||||
entryPoints: ['src/bot.ts'],
|
||||
outfile: 'dist/bot.cjs',
|
||||
}).then(() => console.log('Bot built'));
|
||||
}
|
||||
|
||||
if (buildServer) {
|
||||
console.log('Building server...');
|
||||
build({
|
||||
...commonOptions,
|
||||
|
||||
entryPoints: ['src/server.ts'],
|
||||
outfile: 'dist/server.cjs',
|
||||
}).then(() => {
|
||||
console.log('Server built');
|
||||
logLevel: 'info',
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`Built ${file}`);
|
||||
});
|
||||
@@ -31,7 +31,11 @@ const PLAYERS = await fetch(
|
||||
`https://${server}.wotblitz.com/en/api/rating-leaderboards/season/`,
|
||||
)
|
||||
.then((response) => response.json() as Promise<RatingsInfo>)
|
||||
.then((data) => data.count);
|
||||
.then((data) => (data.detail === undefined ? data.count : undefined));
|
||||
|
||||
if (PLAYERS === undefined) {
|
||||
throw new Error('No current ratings season running');
|
||||
}
|
||||
|
||||
const players: Record<number, RatingsPlayer> = {};
|
||||
const leaderboard: BlitzkriegRatingsLeaderboard = [];
|
||||
@@ -60,7 +64,7 @@ async function branchFromPlayer(id: number) {
|
||||
|
||||
console.log(
|
||||
`Registered ${registered} / ${PLAYERS} (${(
|
||||
(registered / PLAYERS) *
|
||||
(registered / PLAYERS!) *
|
||||
100
|
||||
).toFixed(2)}%)`,
|
||||
);
|
||||
@@ -109,7 +113,10 @@ if (publish) {
|
||||
|
||||
const info = await fetch(
|
||||
`https://${server}.wotblitz.com/en/api/rating-leaderboards/season/`,
|
||||
).then((response) => response.json() as Promise<RatingsInfo>);
|
||||
).then(
|
||||
(response) =>
|
||||
response.json() as Promise<RatingsInfo & { detail: undefined }>,
|
||||
);
|
||||
const normalizedServer = server === 'na' ? 'com' : server;
|
||||
|
||||
const infoPath = `${normalizedServer}/ratings/${info.current_season}/info.json`;
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { ReactNode } from 'react';
|
||||
import Navbar from '../components/Navbar';
|
||||
|
||||
interface RootLayoutProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }: RootLayoutProps) {
|
||||
return (
|
||||
<html>
|
||||
<body
|
||||
style={{
|
||||
margin: 0,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: '100vw',
|
||||
height: '100vh',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<Navbar />
|
||||
|
||||
{children}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export default function Page() {
|
||||
return <h1>Hello, Next.js!</h1>;
|
||||
}
|
||||
+75
-85
@@ -1,106 +1,96 @@
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import { SlashCommandBuilder, escapeMarkdown } from 'discord.js';
|
||||
import markdownEscape from 'markdown-escape';
|
||||
import getWargamingResponse from '../core/blitz/getWargamingResponse';
|
||||
import { PlayerHistoriesRaw } from '../core/blitzstars/getPlayerHistories';
|
||||
import getTimeDaysAgo from '../core/blitzstars/getTimeDaysAgo';
|
||||
import addClanChoices from '../core/discord/addClanChoices';
|
||||
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 { CommandRegistry } from '../events/interactionCreate';
|
||||
|
||||
const DEFAULT_THRESHOLD = 7;
|
||||
import { AccountAchievements } from '../types/accountAchievements';
|
||||
import { AccountInfo } from '../types/accountInfo';
|
||||
import { ClanInfo } from '../types/clanInfo';
|
||||
|
||||
export const clanEventCommand: CommandRegistry = {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inProduction: false,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
.setName('clan-event')
|
||||
.setDescription('Lists all inactive players')
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName('clan')
|
||||
.setDescription('The clan name or tag you are checking')
|
||||
.setRequired(true),
|
||||
),
|
||||
.addStringOption(addClanChoices),
|
||||
|
||||
async handler(interaction) {
|
||||
const REGION = 'com';
|
||||
const CLAN_SEARCH = interaction.options.getString('clan', true);
|
||||
const { region, id } = await resolveClanFromCommand(interaction);
|
||||
const clan = (
|
||||
await getWargamingResponse<ClanInfo>(
|
||||
`https://api.wotblitz.${region}/wotb/clans/info/?application_id=${secrets.WARGAMING_APPLICATION_ID}&clan_id=${id}`,
|
||||
)
|
||||
)[id];
|
||||
const memberIds = clan.members_ids.join(',');
|
||||
const [players, achievements, previousJointVictories] = await Promise.all([
|
||||
getWargamingResponse<AccountInfo>(
|
||||
`https://api.wotblitz.${region}/wotb/account/info/?application_id=${secrets.WARGAMING_APPLICATION_ID}&account_id=${memberIds}`,
|
||||
),
|
||||
getWargamingResponse<AccountAchievements>(
|
||||
`https://api.wotblitz.${region}/wotb/account/achievements/?application_id=${secrets.WARGAMING_APPLICATION_ID}&account_id=${memberIds}`,
|
||||
),
|
||||
Promise.all(
|
||||
clan.members_ids.map((id) =>
|
||||
fetch(`https://www.blitzstars.com/api/playerstats/${id}`)
|
||||
.then((response) => response.json() as Promise<PlayerHistoriesRaw>)
|
||||
.then((data) => ({
|
||||
id,
|
||||
jointVictory: data[0]?.achievements.jointVictoryCount as
|
||||
| number
|
||||
| undefined,
|
||||
})),
|
||||
),
|
||||
).then((data) =>
|
||||
data.reduce<Record<number, number | undefined>>(
|
||||
(accumulator, value) => ({
|
||||
...accumulator,
|
||||
[value.id]: value.jointVictory,
|
||||
}),
|
||||
{},
|
||||
),
|
||||
),
|
||||
]);
|
||||
const jointVictories = clan.members_ids.map((id) => ({
|
||||
id,
|
||||
joinVictory:
|
||||
players[id].last_battle_time > getTimeDaysAgo(region, 1)
|
||||
? previousJointVictories[id] === undefined
|
||||
? 0
|
||||
: achievements[id].max_series.jointVictory -
|
||||
previousJointVictories[id]!
|
||||
: 0,
|
||||
}));
|
||||
|
||||
const {
|
||||
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())
|
||||
.then(({ data }) => data[0]);
|
||||
const memebers = await fetch(
|
||||
`https://api.wotblitz.${REGION}/wotb/clans/info/?application_id=${secrets.WARGAMING_APPLICATION_ID}&clan_id=${clan_id}`,
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ data }) => data[clan_id].members_ids);
|
||||
const stats = await Promise.all(
|
||||
memebers.map(async (id, index) => {
|
||||
await new Promise((resolve) => setTimeout(resolve, index * 200));
|
||||
|
||||
const [yesterdayPlatoonWins, name, todayPlatoonWins] =
|
||||
await Promise.all([
|
||||
fetch(`https://www.blitzstars.com/api/playerstats/${id}`)
|
||||
.then((response) => response.json())
|
||||
.then((data) => data[0]?.achievements.jointVictoryCount),
|
||||
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,
|
||||
name,
|
||||
yesterdayPlatoonWins,
|
||||
todayPlatoonWins,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
return embedInfo(
|
||||
`Estimation of ${clan_name} [${clan_tag}]'s total platoon wins today: ${(
|
||||
stats.reduce(
|
||||
(accumulator, player) =>
|
||||
accumulator +
|
||||
(player.yesterdayPlatoonWins === undefined
|
||||
? 0
|
||||
: player.todayPlatoonWins - player.yesterdayPlatoonWins),
|
||||
return [
|
||||
`# ${escapeMarkdown(clan.name)} [${escapeMarkdown(
|
||||
clan.tag,
|
||||
)}]'s platoon wins today: ${(
|
||||
jointVictories.reduce(
|
||||
(accumulator, { joinVictory }) => accumulator + joinVictory,
|
||||
0,
|
||||
) / 2
|
||||
).toFixed(0)}`,
|
||||
stats
|
||||
.sort(
|
||||
(playerA, playerB) =>
|
||||
(playerB.yesterdayPlatoonWins === undefined
|
||||
? 0
|
||||
: playerB.todayPlatoonWins - playerB.yesterdayPlatoonWins) -
|
||||
(playerA.yesterdayPlatoonWins === undefined
|
||||
? 0
|
||||
: playerA.todayPlatoonWins - playerA.yesterdayPlatoonWins),
|
||||
)
|
||||
).toFixed(0)}\n${jointVictories
|
||||
.filter(({ joinVictory }) => joinVictory)
|
||||
.sort((a, b) => b.joinVictory - a.joinVictory)
|
||||
.map(
|
||||
(player) =>
|
||||
`${markdownEscape(player.name)}: ${
|
||||
player.yesterdayPlatoonWins === undefined
|
||||
? 0
|
||||
: player.todayPlatoonWins - player.yesterdayPlatoonWins
|
||||
}`,
|
||||
({ id, joinVictory }) =>
|
||||
`- ${markdownEscape(players[id].nickname)}: ${joinVictory}`,
|
||||
)
|
||||
.join('\n'),
|
||||
);
|
||||
.join('\n')}`,
|
||||
|
||||
embedWarning(
|
||||
'This is an approximation!',
|
||||
"Wargaming provides very little information about platoons publicly. Caveats:\n- Players in two different clans platooning artificially inflates the total count\n- Game-mode battles aren't counted since Wargaming doesn't publicly share that data\n- This command is also subject to Blitzkrieg's reset times (use `/help timezones` for more info)",
|
||||
),
|
||||
];
|
||||
},
|
||||
|
||||
autocomplete: autocompleteClan,
|
||||
|
||||
@@ -12,7 +12,6 @@ const executionStart = new Date().getTime();
|
||||
|
||||
export const debugCommand: CommandRegistry = {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -26,7 +26,6 @@ export const SKILLED_CLANS: Record<SkilledClan, string> = {
|
||||
|
||||
export const eligibleCommand: CommandRegistry = {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: false,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -29,7 +29,6 @@ export const evolutionCommand = new Promise<CommandRegistryRaw>(
|
||||
|
||||
resolve({
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command,
|
||||
|
||||
@@ -29,7 +29,6 @@ export const fullStatsCommand = new Promise<CommandRegistryRaw>(
|
||||
|
||||
resolve({
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command,
|
||||
|
||||
@@ -30,7 +30,6 @@ function addDocsSubcommands(option: SlashCommandSubcommandsOnlyBuilder) {
|
||||
|
||||
export const helpCommand: CommandRegistry = {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: addDocsSubcommands(
|
||||
|
||||
@@ -3,10 +3,10 @@ import GenericStats from '../components/GenericStats';
|
||||
import NoData, { NoDataType } from '../components/NoData';
|
||||
import TitleBar from '../components/TitleBar';
|
||||
import Wrapper from '../components/Wrapper';
|
||||
import getBlitzClan from '../core/blitz/getBlitzClan';
|
||||
import getWargamingResponse from '../core/blitz/getWargamingResponse';
|
||||
import addClanChoices from '../core/discord/addClanChoices';
|
||||
import autocompleteClan from '../core/discord/autocompleteClan';
|
||||
import resolveClanFromCommand from '../core/discord/resolveClanFromCommand';
|
||||
import { secrets } from '../core/node/secrets';
|
||||
import { CommandRegistry } from '../events/interactionCreate';
|
||||
import { AccountInfo } from '../types/accountInfo';
|
||||
@@ -16,7 +16,6 @@ const DEFAULT_THRESHOLD = 7;
|
||||
|
||||
export const inactiveCommand: CommandRegistry = {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
@@ -33,19 +32,18 @@ export const inactiveCommand: CommandRegistry = {
|
||||
),
|
||||
|
||||
async handler(interaction) {
|
||||
const clanName = interaction.options.getString('clan')!;
|
||||
const { server, id } = await getBlitzClan(clanName);
|
||||
const { region, id } = await resolveClanFromCommand(interaction);
|
||||
const threshold =
|
||||
interaction.options.getNumber('threshold')! ?? DEFAULT_THRESHOLD;
|
||||
const time = new Date().getTime() / 1000;
|
||||
const clanData = (
|
||||
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];
|
||||
const memberIds = clanData.members_ids;
|
||||
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
|
||||
}&account_id=${memberIds.join(',')}`,
|
||||
);
|
||||
|
||||
@@ -46,7 +46,6 @@ const COMP_TANKS = [
|
||||
|
||||
export const ownedTanksCommand: CommandRegistry = {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -3,7 +3,6 @@ import { CommandRegistry } from '../events/interactionCreate';
|
||||
|
||||
export const pingCommand: CommandRegistry = {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
handlesInteraction: true,
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ type SortBy = 'name' | 'count';
|
||||
|
||||
export const playerAchievementsCommand: CommandRegistry = {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -12,7 +12,6 @@ import { AccountInfo } from '../types/accountInfo';
|
||||
|
||||
export const playerInfoCommand: CommandRegistry = {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -218,7 +218,6 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
|
||||
|
||||
resolve({
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command,
|
||||
|
||||
@@ -11,7 +11,6 @@ import { ClanList } from '../types/clanList';
|
||||
|
||||
export const searchClansCommand: CommandRegistry = {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -12,7 +12,6 @@ import { AccountList } from '../types/accountList';
|
||||
|
||||
export const searchPlayersCommand: CommandRegistry = {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -8,7 +8,6 @@ import { CommandRegistry } from '../events/interactionCreate';
|
||||
|
||||
export const searchTanksCommand: CommandRegistry = {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -27,7 +27,6 @@ export const statsCommand = new Promise<CommandRegistryRaw>(async (resolve) => {
|
||||
|
||||
resolve({
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command,
|
||||
@@ -81,7 +80,7 @@ export const statsCommand = new Promise<CommandRegistryRaw>(async (resolve) => {
|
||||
: null,
|
||||
),
|
||||
primaryButton(path, 'Refresh'),
|
||||
linkButton(`${CYCLIC_API}/${path}`, 'Embed'),
|
||||
// linkButton(`${CYCLIC_API}/${path}`, 'Embed'),
|
||||
linkButton(
|
||||
`https://www.blitzstars.com/player/${player.region}/${nickname}`,
|
||||
'BlitzStars',
|
||||
|
||||
@@ -15,7 +15,6 @@ import { AccountInfo } from '../types/accountInfo';
|
||||
|
||||
export const todayCommand: CommandRegistry = {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
@@ -67,7 +66,7 @@ export const todayCommand: CommandRegistry = {
|
||||
return [
|
||||
await today(player, cutoff, maximized, showTotal, false),
|
||||
primaryButton(path, 'Refresh'),
|
||||
linkButton(`${CYCLIC_API}/${path}`, 'Embed'),
|
||||
// linkButton(`${CYCLIC_API}/${path}`, 'Embed'),
|
||||
linkButton(
|
||||
`https://www.blitzstars.com/player/${player.region}/${nickname}`,
|
||||
'BlitzStars',
|
||||
|
||||
@@ -14,7 +14,6 @@ import { PlayerClanData } from '../types/playerClanData';
|
||||
|
||||
export const verifyCommand: CommandRegistry = {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export default function Navbar() {
|
||||
return (
|
||||
<div style={{ display: 'flex', height: 100, backgroundColor: 'red' }}></div>
|
||||
);
|
||||
}
|
||||
@@ -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 getWargamingResponse from './getWargamingResponse';
|
||||
|
||||
export type ClanListWithServer = (Clan & {
|
||||
server: 'com' | 'eu' | 'asia';
|
||||
export type ClanListWithRegion = (Clan & {
|
||||
region: 'com' | 'eu' | 'asia';
|
||||
})[];
|
||||
|
||||
export default async function listClans(search: string, limit = 9) {
|
||||
@@ -21,7 +21,7 @@ export default async function listClans(search: string, limit = 9) {
|
||||
value &&
|
||||
value.map((account) => ({
|
||||
...account,
|
||||
server: 'com' as Region,
|
||||
region: 'com' as Region,
|
||||
})),
|
||||
),
|
||||
getWargamingResponse<ClanList>(
|
||||
@@ -31,7 +31,7 @@ export default async function listClans(search: string, limit = 9) {
|
||||
value &&
|
||||
value.map((account) => ({
|
||||
...account,
|
||||
server: 'eu' as Region,
|
||||
region: 'eu' as Region,
|
||||
})),
|
||||
),
|
||||
getWargamingResponse<ClanList>(
|
||||
@@ -41,7 +41,7 @@ export default async function listClans(search: string, limit = 9) {
|
||||
value &&
|
||||
value.map((account) => ({
|
||||
...account,
|
||||
server: 'asia' as Region,
|
||||
region: 'asia' as Region,
|
||||
})),
|
||||
),
|
||||
])
|
||||
|
||||
@@ -19,8 +19,8 @@ export default async function autocompleteClan(
|
||||
? players.map(
|
||||
(player) =>
|
||||
({
|
||||
name: `${player.name} (${REGION_NAMES[player.server]})`,
|
||||
value: `${player.server}/${player.clan_id}`,
|
||||
name: `${player.name} (${REGION_NAMES[player.region]})`,
|
||||
value: `${player.region}/${player.clan_id}`,
|
||||
}) 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.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,6 @@ export type InteractionReturnable =
|
||||
| Promise<InteractionIterableReturnable>;
|
||||
|
||||
export interface Registry {
|
||||
inDevelopment: boolean;
|
||||
inProduction: boolean;
|
||||
}
|
||||
|
||||
@@ -124,14 +123,12 @@ export const publicCommands: RESTPostAPIChatInputApplicationCommandsJSONBody[] =
|
||||
|
||||
commands.then((awaitedCommands) => {
|
||||
Object.entries(awaitedCommands).forEach(([, registry]) => {
|
||||
if (isDev() ? registry.inDevelopment : registry.inProduction) {
|
||||
const json = registry.command.toJSON();
|
||||
const json = registry.command.toJSON();
|
||||
|
||||
if (registry.inPublic) {
|
||||
publicCommands.push(json);
|
||||
} else {
|
||||
guildCommands.push(json);
|
||||
}
|
||||
if (registry.inPublic) {
|
||||
publicCommands.push(json);
|
||||
} else {
|
||||
guildCommands.push(json);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import { RouteRegistry } from '../server';
|
||||
export const statsRoute: RouteRegistry = {
|
||||
route: '/stats/:type/:period',
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
|
||||
async handler(req) {
|
||||
const type = req.params.type as StatType;
|
||||
|
||||
@@ -5,7 +5,6 @@ import { RouteRegistry } from '../server';
|
||||
export const todayRoute: RouteRegistry = {
|
||||
route: '/today',
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
|
||||
async handler(req) {
|
||||
const player = resolvePlayerFromRequest(req);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import express, { Request, Response } from 'express';
|
||||
import normalizeRouteReturnable from './core/express/normalizeRouteReturnable';
|
||||
import withAutoRefresh from './core/express/withAutoRefresh';
|
||||
import isDev from './core/node/isDev';
|
||||
import { Registry } from './events/interactionCreate';
|
||||
import { statsRoute } from './routes/stats';
|
||||
import { todayRoute } from './routes/today';
|
||||
@@ -22,8 +21,6 @@ export interface RouteRegistry<HandlesInteraction extends boolean = false>
|
||||
const app = express();
|
||||
|
||||
([statsRoute, todayRoute] as RouteRegistry[]).forEach((registry) => {
|
||||
if (!(isDev() ? registry.inDevelopment : registry.inProduction)) return;
|
||||
|
||||
app.get(registry.route, async (req, res) => {
|
||||
console.log(req.originalUrl);
|
||||
|
||||
|
||||
+12
-2
@@ -9,7 +9,17 @@
|
||||
"skipLibCheck": true,
|
||||
"noEmit": true,
|
||||
"resolveJsonModule": true,
|
||||
"jsx": "react-jsx"
|
||||
"jsx": "react-jsx",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"incremental": true,
|
||||
"isolatedModules": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/components/Tanks/components/Row.tsx", "src/commands/clanEvent.ts"]
|
||||
"include": ["src/**/*", ".next/types/**/*.ts", "dist/website/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in new issue
Block a user