sendou.ink/scripts/placements/index.ts
Kalle c2e43fb535
X Rank placements (#1325)
* Read in x rank placements script

* Xsearch initial

* XSearch initial

* XSearch with select

* Add badges

* XSearch player page initial

* Consider only one build by user for popular builds Closes #1312

* Revert "Side nav labels on hover (#1290)"

This reverts commit 6e839c6c2d.

* Added and fixed DAnish translations (#1315)

* Added Danish translations

Added Danish translations for the builds.json file.

Translations for the following variables have been added
stats.count.title # used the Danish word for "average" instead of "stats", as it makes more sense in Danish.
stats.ap.title
stats.percentage.title
stats.all
linkButton.abilityStats
linkButton.popularBuilds
noPopularBuilds

* Added Danish translations

Added Danish translations in the calander.json file

tag.desc.SZ
tag.desc.TW
tag.desc.S1
tag.desc.S2
tag.desc.SR
tag.desc.CARDS

* Added Danish translations

Added Danish translations in the common.json file

The following translations have been added
pages.vods
tag.name.SZ
tag.name.TW
tag.name.S1
tag.name.S2
tag.name.SR
tag.name.CARDS

* Added Danish translations in the faq.json file

Added the following Danish translations in the faq.json file

q7
a7

* Updated the DA/game-misc.json file

Added the names for the 3.0 maps.

* Added Danish translation for team.json

Added the following Danish translations for team.json file
- roles.MIDLINE

Fixed the following translation for the team.json file
- "roles.FRONTLINE": # fixed a typo

* Created a vods.json file for the Danish trans

* Fixed typo

Fixed the following translation in the Da\contributions.json file

"yaga" # fixed a Typo of "våben"

* Add Chinese Translation (#1314)

* Update contributions.json

* Update contributions.json

* Update faq.json

* Update user.json

* Create team.json

* Update common.json

* Update analyzer.json

* Prettier

* Prettier

* Prettier

* Update builds.json

* Update calendar.json

* Update common.json

* Update faq.json

* Update team.json

* Create vods.json

* Admin link player action

* Make PlacementTable rounded if only child

* Fix arrow disappeared

* Placements on user page initial

* Remove S2 site link

* Add badge

* Add feature to README

* Fix type error

* Different badge text if XP badge

* Add badge winners script

* Better user avatar + name wrapping for mobile

* Allow script to skip users

* Fix bad align when no weapons in weapon pool

* Add aliases to player name

* Add division icon to placements table

* Link to user page

* Link to xsearch on player details page

* Top 500 icons to user build page

* Working query but slow for weapons page

* Fix lint complaints

* Add cache to builds

* Remove useless SWR value

* Group months in xsearch

* Add xsearch to nav

* Add meta

* Remove TW for now

* Add splatoon3.ink as contributor

* Remove unneeded TODO

* Fix TODOs related to fetching monthYears

* Add FAQ question

* Leaderboards to nav

* Fix sploosh build stat pages returning 404

* Add badge

* Add article

* Patch 3.1

* Fix Prettier issue

* Add badge

* Add April SR gear

* Add badges

* Rename badge

* Add badge

* Add zh badge translation (#1322)

* Splatoon Competitive Guide article (#1316)

* Create splatoon-competitive-guide.md

* Update splatoon-competitive-guide.md

* Fix ToC Issues

* Update splatoon-competitive-guide.md

* Update splatoon-competitive-guide.md

* Update splatoon-competitive-guide.md

* Corrections

* Formatting

---------

Co-authored-by: Kalle <38327916+Sendouc@users.noreply.github.com>

* Fix typos

* Rename table and adjust columns

* Make cache ttl 0 in dev

* Make placements container a bit nicer for mobile

* Rename leftover xxx

* Placements script allow passing number as arg

* Skip leaderboards for now

* Add translations

* Rename placements folder to top-search

* Add placements to seed

* Add E2E tests

* Read in x rank placements script

* Xsearch initial

* XSearch initial

* XSearch with select

* XSearch player page initial

* Admin link player action

* Make PlacementTable rounded if only child

* Fix arrow disappeared

* Placements on user page initial

* Fix bad align when no weapons in weapon pool

* Add aliases to player name

* Add division icon to placements table

* Link to user page

* Link to xsearch on player details page

* Top 500 icons to user build page

* Working query but slow for weapons page

* Fix lint complaints

* Add cache to builds

* Remove useless SWR value

* Group months in xsearch

* Add xsearch to nav

* Add meta

* Remove TW for now

* Add splatoon3.ink as contributor

* Remove unneeded TODO

* Fix TODOs related to fetching monthYears

* Add FAQ question

* Leaderboards to nav

* Fix sploosh build stat pages returning 404

* Rename table and adjust columns

* Make cache ttl 0 in dev

* Make placements container a bit nicer for mobile

* Rename leftover xxx

* Placements script allow passing number as arg

* Skip leaderboards for now

* Add translations

* Rename placements folder to top-search

* Add placements to seed

* Add E2E tests

* Rename url variable and unify

* Tweaks

---------

Co-authored-by: Frederik <112972665+FrederikFraJylland@users.noreply.github.com>
Co-authored-by: Gell <61431488+gellneko@users.noreply.github.com>
Co-authored-by: Zen <99558412+zenpk@users.noreply.github.com>
Co-authored-by: Teddi <83455454+teddinotteddy@users.noreply.github.com>
2023-04-07 21:02:18 +03:00

183 lines
4.4 KiB
TypeScript

/* eslint-disable no-console */
import "dotenv/config";
import invariant from "tiny-invariant";
import { sql } from "~/db/sql";
import type { XRankPlacement } from "~/db/types";
import { type MainWeaponId, mainWeaponIds } from "~/modules/in-game-lists";
import { xRankSchema } from "./schemas";
const rawJsonNumber = process.argv[2]?.trim();
invariant(rawJsonNumber, "jsonNumber is required (argument 1)");
const jsonNumber = Number(rawJsonNumber);
invariant(
Number.isInteger(jsonNumber),
"jsonNumber must be an integer (argument 1)"
);
type Placements = Array<
Omit<XRankPlacement, "playerId" | "id"> & { playerSplId: string }
>;
const modes = ["splatzones", "towercontrol", "rainmaker", "clamblitz"] as const;
const modeToShort = {
splatzones: "SZ",
towercontrol: "TC",
rainmaker: "RM",
clamblitz: "CB",
} as const;
const regions = ["a", "p"] as const;
void main();
async function main() {
const placements: Placements = [];
for (const mode of modes) {
for (const region of regions) {
for (const includeWeapon of [false]) {
placements.push(
...(await processJson({
includeWeapon,
mode,
region,
number: jsonNumber,
}))
);
}
}
}
addPlacements(placements);
console.log(`done reading in ${placements.length} placements`);
}
async function processJson(args: {
mode: (typeof modes)[number];
region: (typeof regions)[number];
includeWeapon: boolean;
number: number;
}) {
const result: Placements = [];
const url = `https://splatoon3.ink/data/xrank/xrank.detail.${args.region}-${
args.number
}.${args.mode}${args.includeWeapon ? ".weapons" : ""}.json`;
console.log(`reading in ${url}...`);
const json = await fetch(url).then((res) => res.json());
const validated = xRankSchema.parse(json);
const array =
validated.data.node.xRankingAr ??
validated.data.node.xRankingCl ??
validated.data.node.xRankingLf ??
validated.data.node.xRankingGl;
invariant(array, "array is null");
for (const { node: placement } of array.edges) {
const weaponId = Number(atob(placement.weapon.id).replace("Weapon-", ""));
if (!mainWeaponIds.includes(weaponId as MainWeaponId)) {
throw new Error(`Invalid weapon ID: ${weaponId}`);
}
const { month, year } = resolveMonthYear(args.number);
result.push({
name: placement.name,
badges: placement.nameplate.badges
.map((badge) => atob(badge.id).replace("Badge-", ""))
.join(","),
bannerSplId: Number(
atob(placement.nameplate.background.id).replace(
"NameplateBackground-",
""
)
),
nameDiscriminator: placement.nameId,
power: placement.xPower,
rank: placement.rank,
region: args.region === "p" ? "JPN" : "WEST",
title: placement.byname,
weaponSplId: weaponId as MainWeaponId,
month,
year,
mode: modeToShort[args.mode],
playerSplId: parsePlayerId(placement.id),
});
}
return result;
}
function parsePlayerId(encoded: string) {
const parts = atob(encoded).split("-");
const last = parts[parts.length - 1];
invariant(last, "last is null");
return last;
}
function resolveMonthYear(number: number) {
const start = new Date("2023-03-15");
// 2 is the first X Rank month
// 3 is the length of x rank season
const monthsToAdd = (number - 2) * 3;
start.setMonth(start.getMonth() + monthsToAdd);
return {
month: start.getMonth() + 1,
year: start.getFullYear(),
};
}
const addPlayerStm = sql.prepare(/* sql */ `
insert into "SplatoonPlayer" ("splId")
values (@splId)
on conflict ("splId") do nothing
`);
const addPlacementStm = sql.prepare(/* sql */ `
insert into "XRankPlacement" (
"weaponSplId",
"name",
"nameDiscriminator",
"power",
"rank",
"title",
"badges",
"bannerSplId",
"playerId",
"month",
"year",
"region",
"mode"
)
values (
@weaponSplId,
@name,
@nameDiscriminator,
@power,
@rank,
@title,
@badges,
@bannerSplId,
(select "id" from "SplatoonPlayer" where "splId" = @playerSplId),
@month,
@year,
@region,
@mode
)
`);
function addPlacements(placements: Placements) {
sql.transaction(() => {
for (const placement of placements) {
addPlayerStm.run({ splId: placement.playerSplId });
addPlacementStm.run(placement);
}
})();
}