mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 20:19:49 +02:00
feat: dailystats
This commit is contained in:
1 parent
f729aee3de
commit
e37a7947b4
18 files changed
+578
-94
No files matched your search
@@ -43,8 +43,5 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn
|
run: yarn
|
||||||
|
|
||||||
- name: Install playwright
|
|
||||||
run: npx playwright install
|
|
||||||
|
|
||||||
- name: Host
|
- name: Host
|
||||||
run: yarn run start discord-token=${{ secrets.DISCORD_TOKEN }} wargaming-application-id=${{ secrets.WARGAMING_APPLICATION_ID }}
|
run: yarn run start discord-token=${{ secrets.DISCORD_TOKEN }} wargaming-application-id=${{ secrets.WARGAMING_APPLICATION_ID }}
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
tasks:
|
tasks:
|
||||||
- init: yarn
|
- init: yarn
|
||||||
|
- command: npx playwright install && npx playwright install-deps
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"install": "playwright install && playwright install-deps",
|
||||||
"start": "vite-node src/index.ts --script",
|
"start": "vite-node src/index.ts --script",
|
||||||
"lint": "tsc"
|
"lint": "tsc"
|
||||||
},
|
},
|
||||||
|
|||||||
+31
-28
@@ -1,7 +1,8 @@
|
|||||||
import { SlashCommandBuilder } from 'discord.js';
|
import { SlashCommandBuilder } from 'discord.js';
|
||||||
import escapeHTML from 'escape-html';
|
import escapeHTML from 'escape-html';
|
||||||
import GenericStats from '../components/GenericStats/index.js';
|
import GenericStats from '../components/GenericStats/index.js';
|
||||||
import Screenshot from '../components/Screenshot.js';
|
import NoBattlesInPeriod from '../components/NoBattlesInPeriod.js';
|
||||||
|
import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
|
||||||
import TitleBar from '../components/TitleBar.js';
|
import TitleBar from '../components/TitleBar.js';
|
||||||
import Wrapper from '../components/Wrapper.js';
|
import Wrapper from '../components/Wrapper.js';
|
||||||
import { BLITZ_SERVERS } from '../constants/servers.js';
|
import { BLITZ_SERVERS } from '../constants/servers.js';
|
||||||
@@ -12,8 +13,8 @@ import getBlitzStarsAccount from '../core/blitzstars/getBlitzStarsAccount.js';
|
|||||||
import cmdName from '../core/interaction/cmdName.js';
|
import cmdName from '../core/interaction/cmdName.js';
|
||||||
import addUsernameOption from '../core/options/addUsernameOption.js';
|
import addUsernameOption from '../core/options/addUsernameOption.js';
|
||||||
import { args } from '../core/process/args.js';
|
import { args } from '../core/process/args.js';
|
||||||
|
import screenshotHTML from '../core/ui/screenshotHTML.js';
|
||||||
import { CommandRegistry } from '../events/interactionCreate.js';
|
import { CommandRegistry } from '../events/interactionCreate.js';
|
||||||
import { browser } from '../index.js';
|
|
||||||
import { AccountInfo, AllStats } from '../types/accountInfo.js';
|
import { AccountInfo, AllStats } from '../types/accountInfo.js';
|
||||||
import { PlayerClanData } from '../types/playerClanData.js';
|
import { PlayerClanData } from '../types/playerClanData.js';
|
||||||
import { BlitzStartsComputedPeriodicStatistics } from '../types/statistics.js';
|
import { BlitzStartsComputedPeriodicStatistics } from '../types/statistics.js';
|
||||||
@@ -29,7 +30,7 @@ const periodNames: Record<Period, string> = {
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
inProduction: true,
|
inProduction: true,
|
||||||
inDevelopment: true,
|
inDevelopment: false,
|
||||||
inPublic: true,
|
inPublic: true,
|
||||||
|
|
||||||
command: new SlashCommandBuilder()
|
command: new SlashCommandBuilder()
|
||||||
@@ -72,8 +73,8 @@ export default {
|
|||||||
const a2 = accountInfo[id].statistics;
|
const a2 = accountInfo[id].statistics;
|
||||||
const battles = a2.all.battles - a1.all.battles;
|
const battles = a2.all.battles - a1.all.battles;
|
||||||
|
|
||||||
function pb(value: (allStats: AllStats) => number) {
|
function max(value: (allStats: AllStats) => number) {
|
||||||
return (value(a2.all) - value(a1.all)) / battles;
|
return Math.max(value(a2.all), value(a1.all));
|
||||||
}
|
}
|
||||||
function diff(value: (allStats: AllStats) => number) {
|
function diff(value: (allStats: AllStats) => number) {
|
||||||
return value(a2.all) - value(a1.all);
|
return value(a2.all) - value(a1.all);
|
||||||
@@ -82,18 +83,16 @@ export default {
|
|||||||
stats = {
|
stats = {
|
||||||
all: {
|
all: {
|
||||||
battles,
|
battles,
|
||||||
capture_points: pb((a) => a.capture_points),
|
capture_points: diff((a) => a.capture_points),
|
||||||
damage_dealt: pb((a) => a.damage_dealt),
|
damage_dealt: diff((a) => a.damage_dealt),
|
||||||
damage_received: pb((a) => a.damage_received),
|
damage_received: diff((a) => a.damage_received),
|
||||||
dropped_capture_points: diff((a) => a.dropped_capture_points),
|
dropped_capture_points: diff((a) => a.dropped_capture_points),
|
||||||
frags: pb((a) => a.frags),
|
frags: diff((a) => a.frags),
|
||||||
frags8p: pb((a) => a.frags8p),
|
frags8p: diff((a) => a.frags8p),
|
||||||
hits: diff((a) => a.hits),
|
hits: diff((a) => a.hits),
|
||||||
losses: diff((a) => a.losses),
|
losses: diff((a) => a.losses),
|
||||||
max_frags: pb((a) => a.max_frags),
|
max_frags: max((a) => a.max_frags),
|
||||||
max_frags_tank_id: pb((a) => a.max_frags_tank_id),
|
max_xp: max((a) => a.max_xp),
|
||||||
max_xp: pb((a) => a.max_xp),
|
|
||||||
max_xp_tank_id: pb((a) => a.max_xp_tank_id),
|
|
||||||
shots: diff((a) => a.shots),
|
shots: diff((a) => a.shots),
|
||||||
spotted: diff((a) => a.spotted),
|
spotted: diff((a) => a.spotted),
|
||||||
survived_battles: diff((a) => a.survived_battles),
|
survived_battles: diff((a) => a.survived_battles),
|
||||||
@@ -113,22 +112,22 @@ export default {
|
|||||||
}
|
}
|
||||||
if (!stats) return;
|
if (!stats) return;
|
||||||
|
|
||||||
const page = await browser.newPage();
|
const screenshot = await screenshotHTML(
|
||||||
await page.setViewportSize({ width: 640, height: 1 });
|
|
||||||
await page.setContent(
|
|
||||||
Screenshot(
|
|
||||||
Wrapper(
|
Wrapper(
|
||||||
TitleBar(
|
TitleBar(
|
||||||
escapeHTML(blitzStarsAccount.nickname),
|
escapeHTML(blitzStarsAccount.nickname),
|
||||||
|
clanData[id]?.clan ? `[${clanData[id]?.clan?.tag}]` : '',
|
||||||
clanData[id]?.clan
|
clanData[id]?.clan
|
||||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanData[id]?.clan?.emblem_set_id}.png`
|
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanData[id]?.clan?.emblem_set_id}.png`
|
||||||
: 'https://i.imgur.com/uq6pKbh.png',
|
: undefined,
|
||||||
clanData[id]?.clan ? `[${clanData[id]?.clan?.tag}]` : '',
|
|
||||||
`${periodNames[period]} • ${new Date().toDateString()} • ${
|
`${periodNames[period]} • ${new Date().toDateString()} • ${
|
||||||
BLITZ_SERVERS[server]
|
BLITZ_SERVERS[server]
|
||||||
}`,
|
}`,
|
||||||
),
|
),
|
||||||
GenericStats([
|
|
||||||
|
stats.all.battles === 0
|
||||||
|
? NoBattlesInPeriod()
|
||||||
|
: GenericStats([
|
||||||
[
|
[
|
||||||
'Winrate',
|
'Winrate',
|
||||||
`${(100 * (stats.all.wins / stats.all.battles)).toFixed(2)}%`,
|
`${(100 * (stats.all.wins / stats.all.battles)).toFixed(2)}%`,
|
||||||
@@ -153,9 +152,15 @@ export default {
|
|||||||
(stats.all.damage_dealt / stats.all.battles).toFixed(0),
|
(stats.all.damage_dealt / stats.all.battles).toFixed(0),
|
||||||
],
|
],
|
||||||
['Average XP', (stats.all.xp / stats.all.battles).toFixed(0)],
|
['Average XP', (stats.all.xp / stats.all.battles).toFixed(0)],
|
||||||
['Average shots', (stats.all.shots / stats.all.battles).toFixed(2)],
|
[
|
||||||
|
'Average shots',
|
||||||
|
(stats.all.shots / stats.all.battles).toFixed(2),
|
||||||
|
],
|
||||||
['Average hits', (stats.all.hits / stats.all.battles).toFixed(2)],
|
['Average hits', (stats.all.hits / stats.all.battles).toFixed(2)],
|
||||||
['Average kills', (stats.all.frags / stats.all.battles).toFixed(2)],
|
[
|
||||||
|
'Average kills',
|
||||||
|
(stats.all.frags / stats.all.battles).toFixed(2),
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'Average spots',
|
'Average spots',
|
||||||
(stats.all.spotted / stats.all.battles).toFixed(2),
|
(stats.all.spotted / stats.all.battles).toFixed(2),
|
||||||
@@ -173,13 +178,11 @@ export default {
|
|||||||
).toFixed(2),
|
).toFixed(2),
|
||||||
],
|
],
|
||||||
]),
|
]),
|
||||||
),
|
|
||||||
|
PoweredByBlitzStars(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
const screenshot = await page
|
|
||||||
.locator('#screenshot')
|
|
||||||
.screenshot({ omitBackground: true, scale: 'css' });
|
|
||||||
await page.close();
|
|
||||||
await interaction.editReply({ files: [screenshot] });
|
await interaction.editReply({ files: [screenshot] });
|
||||||
|
|
||||||
console.log(`Showing stats for ${blitzStarsAccount.nickname}`);
|
console.log(`Showing stats for ${blitzStarsAccount.nickname}`);
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import { SlashCommandBuilder } from 'discord.js';
|
||||||
|
import escapeHTML from 'escape-html';
|
||||||
|
import Breakdown from '../components/Breakdown.js';
|
||||||
|
import NoBattlesInPeriod from '../components/NoBattlesInPeriod.js';
|
||||||
|
import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
|
||||||
|
import TitleBar from '../components/TitleBar.js';
|
||||||
|
import Wrapper from '../components/Wrapper.js';
|
||||||
|
import { BLITZ_SERVERS } from '../constants/servers.js';
|
||||||
|
import usernameAutocomplete from '../core/autocomplete/username.js';
|
||||||
|
import getBlitzAccount from '../core/blitz/getBlitzAccount.js';
|
||||||
|
import getWargamingResponse from '../core/blitz/getWargamingResponse.js';
|
||||||
|
import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js';
|
||||||
|
import last5AM from '../core/blitzstars/last5AM.js';
|
||||||
|
import { tankopedia } from '../core/blitzstars/tankopedia.js';
|
||||||
|
import cmdName from '../core/interaction/cmdName.js';
|
||||||
|
import addUsernameOption from '../core/options/addUsernameOption.js';
|
||||||
|
import { args } from '../core/process/args.js';
|
||||||
|
import screenshotHTML from '../core/ui/screenshotHTML.js';
|
||||||
|
import { CommandRegistry } from '../events/interactionCreate.js';
|
||||||
|
import { AccountInfo, AllStats } from '../types/accountInfo.js';
|
||||||
|
import { PlayerClanData } from '../types/playerClanData.js';
|
||||||
|
import { TanksStats } from '../types/tanksStats.js';
|
||||||
|
import resolveTankName from '../utilities/resolveTankName.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
inProduction: true,
|
||||||
|
inDevelopment: true,
|
||||||
|
inPublic: true,
|
||||||
|
|
||||||
|
command: new SlashCommandBuilder()
|
||||||
|
.setName(cmdName('today'))
|
||||||
|
.setDescription('A general daily breakdown of your performance')
|
||||||
|
.addStringOption(addUsernameOption),
|
||||||
|
|
||||||
|
async execute(interaction) {
|
||||||
|
const username = interaction.options.getString('username')!;
|
||||||
|
const blitzAccount = await getBlitzAccount(interaction, username);
|
||||||
|
if (!blitzAccount) return;
|
||||||
|
const { id, server } = blitzAccount;
|
||||||
|
const tankStatsOverTime = await getTankStatsOverTime(
|
||||||
|
server,
|
||||||
|
id,
|
||||||
|
last5AM().getTime() / 1000,
|
||||||
|
new Date().getTime() / 1000,
|
||||||
|
);
|
||||||
|
if (!tankStatsOverTime) return;
|
||||||
|
const accountInfo = await getWargamingResponse<AccountInfo>(
|
||||||
|
`https://api.wotblitz.${server}/wotb/account/info/?application_id=${args['wargaming-application-id']}&account_id=${id}`,
|
||||||
|
);
|
||||||
|
if (!accountInfo) return;
|
||||||
|
const clanData = await getWargamingResponse<PlayerClanData>(
|
||||||
|
`https://api.wotblitz.${server}/wotb/clans/accountinfo/?application_id=${args['wargaming-application-id']}&account_id=${id}&extra=clan`,
|
||||||
|
);
|
||||||
|
if (!clanData) return;
|
||||||
|
const careerTankStatsRaw = await getWargamingResponse<TanksStats>(
|
||||||
|
`https://api.wotblitz.${server}/wotb/tanks/stats/?application_id=${args['wargaming-application-id']}&account_id=${id}`,
|
||||||
|
);
|
||||||
|
if (!careerTankStatsRaw) return;
|
||||||
|
const careerStats: Record<number, AllStats> = {};
|
||||||
|
|
||||||
|
Object.entries(careerTankStatsRaw[id]).forEach(([, tankStats]) => {
|
||||||
|
careerStats[tankStats.tank_id] = tankStats.all;
|
||||||
|
});
|
||||||
|
|
||||||
|
const rows = Object.entries(tankStatsOverTime).map(
|
||||||
|
([tankId, tankStats]) => {
|
||||||
|
const career = careerStats[tankId as unknown as number];
|
||||||
|
|
||||||
|
return Breakdown.Row(
|
||||||
|
resolveTankName({
|
||||||
|
tank_id: tankId as unknown as number,
|
||||||
|
name: tankopedia.data[tankId as unknown as number].name,
|
||||||
|
}),
|
||||||
|
tankStats.wins / tankStats.battles,
|
||||||
|
career.wins / career.battles,
|
||||||
|
-Infinity,
|
||||||
|
-Infinity,
|
||||||
|
tankStats.damage_dealt / tankStats.battles,
|
||||||
|
career.damage_dealt / career.battles,
|
||||||
|
(tankStats.battles - tankStats.survived_battles) / tankStats.battles,
|
||||||
|
(career.battles - career.survived_battles) / career.battles,
|
||||||
|
tankStats.battles,
|
||||||
|
career.battles,
|
||||||
|
tankopedia.data[tankId as unknown as number].images.normal,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const screenshot = await screenshotHTML(
|
||||||
|
Wrapper(
|
||||||
|
TitleBar(
|
||||||
|
escapeHTML(accountInfo[id].nickname),
|
||||||
|
clanData[id]?.clan ? `[${clanData[id]?.clan?.tag}]` : '',
|
||||||
|
clanData[id]?.clan
|
||||||
|
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanData[id]?.clan?.emblem_set_id}.png`
|
||||||
|
: undefined,
|
||||||
|
`Today's breakdown • ${new Date().toDateString()} • ${
|
||||||
|
BLITZ_SERVERS[server]
|
||||||
|
}`,
|
||||||
|
),
|
||||||
|
|
||||||
|
rows.length === 0 ? NoBattlesInPeriod() : Breakdown.Root(...rows),
|
||||||
|
|
||||||
|
PoweredByBlitzStars(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await interaction.editReply({ files: [screenshot] });
|
||||||
|
|
||||||
|
console.log(`Showing daily breakdown for ${accountInfo[id].nickname}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
autocomplete: usernameAutocomplete,
|
||||||
|
} satisfies CommandRegistry;
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
import Children from './Children.js';
|
||||||
|
|
||||||
|
const Breakdown = {
|
||||||
|
Root(...children: string[]) {
|
||||||
|
return `
|
||||||
|
<style>
|
||||||
|
.breakdown {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="breakdown">
|
||||||
|
${Children(children)}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
|
||||||
|
Row(
|
||||||
|
name: string,
|
||||||
|
winrate: number,
|
||||||
|
careerWinrate: number,
|
||||||
|
wn8: number,
|
||||||
|
careerWn8: number,
|
||||||
|
averageDamage: number,
|
||||||
|
careerAverageDamage: number,
|
||||||
|
survival: number,
|
||||||
|
careerSurvival: number,
|
||||||
|
battles: number,
|
||||||
|
careerBattles: number,
|
||||||
|
icon?: string,
|
||||||
|
) {
|
||||||
|
return `
|
||||||
|
<style>
|
||||||
|
.breakdown-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="breakdown-row">
|
||||||
|
${this.RowDiscriminator(name, icon)}
|
||||||
|
${this.RowStat(
|
||||||
|
'Winrate',
|
||||||
|
`${(winrate * 100).toFixed(2)}%`,
|
||||||
|
`${(careerWinrate * 100).toFixed(2)}%`,
|
||||||
|
winrate - careerWinrate,
|
||||||
|
)}
|
||||||
|
${this.RowStat(
|
||||||
|
'Damage',
|
||||||
|
averageDamage.toFixed(2),
|
||||||
|
careerAverageDamage.toFixed(2),
|
||||||
|
averageDamage - careerAverageDamage,
|
||||||
|
)}
|
||||||
|
${this.RowStat(
|
||||||
|
'Survival',
|
||||||
|
`${(survival * 100).toFixed(2)}%`,
|
||||||
|
`${(careerSurvival * 100).toFixed(2)}%`,
|
||||||
|
survival - careerSurvival,
|
||||||
|
)}
|
||||||
|
${this.RowStat('Battles', battles.toFixed(0), careerBattles.toFixed(0))}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
/*
|
||||||
|
${this.RowStat(
|
||||||
|
'WN8',
|
||||||
|
wn8.toFixed(0),
|
||||||
|
careerWn8.toFixed(0),
|
||||||
|
wn8 - careerWn8,
|
||||||
|
)}
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
|
||||||
|
RowDiscriminator(name: string, icon?: string) {
|
||||||
|
return `
|
||||||
|
<style>
|
||||||
|
.breakdown-row-discriminator {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 0px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breakdown-row-discriminator-icon {
|
||||||
|
width: 100%;
|
||||||
|
flex: 1;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breakdown-row-discriminator-name {
|
||||||
|
color: #A0A0A0;
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="breakdown-row-discriminator">
|
||||||
|
${
|
||||||
|
icon
|
||||||
|
? `<img src="${icon}" class="breakdown-row-discriminator-icon" />`
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
<span class="breakdown-row-discriminator-name">${name}</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
|
||||||
|
RowStat(name: string, value: string, career: string, delta?: number) {
|
||||||
|
return `
|
||||||
|
<style>
|
||||||
|
.breakdown-row-stat {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breakdown-row-stat-career {
|
||||||
|
color: #A0A0A0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breakdown-row-stat-name {
|
||||||
|
color: #A0A0A0;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breakdown-row-stat-value {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breakdown-row-stat-value-delta {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breakdown-row-stat-value-text {
|
||||||
|
color: white;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="breakdown-row-stat">
|
||||||
|
<span class="breakdown-row-stat-career">${career}</span>
|
||||||
|
|
||||||
|
<div class="breakdown-row-stat-value">
|
||||||
|
${
|
||||||
|
delta
|
||||||
|
? `<img src="${
|
||||||
|
(delta ?? 0) > 0
|
||||||
|
? 'https://i.imgur.com/qbjiXa1.png'
|
||||||
|
: 'https://i.imgur.com/3uyNhun.png'
|
||||||
|
}" class="breakdown-row-stat-value-delta" />`
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
<span class="breakdown-row-stat-value-text">${value}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span class="breakdown-row-stat-name">${name}</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Breakdown;
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
export default function NoBattlesInPeriod() {
|
||||||
|
return `
|
||||||
|
<style>
|
||||||
|
.no-battles-in-period {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-battles-in-period-text {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #A0A0A0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="no-battles-in-period">
|
||||||
|
<span class="no-battles-in-period-text">No battles played in this period</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
export default function PoweredByBlitzStars() {
|
||||||
|
return `
|
||||||
|
<style>
|
||||||
|
.powered-by-blitz-stars {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.powered-by-blitz-stars-icon {
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.powered-by-blitz-stars-text {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #A0A0A0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="powered-by-blitz-stars">
|
||||||
|
<img class="powered-by-blitz-stars-icon" src="https://www.blitzstars.com/assets/images/4b4cb591.TankyMcPewpew.png" />
|
||||||
|
<span class="powered-by-blitz-stars-text">Powered by BlitzStars</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import Children from './Children.js';
|
import Children from './Children.js';
|
||||||
|
|
||||||
export default function Screenshot(...children: string[]) {
|
export default function Root(...children: string[]) {
|
||||||
return `
|
return `
|
||||||
<style>
|
<style>
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Roboto+Flex:[email protected]');
|
@import url('https://fonts.googleapis.com/css2?family=Roboto+Flex:[email protected]');
|
||||||
@@ -14,12 +14,12 @@ export default function Screenshot(...children: string[]) {
|
|||||||
font-family: 'Roboto Flex', sans-serif;
|
font-family: 'Roboto Flex', sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
#screenshot {
|
#root {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div id="screenshot">
|
<div id="root">
|
||||||
${Children(children)}
|
${Children(children)}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
export default function TitleBar(
|
export default function TitleBar(
|
||||||
name: string,
|
name: string,
|
||||||
image: string,
|
nameDiscriminator: string,
|
||||||
nameDiscriminator = '',
|
image?: string,
|
||||||
description = '',
|
description?: string,
|
||||||
) {
|
) {
|
||||||
return `
|
return `
|
||||||
<style>
|
<style>
|
||||||
@@ -51,7 +51,7 @@ export default function TitleBar(
|
|||||||
|
|
||||||
<div class="title-bar">
|
<div class="title-bar">
|
||||||
<div class="title-bar-info">
|
<div class="title-bar-info">
|
||||||
<img class="title-bar-avatar" src="${image}" />
|
${image ? `<img class="title-bar-avatar" src="${image}" />` : ''}
|
||||||
|
|
||||||
<div class="title-bar-text">
|
<div class="title-bar-text">
|
||||||
<span class="title-bar-name">
|
<span class="title-bar-name">
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ export default async function getWargamingResponse<Data extends object>(
|
|||||||
if (parsed.status === 'ok') {
|
if (parsed.status === 'ok') {
|
||||||
return parsed.data;
|
return parsed.data;
|
||||||
} else {
|
} else {
|
||||||
console.error(`Wargaming response status ${parsed.status}`);
|
console.error(
|
||||||
|
`Wargaming response status ${parsed.status} ${parsed.error.message}`,
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
import fetch from 'node-fetch';
|
||||||
|
import { BlitzServer } from '../../constants/servers.js';
|
||||||
|
import { AllStats } from '../../types/accountInfo.js';
|
||||||
|
import { TanksStats } from '../../types/tanksStats.js';
|
||||||
|
import getWargamingResponse from '../blitz/getWargamingResponse.js';
|
||||||
|
import { args } from '../process/args.js';
|
||||||
|
|
||||||
|
export interface TankHistoryNode {
|
||||||
|
all: AllStats;
|
||||||
|
last_battle_time: number;
|
||||||
|
mark_of_mastery: number;
|
||||||
|
battle_life_time: number;
|
||||||
|
account_id: number;
|
||||||
|
tank_id: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const emptyTankHistoryNode: TankHistoryNode = {
|
||||||
|
account_id: 0,
|
||||||
|
battle_life_time: 0,
|
||||||
|
last_battle_time: 0,
|
||||||
|
mark_of_mastery: 0,
|
||||||
|
tank_id: 0,
|
||||||
|
all: {
|
||||||
|
battles: 0,
|
||||||
|
capture_points: 0,
|
||||||
|
damage_dealt: 0,
|
||||||
|
damage_received: 0,
|
||||||
|
dropped_capture_points: 0,
|
||||||
|
frags: 0,
|
||||||
|
frags8p: 0,
|
||||||
|
hits: 0,
|
||||||
|
losses: 0,
|
||||||
|
max_frags: 0,
|
||||||
|
max_xp: 0,
|
||||||
|
shots: 0,
|
||||||
|
spotted: 0,
|
||||||
|
survived_battles: 0,
|
||||||
|
xp: 0,
|
||||||
|
win_and_survived: 0,
|
||||||
|
wins: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TankHistory = TankHistoryNode[];
|
||||||
|
|
||||||
|
export default async function getTankStatsOverTime(
|
||||||
|
server: BlitzServer,
|
||||||
|
id: number,
|
||||||
|
start = -Infinity,
|
||||||
|
end = Infinity,
|
||||||
|
) {
|
||||||
|
const latestTankStatsRaw = await getWargamingResponse<TanksStats>(
|
||||||
|
`https://api.wotblitz.${server}/wotb/tanks/stats/?application_id=${args['wargaming-application-id']}&account_id=${id}`,
|
||||||
|
);
|
||||||
|
if (!latestTankStatsRaw) return;
|
||||||
|
const tankHistoriesResponse = await fetch(
|
||||||
|
`https://www.blitzstars.com/api/tankhistories/for/${id}/`,
|
||||||
|
);
|
||||||
|
const tankHistories = (await tankHistoriesResponse.json()) as TankHistory;
|
||||||
|
const history = [...tankHistories, ...latestTankStatsRaw[id]];
|
||||||
|
|
||||||
|
// sort them even though most won't be used
|
||||||
|
const tankSortedHistory: Record<number, TankHistory> = {};
|
||||||
|
const tankIds: number[] = [];
|
||||||
|
history.forEach((node) => {
|
||||||
|
if (!tankSortedHistory[node.tank_id]) {
|
||||||
|
tankSortedHistory[node.tank_id] = [node];
|
||||||
|
tankIds.push(node.tank_id);
|
||||||
|
} else {
|
||||||
|
tankSortedHistory[node.tank_id].push(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// find the ones played within the range
|
||||||
|
const tankIdsInRange = tankIds.filter((tankId) =>
|
||||||
|
tankSortedHistory[tankId].some(
|
||||||
|
(node) => node.last_battle_time > start && node.last_battle_time < end,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// fetch history node right before "start" and right before "end"
|
||||||
|
const tanksBeforeAndAfter: Record<number, AllStats> = {};
|
||||||
|
tankIdsInRange.forEach((tankId) => {
|
||||||
|
const sortedHistory = tankSortedHistory[tankId];
|
||||||
|
const previousIndex =
|
||||||
|
sortedHistory.findIndex((node) => node.last_battle_time > start) - 1;
|
||||||
|
const latestIndex =
|
||||||
|
sortedHistory.findIndex((node) => node.last_battle_time > end) - 1;
|
||||||
|
const previous = sortedHistory[previousIndex] ?? emptyTankHistoryNode;
|
||||||
|
const latest =
|
||||||
|
sortedHistory[latestIndex] ?? sortedHistory[sortedHistory.length - 1];
|
||||||
|
|
||||||
|
function diff(get: (allStats: AllStats) => number) {
|
||||||
|
return get(latest.all) - get(previous.all);
|
||||||
|
}
|
||||||
|
function max(get: (allStats: AllStats) => number) {
|
||||||
|
return Math.max(get(latest.all), get(previous.all));
|
||||||
|
}
|
||||||
|
|
||||||
|
tanksBeforeAndAfter[tankId] = {
|
||||||
|
battles: diff((a) => a.battles),
|
||||||
|
capture_points: diff((a) => a.capture_points),
|
||||||
|
damage_dealt: diff((a) => a.damage_dealt),
|
||||||
|
damage_received: diff((a) => a.damage_received),
|
||||||
|
dropped_capture_points: diff((a) => a.dropped_capture_points),
|
||||||
|
frags: diff((a) => a.frags),
|
||||||
|
frags8p: diff((a) => a.frags8p),
|
||||||
|
hits: diff((a) => a.hits),
|
||||||
|
losses: diff((a) => a.losses),
|
||||||
|
max_frags: max((a) => a.max_frags),
|
||||||
|
max_xp: max((a) => a.max_xp),
|
||||||
|
shots: diff((a) => a.shots),
|
||||||
|
spotted: diff((a) => a.spotted),
|
||||||
|
survived_battles: diff((a) => a.survived_battles),
|
||||||
|
win_and_survived: diff((a) => a.win_and_survived),
|
||||||
|
wins: diff((a) => a.wins),
|
||||||
|
xp: diff((a) => a.xp),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return tanksBeforeAndAfter;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export default function last5AM() {
|
||||||
|
const fiveAM = new Date();
|
||||||
|
fiveAM.setHours(5, 0, 0, 0); // Set the time to 5:00 AM today
|
||||||
|
|
||||||
|
if (fiveAM > new Date()) {
|
||||||
|
// If it's now before 5:00 AM, go back one day
|
||||||
|
fiveAM.setDate(fiveAM.getDate() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fiveAM;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import Root from '../../components/Root.js';
|
||||||
|
import { browser } from '../../index.js';
|
||||||
|
|
||||||
|
export default async function screenshotHTML(children: string) {
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.setViewportSize({ width: 640, height: 1 });
|
||||||
|
await page.setContent(Root(children));
|
||||||
|
const screenshot = await page
|
||||||
|
.locator('#root')
|
||||||
|
.screenshot({ omitBackground: true, scale: 'css' });
|
||||||
|
await page.close();
|
||||||
|
|
||||||
|
return screenshot;
|
||||||
|
}
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
export interface AllStats {
|
export interface AllStats {
|
||||||
spotted: number;
|
spotted: number;
|
||||||
max_frags_tank_id: number;
|
|
||||||
hits: number;
|
hits: number;
|
||||||
frags: number;
|
frags: number;
|
||||||
max_xp: number;
|
max_xp: number;
|
||||||
max_xp_tank_id: number;
|
|
||||||
wins: number;
|
wins: number;
|
||||||
losses: number;
|
losses: number;
|
||||||
capture_points: number;
|
capture_points: number;
|
||||||
|
|||||||
+8
-22
@@ -1,24 +1,7 @@
|
|||||||
export type TanksStats = {
|
import { AllStats } from './accountInfo.js';
|
||||||
[accountId: number]: {
|
|
||||||
all: {
|
export interface IndividualTankStats {
|
||||||
spotted: number;
|
all: AllStats;
|
||||||
hits: number;
|
|
||||||
frags: number;
|
|
||||||
max_xp: number;
|
|
||||||
wins: number;
|
|
||||||
losses: number;
|
|
||||||
capture_points: number;
|
|
||||||
battles: number;
|
|
||||||
damage_dealt: number;
|
|
||||||
damage_received: number;
|
|
||||||
max_frags: number;
|
|
||||||
shots: number;
|
|
||||||
frags8p: number;
|
|
||||||
xp: number;
|
|
||||||
win_and_survived: number;
|
|
||||||
survived_battles: number;
|
|
||||||
dropped_capture_points: number;
|
|
||||||
};
|
|
||||||
last_battle_time: number;
|
last_battle_time: number;
|
||||||
account_id: number;
|
account_id: number;
|
||||||
max_xp: number;
|
max_xp: number;
|
||||||
@@ -29,5 +12,8 @@ export type TanksStats = {
|
|||||||
battle_life_time: number;
|
battle_life_time: number;
|
||||||
in_garage: number | null;
|
in_garage: number | null;
|
||||||
tank_id: number;
|
tank_id: number;
|
||||||
}[];
|
}
|
||||||
|
|
||||||
|
export type TanksStats = {
|
||||||
|
[accountId: number]: IndividualTankStats[];
|
||||||
};
|
};
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
export type WargamingResponse<Data extends object> =
|
export type WargamingResponse<Data extends object> =
|
||||||
| {
|
| {
|
||||||
status: 'error';
|
status: 'error';
|
||||||
|
error: {
|
||||||
|
field: string;
|
||||||
|
message: string;
|
||||||
|
code: 402;
|
||||||
|
value: null;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
status: 'ok';
|
status: 'ok';
|
||||||
|
|||||||
@@ -123,7 +123,7 @@
|
|||||||
|
|
||||||
"@esbuild/[email protected]":
|
"@esbuild/[email protected]":
|
||||||
version "0.17.19"
|
version "0.17.19"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz#8a0e9738b1635f0c53389e515ae83826dec22aa4"
|
resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz"
|
||||||
integrity sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==
|
integrity sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==
|
||||||
|
|
||||||
"@esbuild/[email protected]":
|
"@esbuild/[email protected]":
|
||||||
@@ -158,7 +158,7 @@
|
|||||||
|
|
||||||
"@playwright/test@^1.34.2":
|
"@playwright/test@^1.34.2":
|
||||||
version "1.34.2"
|
version "1.34.2"
|
||||||
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.34.2.tgz#938ccfb8c162e8ef83dbef3d88ce6851acd469e6"
|
resolved "https://registry.npmjs.org/@playwright/test/-/test-1.34.2.tgz"
|
||||||
integrity sha512-v/LBnwzD0225q8xEv3t9DmNPX61yvNnEbiA8PoNk1fbkxApJFCWYLPpQbdVWzHaARdZD9g1PYBoOvnffortfKw==
|
integrity sha512-v/LBnwzD0225q8xEv3t9DmNPX61yvNnEbiA8PoNk1fbkxApJFCWYLPpQbdVWzHaARdZD9g1PYBoOvnffortfKw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
@@ -191,29 +191,29 @@
|
|||||||
|
|
||||||
"@total-typescript/ts-reset@^0.4.2":
|
"@total-typescript/ts-reset@^0.4.2":
|
||||||
version "0.4.2"
|
version "0.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/@total-typescript/ts-reset/-/ts-reset-0.4.2.tgz#c564c173ba09973968e1046c93965b7a257878a4"
|
resolved "https://registry.npmjs.org/@total-typescript/ts-reset/-/ts-reset-0.4.2.tgz"
|
||||||
integrity sha512-vqd7ZUDSrXFVT1n8b2kc3LnklncDQFPvR58yUS1kEP23/nHPAO9l1lMjUfnPrXYYk4Hj54rrLKMW5ipwk7k09A==
|
integrity sha512-vqd7ZUDSrXFVT1n8b2kc3LnklncDQFPvR58yUS1kEP23/nHPAO9l1lMjUfnPrXYYk4Hj54rrLKMW5ipwk7k09A==
|
||||||
|
|
||||||
"@types/escape-html@^1.0.2":
|
"@types/escape-html@^1.0.2":
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/escape-html/-/escape-html-1.0.2.tgz#072b7b13784fb3cee9c2450c22f36405983f5e3c"
|
resolved "https://registry.npmjs.org/@types/escape-html/-/escape-html-1.0.2.tgz"
|
||||||
integrity sha512-gaBLT8pdcexFztLSPRtriHeXY/Kn4907uOCZ4Q3lncFBkheAWOuNt53ypsF8szgxbEJ513UeBzcf4utN0EzEwA==
|
integrity sha512-gaBLT8pdcexFztLSPRtriHeXY/Kn4907uOCZ4Q3lncFBkheAWOuNt53ypsF8szgxbEJ513UeBzcf4utN0EzEwA==
|
||||||
|
|
||||||
"@types/lodash.startcase@^4.4.7":
|
"@types/lodash.startcase@^4.4.7":
|
||||||
version "4.4.7"
|
version "4.4.7"
|
||||||
resolved "https://registry.yarnpkg.com/@types/lodash.startcase/-/lodash.startcase-4.4.7.tgz#69857f17be0aa5ce74da4fa386e32e22c012258a"
|
resolved "https://registry.npmjs.org/@types/lodash.startcase/-/lodash.startcase-4.4.7.tgz"
|
||||||
integrity sha512-6v8FVOcfxdomO1Vammc1Zsah7/4aif/Lx16oQQ0WZmKVGF/Yf5c5m68LqI/ELOhKaKUr8KfnDdKrytdrThoRQw==
|
integrity sha512-6v8FVOcfxdomO1Vammc1Zsah7/4aif/Lx16oQQ0WZmKVGF/Yf5c5m68LqI/ELOhKaKUr8KfnDdKrytdrThoRQw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/lodash" "*"
|
"@types/lodash" "*"
|
||||||
|
|
||||||
"@types/lodash@*":
|
"@types/lodash@*":
|
||||||
version "4.14.194"
|
version "4.14.194"
|
||||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.194.tgz#b71eb6f7a0ff11bff59fc987134a093029258a76"
|
resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.194.tgz"
|
||||||
integrity sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==
|
integrity sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==
|
||||||
|
|
||||||
"@types/markdown-escape@^1.1.0":
|
"@types/markdown-escape@^1.1.0":
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/markdown-escape/-/markdown-escape-1.1.0.tgz#8bd940d6701880eb7229467542c029bc05a7b22f"
|
resolved "https://registry.npmjs.org/@types/markdown-escape/-/markdown-escape-1.1.0.tgz"
|
||||||
integrity sha512-bJZh73L6fSt8MmTON/btR8hiKRipoIoPfLO41lxr6l65QXdG1rwUjR8Hu5xU7XYHBwKHiJZ+sTQ8L2TKkQrBpw==
|
integrity sha512-bJZh73L6fSt8MmTON/btR8hiKRipoIoPfLO41lxr6l65QXdG1rwUjR8Hu5xU7XYHBwKHiJZ+sTQ8L2TKkQrBpw==
|
||||||
|
|
||||||
"@types/node@*":
|
"@types/node@*":
|
||||||
@@ -223,7 +223,7 @@
|
|||||||
|
|
||||||
"@types/node@^20.2.1":
|
"@types/node@^20.2.1":
|
||||||
version "20.2.1"
|
version "20.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.1.tgz#de559d4b33be9a808fd43372ccee822c70f39704"
|
resolved "https://registry.npmjs.org/@types/node/-/node-20.2.1.tgz"
|
||||||
integrity sha512-DqJociPbZP1lbZ5SQPk4oag6W7AyaGMO6gSfRwq3PWl4PXTwJpRQJhDq4W0kzrg3w6tJ1SwlvGZ5uKFHY13LIg==
|
integrity sha512-DqJociPbZP1lbZ5SQPk4oag6W7AyaGMO6gSfRwq3PWl4PXTwJpRQJhDq4W0kzrg3w6tJ1SwlvGZ5uKFHY13LIg==
|
||||||
|
|
||||||
"@types/ws@^8.5.4":
|
"@types/ws@^8.5.4":
|
||||||
@@ -235,7 +235,7 @@
|
|||||||
|
|
||||||
acorn@^8.8.2:
|
acorn@^8.8.2:
|
||||||
version "8.8.2"
|
version "8.8.2"
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
|
resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz"
|
||||||
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
|
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
|
||||||
|
|
||||||
busboy@^1.6.0:
|
busboy@^1.6.0:
|
||||||
@@ -247,7 +247,7 @@ busboy@^1.6.0:
|
|||||||
|
|
||||||
cac@^6.7.14:
|
cac@^6.7.14:
|
||||||
version "6.7.14"
|
version "6.7.14"
|
||||||
resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959"
|
resolved "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz"
|
||||||
integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==
|
integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==
|
||||||
|
|
||||||
data-uri-to-buffer@^4.0.0:
|
data-uri-to-buffer@^4.0.0:
|
||||||
@@ -257,7 +257,7 @@ data-uri-to-buffer@^4.0.0:
|
|||||||
|
|
||||||
debug@^4.3.4:
|
debug@^4.3.4:
|
||||||
version "4.3.4"
|
version "4.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
|
||||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
ms "2.1.2"
|
ms "2.1.2"
|
||||||
@@ -288,7 +288,7 @@ discord.js@^14.9.0:
|
|||||||
|
|
||||||
esbuild@^0.17.5:
|
esbuild@^0.17.5:
|
||||||
version "0.17.19"
|
version "0.17.19"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.19.tgz#087a727e98299f0462a3d0bcdd9cd7ff100bd955"
|
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz"
|
||||||
integrity sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==
|
integrity sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
"@esbuild/android-arm" "0.17.19"
|
"@esbuild/android-arm" "0.17.19"
|
||||||
@@ -316,7 +316,7 @@ esbuild@^0.17.5:
|
|||||||
|
|
||||||
escape-html@^1.0.3:
|
escape-html@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz"
|
||||||
integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
|
integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
|
||||||
|
|
||||||
fast-deep-equal@^3.1.3:
|
fast-deep-equal@^3.1.3:
|
||||||
@@ -355,7 +355,7 @@ [email protected], fsevents@~2.3.2:
|
|||||||
|
|
||||||
fuzzysort@^2.0.4:
|
fuzzysort@^2.0.4:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/fuzzysort/-/fuzzysort-2.0.4.tgz#a21d1ce8947eaf2797dc3b7c28c36db9d1165f84"
|
resolved "https://registry.npmjs.org/fuzzysort/-/fuzzysort-2.0.4.tgz"
|
||||||
integrity sha512-Api1mJL+Ad7W7vnDZnWq5pGaXJjyencT+iKGia2PlHUcSsSzWwIQ3S1isiMpwpavjYtGd2FzhUIhnnhOULZgDw==
|
integrity sha512-Api1mJL+Ad7W7vnDZnWq5pGaXJjyencT+iKGia2PlHUcSsSzWwIQ3S1isiMpwpavjYtGd2FzhUIhnnhOULZgDw==
|
||||||
|
|
||||||
ieee754@^1.2.1:
|
ieee754@^1.2.1:
|
||||||
@@ -370,7 +370,7 @@ inherits@^2.0.3:
|
|||||||
|
|
||||||
jsonc-parser@^3.2.0:
|
jsonc-parser@^3.2.0:
|
||||||
version "3.2.0"
|
version "3.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76"
|
resolved "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz"
|
||||||
integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
|
integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
|
||||||
|
|
||||||
lodash.snakecase@^4.1.1:
|
lodash.snakecase@^4.1.1:
|
||||||
@@ -380,7 +380,7 @@ lodash.snakecase@^4.1.1:
|
|||||||
|
|
||||||
lodash.startcase@^4.4.0:
|
lodash.startcase@^4.4.0:
|
||||||
version "4.4.0"
|
version "4.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.startcase/-/lodash.startcase-4.4.0.tgz#9436e34ed26093ed7ffae1936144350915d9add8"
|
resolved "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz"
|
||||||
integrity sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==
|
integrity sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==
|
||||||
|
|
||||||
lodash@^4.17.21:
|
lodash@^4.17.21:
|
||||||
@@ -390,12 +390,12 @@ lodash@^4.17.21:
|
|||||||
|
|
||||||
markdown-escape@^2.0.0:
|
markdown-escape@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/markdown-escape/-/markdown-escape-2.0.0.tgz#44484d30d7845b91575c77fd8898f23a0a6f890c"
|
resolved "https://registry.npmjs.org/markdown-escape/-/markdown-escape-2.0.0.tgz"
|
||||||
integrity sha512-Trz4v0+XWlwy68LJIyw3bLbsJiC8XAbRCKF9DbEtZjyndKOGVx6n+wNB0VfoRmY2LKboQLeniap3xrb6LGSJ8A==
|
integrity sha512-Trz4v0+XWlwy68LJIyw3bLbsJiC8XAbRCKF9DbEtZjyndKOGVx6n+wNB0VfoRmY2LKboQLeniap3xrb6LGSJ8A==
|
||||||
|
|
||||||
mlly@^1.2.0:
|
mlly@^1.2.0:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.2.1.tgz#cd50151f5712b651c5c379085157bcdff661133b"
|
resolved "https://registry.npmjs.org/mlly/-/mlly-1.2.1.tgz"
|
||||||
integrity sha512-1aMEByaWgBPEbWV2BOPEMySRrzl7rIHXmQxam4DM8jVjalTQDjpN2ZKOLUrwyhfZQO7IXHml2StcHMhooDeEEQ==
|
integrity sha512-1aMEByaWgBPEbWV2BOPEMySRrzl7rIHXmQxam4DM8jVjalTQDjpN2ZKOLUrwyhfZQO7IXHml2StcHMhooDeEEQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn "^8.8.2"
|
acorn "^8.8.2"
|
||||||
@@ -405,12 +405,12 @@ mlly@^1.2.0:
|
|||||||
|
|
||||||
[email protected]:
|
[email protected]:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
|
||||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||||
|
|
||||||
nanoid@^3.3.6:
|
nanoid@^3.3.6:
|
||||||
version "3.3.6"
|
version "3.3.6"
|
||||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
|
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz"
|
||||||
integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
|
integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
|
||||||
|
|
||||||
node-domexception@^1.0.0:
|
node-domexception@^1.0.0:
|
||||||
@@ -429,7 +429,7 @@ node-fetch@^3.3.1:
|
|||||||
|
|
||||||
pathe@^1.1.0:
|
pathe@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.0.tgz#e2e13f6c62b31a3289af4ba19886c230f295ec03"
|
resolved "https://registry.npmjs.org/pathe/-/pathe-1.1.0.tgz"
|
||||||
integrity sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==
|
integrity sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==
|
||||||
|
|
||||||
peek-readable@^5.0.0:
|
peek-readable@^5.0.0:
|
||||||
@@ -439,12 +439,12 @@ peek-readable@^5.0.0:
|
|||||||
|
|
||||||
picocolors@^1.0.0:
|
picocolors@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz"
|
||||||
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
|
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
|
||||||
|
|
||||||
pkg-types@^1.0.3:
|
pkg-types@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.0.3.tgz#988b42ab19254c01614d13f4f65a2cfc7880f868"
|
resolved "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz"
|
||||||
integrity sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==
|
integrity sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==
|
||||||
dependencies:
|
dependencies:
|
||||||
jsonc-parser "^3.2.0"
|
jsonc-parser "^3.2.0"
|
||||||
@@ -453,12 +453,12 @@ pkg-types@^1.0.3:
|
|||||||
|
|
||||||
[email protected]:
|
[email protected]:
|
||||||
version "1.34.2"
|
version "1.34.2"
|
||||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.34.2.tgz#4989ba082f623f21679724033629b2333b626569"
|
resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.34.2.tgz"
|
||||||
integrity sha512-MrkgGWLANc5qthXduvIY1a/tuafROyTORVd86fwKwgoYrmnBooN/GgeZSBm7ljTLV2FCWNSXV3se7qeScKn83g==
|
integrity sha512-MrkgGWLANc5qthXduvIY1a/tuafROyTORVd86fwKwgoYrmnBooN/GgeZSBm7ljTLV2FCWNSXV3se7qeScKn83g==
|
||||||
|
|
||||||
postcss@^8.4.23:
|
postcss@^8.4.23:
|
||||||
version "8.4.23"
|
version "8.4.23"
|
||||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.23.tgz#df0aee9ac7c5e53e1075c24a3613496f9e6552ab"
|
resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz"
|
||||||
integrity sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==
|
integrity sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid "^3.3.6"
|
nanoid "^3.3.6"
|
||||||
@@ -483,7 +483,7 @@ readable-web-to-node-stream@^3.0.2:
|
|||||||
|
|
||||||
rollup@^3.21.0:
|
rollup@^3.21.0:
|
||||||
version "3.22.0"
|
version "3.22.0"
|
||||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.22.0.tgz#e6671baebdd473154ac7998bbc57faabcd7bba20"
|
resolved "https://registry.npmjs.org/rollup/-/rollup-3.22.0.tgz"
|
||||||
integrity sha512-imsigcWor5Y/dC0rz2q0bBt9PabcL3TORry2hAa6O6BuMvY71bqHyfReAz5qyAqiQATD1m70qdntqBfBQjVWpQ==
|
integrity sha512-imsigcWor5Y/dC0rz2q0bBt9PabcL3TORry2hAa6O6BuMvY71bqHyfReAz5qyAqiQATD1m70qdntqBfBQjVWpQ==
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
@@ -495,7 +495,7 @@ safe-buffer@~5.2.0:
|
|||||||
|
|
||||||
source-map-js@^1.0.2:
|
source-map-js@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
|
||||||
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
||||||
|
|
||||||
streamsearch@^1.1.0:
|
streamsearch@^1.1.0:
|
||||||
@@ -538,12 +538,12 @@ tslib@^2.5.0:
|
|||||||
|
|
||||||
typescript@^5.0.4:
|
typescript@^5.0.4:
|
||||||
version "5.0.4"
|
version "5.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b"
|
resolved "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz"
|
||||||
integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==
|
integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==
|
||||||
|
|
||||||
ufo@^1.1.2:
|
ufo@^1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.1.2.tgz#d0d9e0fa09dece0c31ffd57bd363f030a35cfe76"
|
resolved "https://registry.npmjs.org/ufo/-/ufo-1.1.2.tgz"
|
||||||
integrity sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==
|
integrity sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==
|
||||||
|
|
||||||
undici@^5.21.0:
|
undici@^5.21.0:
|
||||||
@@ -560,7 +560,7 @@ util-deprecate@^1.0.1:
|
|||||||
|
|
||||||
vite-node@^0.31.1:
|
vite-node@^0.31.1:
|
||||||
version "0.31.1"
|
version "0.31.1"
|
||||||
resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-0.31.1.tgz#9fea18cbf9552ab262b969068249a8b8e7fb8b38"
|
resolved "https://registry.npmjs.org/vite-node/-/vite-node-0.31.1.tgz"
|
||||||
integrity sha512-BajE/IsNQ6JyizPzu9zRgHrBwczkAs0erQf/JRpgTIESpKvNj9/Gd0vxX905klLkb0I0SJVCKbdrl5c6FnqYKA==
|
integrity sha512-BajE/IsNQ6JyizPzu9zRgHrBwczkAs0erQf/JRpgTIESpKvNj9/Gd0vxX905klLkb0I0SJVCKbdrl5c6FnqYKA==
|
||||||
dependencies:
|
dependencies:
|
||||||
cac "^6.7.14"
|
cac "^6.7.14"
|
||||||
@@ -572,7 +572,7 @@ vite-node@^0.31.1:
|
|||||||
|
|
||||||
"vite@^3.0.0 || ^4.0.0":
|
"vite@^3.0.0 || ^4.0.0":
|
||||||
version "4.3.8"
|
version "4.3.8"
|
||||||
resolved "https://registry.yarnpkg.com/vite/-/vite-4.3.8.tgz#70cd6a294ab52d7fb8f37f5bc63d117dd19e9918"
|
resolved "https://registry.npmjs.org/vite/-/vite-4.3.8.tgz"
|
||||||
integrity sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==
|
integrity sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild "^0.17.5"
|
esbuild "^0.17.5"
|
||||||
|
|||||||
Reference in new issue
Block a user