Compare commits

...
31 Commits
Author SHA1 Message Date
TrèsAbhi 3363c9ab58 Merge pull request #50 from tresabhi/1.15.3 2023-11-25 21:12:30 -06:00
TrèsAbhi 10f64902aa fix: xml in md 2023-11-25 21:10:53 -06:00
TrèsAbhi 25e1f4caa4 fix: workflow triggers 2023-11-25 21:09:24 -06:00
TrèsAbhi 222fa89422 fix: remove pull request 2023-11-25 21:04:04 -06:00
TrèsAbhi 750e145f03 feat: version lint 2023-11-25 21:03:29 -06:00
TrèsAbhi 3bbbbfa402 feat: changelogs 2023-11-25 20:57:58 -06:00
TrèsAbhi f728751fa9 feat: better debug 2023-11-25 20:46:20 -06:00
TrèsAbhi f5425d0e54 fix: more accurate user count 2023-11-25 20:45:00 -06:00
TrèsAbhi debaaccf4c feat: presence 2023-11-25 20:40:11 -06:00
TrèsAbhi a3e20501af feat: new credits transfer 2023-11-25 20:08:01 -06:00
TrèsAbhi c87a75f3fd feat: combined ratings archive workflows 2023-11-25 20:01:12 -06:00
TrèsAbhi 55729c5eda feat: ratings leaderboard archive explicit target 2023-11-25 19:46:56 -06:00
TrèsAbhi 06cbcc2339 fix: "Midnight" in name 2023-11-23 14:39:04 -06:00
TrèsAbhi 1afe860e76 feat: change workflow file name to midnight 2023-11-23 14:38:04 -06:00
TrèsAbhi c0ac935652 feat: remove manual asia leaderboard trigger 2023-11-23 14:36:40 -06:00
TrèsAbhi 7c76b0f5a5 feat: Asia leaderboard manual trigger 2023-11-22 23:51:52 -06:00
TrèsAbhi 42091c54b7 fix: illegal json invocation 2023-11-22 23:49:24 -06:00
TrèsAbhi 396b48d017 feat: smaller fetching size 2023-11-20 13:32:53 -06:00
TrèsAbhi bb1c0c7625 Merge pull request #49 from tresabhi/1.15.2 2023-11-19 14:05:46 -06:00
TrèsAbhi 1170676141 feat: changelogs 2023-11-19 14:05:39 -06:00
TrèsAbhi 7baaaa9db9 fix: remove seeding player neighbor checking 2023-11-19 14:02:00 -06:00
TrèsAbhi c1ecef0179 fix: add max target position 2023-11-19 13:55:11 -06:00
TrèsAbhi 032d98e6bd fix: version number 2023-11-16 11:53:13 -06:00
TrèsAbhi f4a90cd531 Merge pull request #48 from tresabhi/1.15.1 2023-11-16 11:51:58 -06:00
TrèsAbhi 82f03583fe feat: updated docs with latest info 2023-11-16 11:51:10 -06:00
TrèsAbhi 81c1a50052 fix: guide link 2023-11-16 11:47:32 -06:00
TrèsAbhi c7207799e2 feat: changelogs 2023-11-16 11:45:44 -06:00
TrèsAbhi e0a719ee93 fix: patient JSON parsing 2023-11-16 11:41:52 -06:00
TrèsAbhi ee6d2e7d82 feat: remove neighbor relative positional caching 2023-11-16 11:14:38 -06:00
TrèsAbhi 14710b5218 fix: use non-caching apis for ratings command 2023-11-16 11:13:51 -06:00
TrèsAbhi 4b5e0d1c1c feat: american neighbor spelling 2023-11-16 10:58:19 -06:00
33 changed files with 250 additions and 226 deletions

No files matched your search

@@ -1,34 +0,0 @@
name: CD Asia Ratings Latest
on:
schedule:
- cron: "0 0 * * *"
jobs:
host:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Use node
uses: actions/setup-node@v3
with:
node-version: 18
cache: "npm"
- name: Install Yarn
run: npm install --location=global yarn
- name: Use node_modules cache
uses: actions/cache@v3
with:
path: "**/node_modules"
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
- name: Install dependencies
run: yarn
- name: Generate leaderboard
run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=asia --latest
@@ -1,34 +0,0 @@
name: CD Asia Ratings Leaderboards
on:
schedule:
- cron: "0 17 * * *"
jobs:
host:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Use node
uses: actions/setup-node@v3
with:
node-version: 18
cache: "npm"
- name: Install Yarn
run: npm install --location=global yarn
- name: Use node_modules cache
uses: actions/cache@v3
with:
path: "**/node_modules"
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
- name: Install dependencies
run: yarn
- name: Generate leaderboard
run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=asia
+1 -1
View File
@@ -2,7 +2,7 @@ name: CD Docs
on:
push:
branches: [main]
branches: main
jobs:
build:
@@ -1,8 +1,12 @@
name: CD Europe Ratings Latest
name: CD Asia Ratings
# latest: '0 0 * * *'
# asia midnight: '0 17 * * *'
on:
schedule:
- cron: "0 0 * * *"
- cron: '0 0 * * *'
- cron: '0 17 * * *'
jobs:
host:
@@ -16,7 +20,7 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: 18
cache: "npm"
cache: 'npm'
- name: Install Yarn
run: npm install --location=global yarn
@@ -24,11 +28,11 @@ jobs:
- name: Use node_modules cache
uses: actions/cache@v3
with:
path: "**/node_modules"
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
- name: Install dependencies
run: yarn
- name: Generate leaderboard
run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=eu --latest
run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=asia --target=${{ github.event.schedule == '0 0 * * *' && 'latest' || 'midnight' }}
@@ -1,8 +1,12 @@
name: CD North America Ratings Latest
name: CD Europe Ratings
# latest: '0 0 * * *'
# eu midnight: '0 23 * * *'
on:
schedule:
- cron: '0 0 * * *'
- cron: '0 23 * * *'
jobs:
host:
@@ -31,4 +35,4 @@ jobs:
run: yarn
- name: Generate leaderboard
run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=na --latest
run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=eu --target=${{ github.event.schedule == '0 0 * * *' && 'latest' || 'midnight' }}
@@ -1,8 +1,12 @@
name: CD Europe Ratings Leaderboards
name: CD North America Ratings
# latest: '0 0 * * *'
# na midnight: '0 5 * * *'
on:
schedule:
- cron: "0 23 * * *"
- cron: '0 0 * * *'
- cron: '0 5 * * *'
jobs:
host:
@@ -16,7 +20,7 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: 18
cache: "npm"
cache: 'npm'
- name: Install Yarn
run: npm install --location=global yarn
@@ -24,11 +28,11 @@ jobs:
- name: Use node_modules cache
uses: actions/cache@v3
with:
path: "**/node_modules"
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
- name: Install dependencies
run: yarn
- name: Generate leaderboard
run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=eu
run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=na --target=${{ github.event.schedule == '0 0 * * *' && 'latest' || 'midnight' }}
+1 -1
View File
@@ -1,6 +1,6 @@
name: CI Build Bot
on: [push, pull_request]
on: push
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
+1 -1
View File
@@ -1,6 +1,6 @@
name: CI Build Docs
on: [push, pull_request]
on: push
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
+1 -1
View File
@@ -1,6 +1,6 @@
name: CI Build Website
on: [push, pull_request]
on: push
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -1,8 +1,6 @@
name: CD North America Ratings Leaderboards
name: CI Version
on:
schedule:
- cron: '0 5 * * *'
on: push
jobs:
host:
@@ -31,4 +29,4 @@ jobs:
run: yarn
- name: Generate leaderboard
run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=na
run: yarn lint:version
+3
View File
@@ -13,9 +13,12 @@
"Everytime",
"fullstats",
"fuzzysort",
"immer",
"kranvagn",
"krieg",
"Leaderboard",
"leaderboards",
"MURICA",
"Oopsy",
"outdir",
"outfile",
+1 -1
View File
@@ -13,7 +13,7 @@ export default defineConfig({
themeConfig: {
nav: [
{ text: 'Home', link: '/' },
{ text: 'Guide', link: '/guide/about' },
{ text: 'Guide', link: '/guide/introduction' },
],
sidebar: [
+24
View File
@@ -0,0 +1,24 @@
# Blitzkrieg 1.15.1
'MURICA!
## Changes
- "Neighbor" is now spelled in the American way
- Updated documentation website with the latest information
## Fixes
- Fixed the guide link on the documentation website
## Technical features
- Added capability to fetch patiently while also parsing the JSON
## Technical changes
- Removed neighbor relative position caching
## Technical fixes
- `/ratings` now uses the non-caching APIs
+9
View File
@@ -0,0 +1,9 @@
# Blitzkrieg 1.15.2
Infinity reduced to a finite value.
## Fixes
- Added a maximum value to the jump to position button
- Removed neighbor checking for the seeding player
- This fixes the jump to position button not loading at all
+30
View File
@@ -0,0 +1,30 @@
# Blitzkrieg 1.15.3
The bot now gets more expressive!
## Features
- The bot can now have presence messages; examples:
- "Living in {number} servers"
- "Server {number} users"
- "Observing {number} channels"
- More will be added in the future! Give me some ideas
## Changes
- Moved `/credits` to `/about creators`
- `/debug` command now ditches embeds and has better information to serve
## Technical Features
- Added a workflow and lint for package and changelog version miss match
## Technical Changes
- Removed manual trigger for Asian latest ratings leaderboard archiver
- Leaderboard archiver now accepts an explicit target like `midnight` or `latest`
- Combined midnight and latest leaderboard archival workflow into one file
## Technical Fixed
- Reviewed all workflow triggers and updated them
+6
View File
@@ -0,0 +1,6 @@
# Creators
- TrèsAbhi `@tresabhi`
- Creator & main programmer; _I do it all!_
- Prince_NA `@prince_na`
- Advisor & tester
-17
View File
@@ -1,17 +0,0 @@
# Installing Blitzkrieg
It's easy as 1, 2, 3!
## Step 1
Join a server that already has Blitzkrieg or [join our official Discord server](https://discord.gg/nDt7AjGJQH).
## Step 2
View the bot's profile and click "Add to Server".
<video src="https://i.imgur.com/Zq0P3m2.mp4" autoplay loop muted width=320 title="how to install"></video>
## Step 3
Review the permissions the bot is asking for and add it to your server!
+13 -1
View File
@@ -1,6 +1,10 @@
# Introduction
Blitzkrieg is a multipurpose bot for anything and everything World of Tanks Blitz.
🎉 Services for everything and anything World of Tanks Blitz
## Bot
Blitzkrieg is available as a Discord bot and can be [installed very easily](/guide/invite).
- Track statistics
- Find inactive players in a clan
@@ -8,3 +12,11 @@ Blitzkrieg is a multipurpose bot for anything and everything World of Tanks Blit
- Create embeds for streams
- Track a player/tanks statistical evolution
- ...and a variety of other similar things
## Website
Provides a bunch of very helpful tools; https://blitz-krieg.vercel.app/
- Session tracker
- Ratings leaderboard
- Way more to come
+2 -2
View File
@@ -12,10 +12,10 @@ hero:
actions:
- theme: brand
text: Add to Discord Server
link: guide/install
link: /guide/invite
- theme: alt
text: Guide
link: /guide/about
link: /guide/introduction
features:
- title: Clean and Efficient UI
+2 -1
View File
@@ -1,6 +1,6 @@
{
"name": "blitzkrieg",
"version": "1.15.0",
"version": "1.15.3",
"description": "🎉 Tools for everything World of Tanks Blitz",
"main": "src/server.ts",
"type": "module",
@@ -21,6 +21,7 @@
"lint": "npx tsc",
"lint:website": "next lint",
"format": "prettier --write \"**/*.@(json|js|jsx|css|md|ts|tsx|html|xml|yml|gltf)\"",
"lint:version": "vite-node --script scripts/checkVersionMissMatch",
"knip": "knip",
"update": "yarn upgrade --latest"
},
+14 -18
View File
@@ -6,7 +6,7 @@ import {
RatingsNeighbors,
RatingsPlayer,
} from '../src/commands/ratings';
import { patientFetch } from '../src/core/blitzkrieg/patientFetch';
import { patientFetchJSON } from '../src/core/blitzkrieg/patientFetchJSON';
import commitMultipleFiles from './commitMultipleFiles.js';
/*
@@ -23,17 +23,18 @@ export type BlitzkriegRatingsLeaderboardEntry = { id: number; score: number };
export type BlitzkriegRatingsLeaderboard = BlitzkriegRatingsLeaderboardEntry[];
const publish = argv.includes('--publish');
const latest = argv.includes('--latest');
const target = argv
.find((arg) => arg.startsWith('--target='))
?.split('=')[1] as 'midnight' | 'latest' | undefined;
const server = argv.find((arg) => arg.startsWith('--region='))?.split('=')[1];
if (!target) throw new Error('Target parameter not specified');
if (!server) throw new Error('Region parameter not specified');
const NEIGHBORS = 1024;
const PLAYERS = await patientFetch(
const NEIGHBORS = 2 ** 8;
const PLAYERS = await patientFetchJSON<RatingsInfo>(
`https://${server}.wotblitz.com/en/api/rating-leaderboards/season/`,
)
.then((response) => response.json() as Promise<RatingsInfo>)
.then((data) => (data.detail === undefined ? data.count : undefined));
).then((data) => (data.detail === undefined ? data.count : undefined));
if (PLAYERS === undefined) {
throw new Error('No current ratings season running');
@@ -44,9 +45,9 @@ const leaderboard: BlitzkriegRatingsLeaderboard = [];
let registered = 0;
async function branchFromPlayer(id: number) {
const { neighbors } = await patientFetch(
const { neighbors } = await patientFetchJSON<RatingsNeighbors>(
`https://${server}.wotblitz.com/en/api/rating-leaderboards/user/${id}/?neighbors=${NEIGHBORS}`,
).then((response) => response.json() as Promise<RatingsNeighbors>);
);
const firstPlayer = neighbors[0];
const lastPlayer = neighbors[neighbors.length - 1];
@@ -75,9 +76,9 @@ async function branchFromPlayer(id: number) {
}
async function branchFromLeague(id: number) {
const { result } = await patientFetch(
const { result } = await patientFetchJSON<{ result: RatingsPlayer[] }>(
`https://${server}.wotblitz.com/en/api/rating-leaderboards/league/${id}/top/`,
).then((response) => response.json() as Promise<{ result: RatingsPlayer[] }>);
);
const firstPlayer = result[0];
const lastPlayer = result[result.length - 1];
@@ -113,18 +114,13 @@ const leaderboardJSON = JSON.stringify(leaderboard);
if (publish) {
const octokit = new Octokit({ auth: env.GH_TOKEN });
const info = await patientFetch(
const info = await patientFetchJSON<RatingsInfo & { detail: undefined }>(
`https://${server}.wotblitz.com/en/api/rating-leaderboards/season/`,
).then(
(response) =>
response.json() as Promise<RatingsInfo & { detail: undefined }>,
);
const normalizedServer = server === 'na' ? 'com' : server;
const infoPath = `${normalizedServer}/ratings/${info.current_season}/info.json`;
const leaderboardPath = `${normalizedServer}/ratings/${info.current_season}/${
latest ? 'latest' : 'midnight'
}.json`;
const leaderboardPath = `${normalizedServer}/ratings/${info.current_season}/${target}.json`;
const infoJSON = JSON.stringify(info);
console.log(`Publishing to season ${info.current_season}...`);
+12
View File
@@ -0,0 +1,12 @@
import { readdir } from 'fs/promises';
import packageJSON from '../package.json';
const { version } = packageJSON;
const changelogs = await readdir('docs/changelogs');
const hasVersion = changelogs.includes(`${version}.md`);
if (hasVersion) {
console.log(`Version ${version} found in changelogs`);
} else {
throw new Error(`Version ${version} not found in changelogs`);
}
+6 -16
View File
@@ -137,15 +137,12 @@ export default function Page() {
await Promise.all(
range(0, 5).map(async (league: number) => {
const data = await getRatingsLeague(region, league);
leaguePositionCache.current[region][league] =
data.result[0].number - 1;
leaguePositionCache.current[region][league] = data[0].number - 1;
return data;
}),
)
)
.map(({ result }) => result)
.flat();
).flat();
useLeaderboardCache.setState(
produce((draft: LeaderboardCache) => {
@@ -302,19 +299,12 @@ export default function Page() {
}
}
const seedingPlayerNeighborEntry = Object.entries(
leaderboard[region][season],
).find(([, player]) => id === player);
if (seedingPlayerNeighborEntry === undefined) return null;
const seedingPlayerPosition = parseInt(seedingPlayerNeighborEntry[0]);
const { neighbors } = await getRatingsNeighbors(region, id, size, true);
useLeaderboardCache.setState(
produce((draft: LeaderboardCache) => {
neighbors.forEach((neighbor, neighborIndex) => {
const position = neighborIndex - radius + seedingPlayerPosition;
const position = neighbor.number - 1;
if (!(position in draft[region][season])) {
draft[region][season][position] = neighbor.spa_id;
@@ -349,9 +339,9 @@ export default function Page() {
async function jumpToPosition(position: number) {
if (!ratingsInfo || ratingsInfo?.detail) return;
const targetPosition = Math.max(
0,
Math.min(position, ratingsInfo.count - 1),
const targetPosition = Math.min(
ratingsInfo.count - 1,
Math.max(0, Math.min(position, ratingsInfo.count - 1)),
);
if (season === 0) {
+2
View File
@@ -11,6 +11,7 @@ const DOCS = {
introduction: 'guide/introduction',
invite: 'guide/invite',
timezones: 'guide/timezones',
creators: 'guide/creators',
};
const DOC_DESCRIPTIONS: Record<keyof typeof DOCS, string> = {
permissions: 'The permissions needed for the bot to function',
@@ -18,6 +19,7 @@ const DOC_DESCRIPTIONS: Record<keyof typeof DOCS, string> = {
introduction: 'About the bot',
invite: 'How to invite the bot',
timezones: 'How Blitzkrieg infers and uses your timezone',
creators: 'Who created the bot',
};
function addDocsSubcommands(option: SlashCommandSubcommandsOnlyBuilder) {
-15
View File
@@ -1,15 +0,0 @@
import { AttachmentBuilder, SlashCommandBuilder } from 'discord.js';
import { CommandRegistry } from '../events/interactionCreate';
export const creditsCommand: CommandRegistry = {
inProduction: true,
inPublic: true,
command: new SlashCommandBuilder()
.setName('credits')
.setDescription('Me and the people who made this bot'),
async handler() {
return new AttachmentBuilder('https://i.imgur.com/ZF5ch33.png');
},
};
+15 -23
View File
@@ -1,11 +1,6 @@
import { SlashCommandBuilder } from 'discord.js';
import packageJSON from '../../package.json' assert { type: 'json' };
import getClientId from '../core/blitzkrieg/getClientId';
import { tankAverages } from '../core/blitzstars/tankAverages';
import { tankopedia } from '../core/blitzstars/tankopedia';
import { client } from '../core/discord/client';
import embedInfo from '../core/discord/embedInfo';
import markdownTable from '../core/discord/markdownTable';
import { CommandRegistry } from '../events/interactionCreate';
const executionStart = new Date().getTime();
@@ -21,24 +16,21 @@ export const debugCommand: CommandRegistry = {
async handler(interaction) {
const currentTime = new Date().getTime();
const uptime = currentTime - executionStart;
const list = [
['Version', packageJSON.version],
['Shard', client.shard?.ids[0] ?? 'default'],
[
'Uptime',
`${Math.floor((uptime / 1000 / 60 / 60) % 24)}h ${Math.floor(
(uptime / 1000 / 60) % 60,
)}m ${Math.floor((uptime / 1000) % 60)}s ${Math.floor(
uptime % 1000,
)}ms`,
],
]
.map(([key, value]) => `- ${key}: ${value}`)
.join('\n');
return embedInfo(
`${client.user?.username} debug information`,
markdownTable([
['Version', packageJSON.version],
['Client ID', getClientId()],
['Tag', interaction.client.user.tag],
[
'Uptime',
`${Math.floor(uptime / 1000 / 60 / 60 / 24)}d ${Math.floor(
(uptime / 1000 / 60 / 60) % 24,
)}h ${Math.floor((uptime / 1000 / 60) % 60)}m ${Math.floor(
(uptime / 1000) % 60,
)}s ${Math.floor(uptime % 1000)}ms`,
],
['Tankopedia cached', `${(await tankopedia) !== undefined}`],
['Tank averages cached', `${(await tankAverages) !== undefined}`],
]),
);
return `# Debug\n\n${list}`;
},
};
+25 -31
View File
@@ -15,6 +15,8 @@ import { REGION_NAMES_SHORT, Region } from '../constants/regions';
import { getAccountInfo } from '../core/blitz/getAccountInfo';
import { getClanAccountInfo } from '../core/blitz/getClanAccountInfo';
import getRatingsInfo from '../core/blitz/getRatingsInfo';
import { getRatingsLeague } from '../core/blitz/getRatingsLeague';
import { getRatingsNeighbors } from '../core/blitz/getRatingsNeighbors';
import regionToRegionSubdomain from '../core/blitz/regionToRegionSubdomain';
import { getArchivedLatestSeasonNumber } from '../core/blitzkrieg/getArchivedLatestSeasonNumber';
import getArchivedRatingsInfo from '../core/blitzkrieg/getArchivedRatingsInfo';
@@ -123,14 +125,14 @@ function addSubcommands(
.addSubcommand((option) =>
addOptions(
option
.setName('neighbours')
.setDescription('Your position and neighbours'),
.setName('neighbors')
.setDescription('Your position and neighbors'),
)
.addStringOption(addUsernameChoices)
.addIntegerOption((option) =>
option
.setName('limit')
.setDescription('How many neighbours to display (default: 10)')
.setDescription('How many neighbors to display (default: 10)')
.setRequired(false)
.setMinValue(5)
.setMaxValue(30),
@@ -228,7 +230,7 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
| 'current';
const subcommand = interaction.options.getSubcommand(true) as
| 'league'
| 'neighbours';
| 'neighbors';
const limit = interaction.options.getInteger('limit') ?? 10;
const seasonOption = interaction.options.getString('season');
const season = seasonOption ? parseInt(seasonOption) : undefined;
@@ -257,11 +259,8 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
const regionSubdomain = regionToRegionSubdomain(region);
const result =
subcommandGroup === 'current'
? await fetch(
`https://${regionSubdomain}.wotblitz.com/en/api/rating-leaderboards/league/${leagueIndex}/top/`,
)
.then((response) => response.json() as Promise<LeagueTop>)
.then(async ({ result }) =>
? await getRatingsLeague(region, leagueIndex).then(
async (result) =>
result.slice(0, limit).map(
(player) =>
({
@@ -272,7 +271,7 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
nickname: player.nickname,
}) satisfies SimplifiedPlayer,
),
)
)
: await getArchivedRatingsLeaderboard(region, season!).then(
async (players) => {
const firstPlayerIndex =
@@ -338,29 +337,24 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
const accountInfo = await getAccountInfo(region, id);
const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan;
const regionSubdomain = regionToRegionSubdomain(region);
const neighbors =
subcommandGroup === 'current'
? await fetch(
`https://${regionSubdomain}.wotblitz.com/en/api/rating-leaderboards/user/${id}/?neighbors=${Math.round(
limit / 2,
)}`,
? await getRatingsNeighbors(
region,
id,
Math.round(limit / 2),
).then((players) =>
players.neighbors.map(
(player) =>
({
id: player.spa_id,
position: player.number,
score: player.score,
clan: player.clan_tag,
nickname: player.nickname,
}) satisfies SimplifiedPlayer,
),
)
.then(
(response) => response.json() as Promise<RatingsNeighbors>,
)
.then((players) =>
players.neighbors.map(
(player) =>
({
id: player.spa_id,
position: player.number,
score: player.score,
clan: player.clan_tag,
nickname: player.nickname,
}) satisfies SimplifiedPlayer,
),
)
: await getArchivedRatingsLeaderboard(region, season!).then(
async (players) => {
const playerIndex = players.findIndex(
@@ -414,7 +408,7 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
titleName = neighbors
? accountInfo.nickname
: `No Ongoing Season - ${REGION_NAMES_SHORT[region]}`;
titleDescription = 'Ratings neighbours';
titleDescription = 'Ratings neighbors';
playersBefore = neighbors ? neighbors[0].position - 1 : 0;
playersAfter =
regionRatingsInfo.count - neighbors[neighbors.length - 1].position;
+9 -4
View File
@@ -1,4 +1,4 @@
import { LeagueTop } from '../../commands/ratings';
import { LeagueTop, RatingsPlayer } from '../../commands/ratings';
import { Region } from '../../constants/regions';
import { context } from '../blitzkrieg/context';
import { patientFetch } from '../blitzkrieg/patientFetch';
@@ -9,7 +9,10 @@ export async function getRatingsLeague(
league: number,
usePatientFetcher = false,
) {
const fetcher = usePatientFetcher ? patientFetch : fetch;
const fetcher = (url: string) =>
usePatientFetcher
? patientFetch(url, undefined, { cache: 'no-store' })
: fetch(url, { cache: 'no-store' });
const response = await fetcher(
context === 'website'
? `/api/${region}/ratings/current/league/${league}`
@@ -17,7 +20,9 @@ export async function getRatingsLeague(
region,
)}.wotblitz.com/en/api/rating-leaderboards/league/${league}/top/`,
);
const json = (await response.json()) as LeagueTop;
const json = await response.json();
return json;
return context === 'website'
? (json as RatingsPlayer[])
: (json as LeagueTop).result;
}
+4 -3
View File
@@ -10,9 +10,10 @@ export async function getRatingsNeighbors(
count: number,
usePatientFetcher = false,
) {
const fetcher = usePatientFetcher
? patientFetch
: (url: string) => fetch(url, { cache: 'no-store' });
const fetcher = (url: string) =>
usePatientFetcher
? patientFetch(url, undefined, { cache: 'no-store' })
: fetch(url, { cache: 'no-store' });
const response = await fetcher(
withCORSProxy(
`https://${regionToRegionSubdomain(
+23
View File
@@ -0,0 +1,23 @@
export async function patientFetchJSON<Type extends object>(
url: string,
timeout = 1000,
options?: Partial<{ cache: 'no-store' }>,
) {
let patientJSON: Type;
while (patientJSON! === undefined) {
try {
patientJSON = (await fetch(url, options).then((response) =>
response.json(),
)) as Type;
} catch (error) {
console.warn(
`Failed to fetch ${url} as JSON; retrying in ${timeout}ms...`,
error,
);
await new Promise((resolve) => setTimeout(resolve, timeout));
}
}
return patientJSON;
}
+2 -1
View File
@@ -1,10 +1,11 @@
import { Client, GatewayIntentBits } from 'discord.js';
import guildMemberAdd from '../../events/guildMemberAdd';
import interactionCreate from '../../events/interactionCreate';
import ready from '../../events/ready';
export const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers],
})
// .on('ready', ready)
.on('ready', ready)
.on('guildMemberAdd', guildMemberAdd)
.on('interactionCreate', interactionCreate);
-2
View File
@@ -16,7 +16,6 @@ import {
import discord from '../../../discord.json' assert { type: 'json' };
import { aboutCommand } from '../../commands/about';
import { breakdownCommand } from '../../commands/breakdown';
import { creditsCommand } from '../../commands/credits';
import { debugCommand } from '../../commands/debug';
import { eligibleCommand } from '../../commands/eligible';
import { evolutionCommand } from '../../commands/evolution';
@@ -102,7 +101,6 @@ export const COMMANDS_RAW: CommandRegistry[] = [
evolutionCommand,
statsCommand,
ratingsCommand,
creditsCommand,
];
export const commands = Promise.all(COMMANDS_RAW).then((rawCommands) =>
+17 -2
View File
@@ -1,5 +1,20 @@
import { Client } from 'discord.js';
import { ActivityType, Client } from 'discord.js';
export default function ready(client: Client<true>) {
console.log(`🟢 Launched bot ${client.shard?.ids[0]}`);
console.log(`🟢 Launched bot ${client.shard?.ids[0] ?? 'default'}`);
const activities: (() => string)[] = [
() => `Living in ${client.guilds.cache.size.toLocaleString()} servers`,
() => `Serving ${client.users.cache.size.toLocaleString()} users`,
() => `Observing ${client.channels.cache.size.toLocaleString()} channels`,
];
client.user.setPresence({
activities: [
{
type: ActivityType.Custom,
name: activities[Math.floor(Math.random() * activities.length)](),
},
],
});
}