feat: add sdvx PUC tierlists (#1375)

* add sdvx PUC tierlists

* address review comments
This commit is contained in:
Aaron
2025-10-22 21:58:49 +01:00
committed by GitHub
parent 8f78ef1c9b
commit e6fd4c21ed
4 changed files with 14526 additions and 2421 deletions
+13 -1
View File
@@ -2,7 +2,7 @@ import { NumericSOV } from "util/sorts";
import { ChangeOpacity } from "util/color-opacity";
import { FormatMillions } from "util/misc";
import { GPTClientImplementation } from "lib/types";
import { COLOUR_SET, GPTStrings, SDVX_GRADES } from "tachi-common";
import { COLOUR_SET, GPTStrings, SDVX_GRADES, SDVX_LAMPS } from "tachi-common";
import MillionsScoreCell from "components/tables/cells/MillionsScoreCell";
import SDVXJudgementCell from "components/tables/cells/SDVXJudgementCell";
import SDVXLampCell from "components/tables/cells/SDVXLampCell";
@@ -162,6 +162,18 @@ export const SDVX_IMPL: GPTClientImplementation<"sdvx:Single"> = {
(c) => c.data.clearTier?.individualDifference,
(s) => [s.scoreData.lamp, s.scoreData.lamp !== "FAILED"]
),
CreateRatingSys(
"PUC Tierlist",
"Tierlist ratings for PUC lamp",
"lamp",
(c) => c.data.pucTier?.value,
(c) => c.data.pucTier?.text,
(c) => c.data.pucTier?.individualDifference,
(s) => [
s.scoreData.lamp,
s.scoreData.enumIndexes.lamp >= SDVX_LAMPS.PERFECT_ULTIMATE_CHAIN,
]
),
CreateRatingSys(
"S Tierlist",
"Tierlist ratings for S grade",
+1
View File
@@ -187,6 +187,7 @@ export const SDVX_SINGLE_CONF = {
chartData: z.strictObject({
inGameID: zodNonNegativeInt,
clearTier: zodTierlistData,
pucTier: zodTierlistData,
sTier: zodTierlistData,
}),
File diff suppressed because it is too large Load Diff
+123 -21
View File
@@ -8,9 +8,72 @@ import * as cheerio from "cheerio";
type SDVXChart = ChartDocument<"sdvx:Single">;
type SDVXSong = SongDocument<"sdvx">;
// Internal data for PUC tierlists are inconsistent
const MANUAL_PUC_TIERS: { [level: number]: { [tier: string]: string } } = {
16: {
0: "16.?",
1: "16.0",
2: "16.1",
3: "16.2",
4: "16.3",
5: "16.4",
6: "16.5",
7: "16.6",
8: "16.7",
9: "16.8",
10: "16.9",
11: "16.999",
12: "16.?",
},
17: {
10: "18.0",
},
19: {
0: "19.13",
1: "19.12",
2: "19.11",
3: "19.10",
4: "19.9",
5: "19.8",
6: "19.7",
7: "19.6",
8: "19.5",
9: "19.4",
10: "19.3",
11: "19.2",
12: "19.1",
13: "19.0",
14: "19.?",
},
20: {
0: "20.7",
1: "20.6",
2: "20.5",
3: "20.4",
4: "20.3",
5: "20.2",
6: "20.1",
7: "20.0",
8: "20.?",
},
};
// Used for tierlist value sorting
const MANUAL_PUC_VALUES: { [tierText: string]: number } = {
// ".?" values indicate individual difference and should appear at the bottom of their tierlists
"16.?": 15.9,
"19.?": 18.9,
"20.?": 19.9,
// To avoid these tiers getting grouped with 19.1
"19.10": 20.0,
19.11: 20.1,
19.12: 20.2,
19.13: 20.3,
};
// Tier 0+ and Tier 0- for the Lvl 19/20 tierlist are internally named -1 and 0
// respectively, so map them back to the display names
const MANUAL_TIERS: { [level: number]: { [tier: string]: string } } = {
const MANUAL_S_TIERS: { [level: number]: { [tier: string]: string } } = {
19: {
"-1": "0+",
0: "0-",
@@ -21,8 +84,14 @@ function normalizeStr(s: string) {
return s.toLowerCase().replace(/ /g, "");
}
async function scrape(charts: SDVXChart[], songs: SDVXSong[], level: number) {
const html = await (await fetch(`https://sdvx.maya2silence.com/table/${level}`, {})).text();
async function scrape(
url: string,
charts: SDVXChart[],
songs: SDVXSong[],
level: number,
tierlistType: "S_RANK" | "PUC_LAMP"
) {
const html = await fetch(url).then((r: Response) => r.text());
const $ = cheerio.load(html);
for (const tierBox of $(".tier_box")) {
@@ -33,7 +102,10 @@ async function scrape(charts: SDVXChart[], songs: SDVXSong[], level: number) {
continue;
}
const tierText = `Tier ${MANUAL_TIERS[level]?.[tier] ?? tier}`;
const tierText =
tierlistType === "S_RANK"
? `T${MANUAL_S_TIERS[level]?.[tier] ?? tier}`
: MANUAL_PUC_TIERS[level]?.[tier] ?? `${level}.${tier}`;
for (const chartData of $(tierBox).find(".chart_data")) {
const title = chartData.attribs["data-title"] || "";
@@ -59,27 +131,39 @@ async function scrape(charts: SDVXChart[], songs: SDVXSong[], level: number) {
continue;
}
// e.g. Level 17 Tier 9 -> 17 + 1 - 9 / 10 = 17.1
const value = level + 1 - parseInt(tier, 10) / 10;
// S_RANK value is derived since the S tierlist groups charts under Tier 1, Tier 2, etc.
// instead of 17.3, 17.4, etc. like the PUC tierlist
// Example: Level 17 Tier 9 -> 17 + 1 - 9 / 10 = 17.1
const value =
tierlistType === "S_RANK"
? level + 1 - parseInt(tier, 10) / 10
: MANUAL_PUC_VALUES[tierText] ?? Number(tierText);
const individualDifference = tierText.includes("?");
const tierInfoKey: keyof SDVXChart["data"] =
tierlistType === "S_RANK" ? "sTier" : "pucTier";
if (chart.data.sTier) {
if (chart.data.sTier.text !== tierText) {
if (chart.data[tierInfoKey]) {
const tierInfo = chart.data[tierInfoKey]!;
if (
tierInfo.text !== tierText ||
tierInfo.value !== value ||
tierInfo.individualDifference !== individualDifference
) {
console.log(
`[${chart.data.sTier.text} -> ${tierText}]: ${title} - ${artist} [${diff}]`
`[${chart.data[tierInfoKey]!.text} (${chart.data[tierInfoKey]!.value})
} -> ${tierText} (${value})]: ${title} - ${artist} [${diff}]`
);
chart.data.sTier.text = tierText;
chart.data.sTier.value = value;
}
} else {
console.log(`[${tierText}] ${title} - ${artist} [${diff}]`);
chart.data.sTier = {
individualDifference: false,
text: tierText,
value,
};
console.log(`[${tierText} (${value})] ${title} - ${artist} [${diff}]`);
}
chart.data[tierInfoKey] = {
individualDifference,
text: tierText,
value,
};
}
}
}
@@ -89,9 +173,27 @@ async function main() {
const songs: SDVXSong[] = ReadCollection("songs-sdvx.json");
for (const level of [17, 18, 19]) {
console.log(`\nScraping Level ${level}`);
console.log(`\n[S Rank] Scraping Level ${level}`);
await scrape(charts, songs, level);
await scrape(
`https://sdvx.maya2silence.com/table/${level}`,
charts,
songs,
level,
"S_RANK"
);
}
for (const level of [16, 17, 18, 19, 20]) {
console.log(`\n[PUC Lamp] Scraping Level ${level}`);
await scrape(
`https://sdvx.maya2silence.com/table/${level}p`,
charts,
songs,
level,
"PUC_LAMP"
);
}
WriteCollection("charts-sdvx.json", charts);