Remove non-compiling scripts

This commit is contained in:
zkldi
2022-02-09 16:09:50 +00:00
parent 30e034ef83
commit b907cbcaea
42 changed files with 3 additions and 773789 deletions
@@ -1,5 +0,0 @@
This folder is for porting documents from the old KamaitachiDB to the newer formats.
The scripts here should NOT be ran unless you know *exactly* what the hell you're doing.
And, even then - basically only I know, so. Please be careful.
@@ -1,79 +0,0 @@
// oh boy
/* eslint-disable @typescript-eslint/no-explicit-any */
import db from "external/mongo/db";
import { GoalDocument } from "tachi-common";
import CreateLogCtx from "../../src/common/logger";
import MigrateRecords from "./migrate";
const logger = CreateLogCtx(__filename);
function ConvertFn(c: any): GoalDocument | null {
let charts: GoalDocument["charts"];
if (c.directChartID) {
charts = {
type: "single",
data: c.directChartID,
};
} else if (c.directChartIDs) {
charts = {
type: "multi",
data: c.directChartIDs,
};
} else if (c.chartQuery) {
logger.warn(`Skipped goal ${c.title}, as it used cQuery.`);
return null;
} else {
logger.warn(`Any Goal ${c.goalID}, ${c.title}. Skipping.`);
return null;
}
const partialCriteria: Partial<GoalDocument["criteria"]> = {
mode: "single",
};
if (c.scoreQuery["scoreData¬lampIndex"]) {
partialCriteria.key = "scoreData.lampIndex";
} else if (c.scoreQuery["scoreData¬gradeIndex"]) {
partialCriteria.key = "scoreData.gradeIndex";
} else if (c.scoreQuery["scoreData¬score"]) {
partialCriteria.key = "scoreData.score";
} else if (c.scoreQuery["scoreData¬percent"]) {
partialCriteria.key = "scoreData.percent";
} else {
throw new Error(`Invalid goal ${c.goalID} ${c.title}.`);
}
const v = c.scoreQuery[partialCriteria.key.replace(/\./gu, "¬")];
const value = v ? v["~gte"] : undefined;
// would break for value == 0, but a goal would never be
// zero.
if (!value) {
throw new Error(`Invalid goal ${c.goalID} ${c.title}.`);
}
partialCriteria.value = value;
// @ts-expect-error ts cant resolve this union properly
const newGoalDoc: GoalDocument = {
game: c.game,
playtype: c.playtype,
title: c.title,
timeAdded: c.timeAdded,
goalID: c.goalID, // maybe
createdBy: c.createdBy,
charts,
criteria: partialCriteria as GoalDocument["criteria"],
};
return newGoalDoc;
}
(async () => {
await MigrateRecords(db.goals, "goals", ConvertFn);
process.exit(0);
})();
@@ -1,62 +0,0 @@
import CreateLogCtx from "lib/logger/logger";
import { ICollection } from "monk";
import { oldKTDB } from "./old-db";
const logger = CreateLogCtx(__filename);
export default async function MigrateRecords(
existingCollection: ICollection,
collectionName: string,
HandlerFN: (c: unknown) => unknown,
filter: Record<string, any> = {},
force = false
) {
const existingRecords = await existingCollection.count({});
logger.info(`Starting migration for ${collectionName}...`);
if (existingRecords > 0) {
if (force) {
logger.warn(
`Forcing migration of documents - appending to ${existingRecords} existing records.`
);
} else {
logger.error(`${existingRecords} documents already exist in db, terminating.`);
process.exit(1);
}
}
let i = 0;
const bucketSize = 10_000;
// eslint-disable-next-line no-constant-condition
while (true) {
// eslint-disable-next-line no-await-in-loop
const docs = await oldKTDB.get(collectionName).find(filter, { limit: bucketSize, skip: i });
logger.info(`Migrating ${i} - ${i + docs.length} documents.`);
if (docs.length === 0) {
break;
}
// eslint-disable-next-line no-await-in-loop
const newDocs = await Promise.all(docs.map(HandlerFN));
i += bucketSize;
const notNulls = newDocs.filter((e) => e !== null);
logger.info(`Success: ${notNulls.length}, Failures: ${newDocs.length - notNulls.length}.`);
// eslint-disable-next-line no-await-in-loop
await existingCollection.insert(notNulls);
logger.info(`Migrated ${docs.length} documents.`);
if (docs.length < bucketSize) {
break;
}
}
logger.info(`Done!`);
}
@@ -1,18 +0,0 @@
import CreateLogCtx from "lib/logger/logger";
import { Environment } from "lib/setup/config";
import monk from "monk";
const logger = CreateLogCtx(__filename);
logger.info(`Connecting to Old KTDB at ${Environment.mongoUrl}/kamaitachidb.`);
export const oldKTDB = monk(`${Environment.mongoUrl}/kamaitachidb`);
oldKTDB
.then(() => {
logger.info(`Done.`);
})
.catch((err) => {
logger.crit(`Fatal in connecting to old KT DB.`, { err });
process.exit(1);
});
@@ -1,153 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
import { CreateScoreID } from "lib/score-import/framework/score-importing/score-id";
import { GetGamePTConfig, ScoreDocument, StaticConfig } from "tachi-common";
import MigrateRecords from "../migrate";
import { oldKTDB } from "../old-db";
const logger = CreateLogCtx(__filename);
function ConditionalAssign(base: any, baseProp: string, other: any, otherProp: string) {
if (Object.prototype.hasOwnProperty.call(other, otherProp)) {
base[baseProp] = other[otherProp];
}
}
async function ConvertFn(c: any): Promise<ScoreDocument | null> {
if (!StaticConfig.allSupportedGames.includes(c.game)) {
logger.warn(`Ignored game ${c.game}`);
return null;
}
const game = c.game;
const playtype = c.scoreData.playtype;
const oldChartDoc = await oldKTDB.get("charts-bms").findOne({
chartID: c.chartID,
});
if (!oldChartDoc) {
logger.warn(`Cannot find oldChartDoc for ${c.chartID}`);
}
// @ts-expect-error implicit any is expected
const chartDoc = await db.charts[game].findOne({
"data.hashMD5": oldChartDoc.internals.hash,
});
if (!chartDoc) {
const oldSong = await oldKTDB.get("songs-bms").findOne({ id: c.songID });
logger.warn(`Cannot find ChartDoc for ${oldSong.title} ${oldChartDoc.level} ${playtype}`);
return null;
}
const gptConfig = GetGamePTConfig(game, chartDoc.playtype);
if (!gptConfig) {
logger.error(`Cannot find GPTConfig for ${game} ${chartDoc.playtype}?`);
throw new Error(`Screwed`);
}
const base: Omit<ScoreDocument, "scoreID"> = {
userID: c.userID,
songID: chartDoc.songID,
playtype: chartDoc.playtype,
chartID: chartDoc.chartID,
game: c.game,
timeAdded: c.timeAdded,
timeAchieved: Number.isNaN(c.timeAchieved) ? null : c.timeAchieved,
comment: c.comment ?? null,
highlight: c.highlight ?? false,
service: c.service,
importType: null,
// we'll just recalc calculated data instead of trying to update
calculatedData: {},
isPrimary: chartDoc.isPrimary,
scoreData: {
esd: c.scoreData.esd ?? null,
grade: c.scoreData.grade,
gradeIndex: gptConfig.grades.indexOf(c.scoreData.grade),
lamp: c.scoreData.lamp,
lampIndex: gptConfig.lamps.indexOf(c.scoreData.lamp),
percent: c.scoreData.percent,
score: c.scoreData.score,
judgements: c.scoreData.hitData,
hitMeta: {
fast: c.scoreData.hitMeta.fast,
slow: c.scoreData.hitMeta.slow,
maxCombo: c.scoreData.hitMeta.maxCombo,
bp: c.scoreData.hitMeta.bp,
gauge: c.scoreData.hitMeta.gauge,
epg: c.scoreData.hitMeta.epg,
egr: c.scoreData.hitMeta.egr,
egd: c.scoreData.hitMeta.egd,
ebd: c.scoreData.hitMeta.ebd,
epr: c.scoreData.hitMeta.epr,
lpg: c.scoreData.hitMeta.lpg,
lgr: c.scoreData.hitMeta.lgr,
lgd: c.scoreData.hitMeta.lgd,
lbd: c.scoreData.hitMeta.lbd,
lpr: c.scoreData.hitMeta.lpr,
},
},
scoreMeta: {
random: c.scoreMeta?.optionsRandom ?? null,
inputDevice: c.scoreMeta?.inputDevice ?? null,
},
};
// @ts-expect-error shut
if (base.scoreData.hitMeta.bp === -1 || Number.isNaN(base.scoreData.hitMeta.bp)) {
// @ts-expect-error shut
base.scoreData.hitMeta.bp = null;
}
// @ts-expect-error shut
if (Number(base.scoreData.hitMeta.bp) < 0) {
// @ts-expect-error shut
base.scoreData.hitMeta.bp = null;
}
// @ts-expect-error shut
if (base.scoreData.hitMeta.gauge === -1) {
// @ts-expect-error shut
base.scoreData.hitMeta.gauge = null;
}
// @ts-expect-error shut
delete base.scoreData.hitMeta.inputDevice;
const scoreID = CreateScoreID(base.userID, base, base.chartID);
const exists = await db.scores.findOne({ scoreID });
if (exists) {
logger.warn(`Skipping duplicate score ${base.chartID} ${base.userID}.`);
return null;
}
const score: ScoreDocument = {
...base,
scoreID,
};
await oldKTDB.get("score-id-lookup").insert({
old: c.scoreID,
new: scoreID,
});
return score;
}
export async function MigrateBMSScores() {
await MigrateRecords(db.scores, "scores", ConvertFn, { game: "bms" }, true);
}
if (require.main === module) {
(async () => {
await MigrateBMSScores();
process.exit(0);
})();
}
@@ -1,95 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
import { CreateScoreID } from "lib/score-import/framework/score-importing/score-id";
import { GetGameConfig, GetGamePTConfig, ScoreDocument } from "tachi-common";
import MigrateRecords from "../migrate";
import { oldKTDB } from "../old-db";
const logger = CreateLogCtx(__filename);
async function ConvertFn(c: any): Promise<ScoreDocument | null> {
const game = c.game;
const playtype = c.scoreData.playtype;
const gameConfig = GetGameConfig(game);
if (!gameConfig.validPlaytypes.includes(playtype)) {
logger.warn(`Ignored game pt ${game}, ${playtype}`);
throw new Error(`Ignored game pt ${game}, ${playtype}`);
}
const gptConfig = GetGamePTConfig(game, playtype);
if (!gptConfig) {
logger.error(`No gptconfig for ${game} ${playtype}?`);
throw new Error(`No gptconfig for ${game} ${playtype}?`);
}
// @ts-expect-error implicit any is expected
const chartDoc = await db.charts[game].findOne({
songID: c.songID,
difficulty: c.scoreData.difficulty,
playtype,
});
if (!chartDoc) {
logger.warn(`Cannot find ChartDoc for ${c.songID} ${c.scoreData.difficulty} ${playtype} `);
return null;
}
const base: Omit<ScoreDocument<"chunithm:Single">, "scoreID"> = {
userID: c.userID,
songID: chartDoc.songID,
playtype,
chartID: chartDoc.chartID,
game: c.game,
timeAdded: c.timeAdded,
timeAchieved: Number.isNaN(c.timeAchieved) ? null : c.timeAchieved,
comment: c.comment ?? null,
highlight: c.highlight ?? false,
service: c.service,
importType: null,
// we'll just recalc calculated data instead of trying to update
calculatedData: {},
isPrimary: chartDoc.isPrimary,
scoreData: {
esd: c.scoreData.esd ?? null,
grade: c.scoreData.grade,
gradeIndex: gptConfig.grades.indexOf(c.scoreData.grade),
lamp: c.scoreData.lamp,
lampIndex: gptConfig.lamps.indexOf(c.scoreData.lamp),
percent: c.scoreData.percent,
score: c.scoreData.score,
judgements: c.scoreData.hitData,
hitMeta: c.scoreData.hitMeta,
},
scoreMeta: {},
};
const scoreID = CreateScoreID(base.userID, base, base.chartID);
const exists = await db.scores.findOne({ scoreID });
if (exists) {
logger.warn(`Skipping duplicate score ${base.chartID} ${base.userID}.`);
return null;
}
const score: ScoreDocument = {
...base,
scoreID,
};
await oldKTDB.get("score-id-lookup").insert({
old: c.scoreID,
new: scoreID,
});
return score;
}
export async function MigrateCHUNITHMScores() {
await MigrateRecords(db.scores, "scores", ConvertFn, { game: "chunithm" }, true);
}
@@ -1,101 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
import { CreateScoreID } from "lib/score-import/framework/score-importing/score-id";
import { GetGamePTConfig, ScoreDocument, StaticConfig } from "tachi-common";
import MigrateRecords from "../migrate";
import { oldKTDB } from "../old-db";
const logger = CreateLogCtx(__filename);
async function ConvertFn(c: any): Promise<ScoreDocument | null> {
if (!StaticConfig.allSupportedGames.includes(c.game)) {
logger.warn(`Ignored game ${c.game}`);
return null;
}
const game = c.game;
// @ts-expect-error implicit any is expected
const chartDoc = await db.charts[game].findOne({
chartID: c.chartID,
});
if (!chartDoc) {
logger.warn(`Cannot find ChartDoc for ${c.songID} ${c.chartID} ${c.scoreData.difficulty}`);
return null;
}
const gptConfig = GetGamePTConfig(game, chartDoc.playtype);
if (!gptConfig) {
logger.error(`Cannot find GPTConfig for ${game} ${chartDoc.playtype}?`);
throw new Error(`Screwed`);
}
const base: Omit<ScoreDocument<"ddr:SP" | "ddr:DP">, "scoreID"> = {
userID: c.userID,
songID: chartDoc.songID,
playtype: chartDoc.playtype,
chartID: chartDoc.chartID,
game: c.game,
timeAdded: c.timeAdded,
timeAchieved: Number.isNaN(c.timeAchieved) ? null : c.timeAchieved,
comment: c.comment ?? null,
highlight: c.highlight ?? false,
service: c.service,
importType: null,
// we'll just recalc calculated data instead of trying to update
calculatedData: {},
isPrimary: chartDoc.isPrimary,
scoreData: {
esd: c.scoreData.esd ?? null,
grade: c.scoreData.grade,
gradeIndex: gptConfig.grades.indexOf(c.scoreData.grade),
lamp: c.scoreData.lamp,
lampIndex: gptConfig.lamps.indexOf(c.scoreData.lamp),
percent: c.scoreData.percent,
score: c.scoreData.score,
judgements: c.scoreData.hitData,
hitMeta: c.scoreData.hitMeta,
},
scoreMeta: {},
};
const scoreID = CreateScoreID(base.userID, base, base.chartID);
const exists = await db.scores.findOne({ scoreID });
if (exists) {
logger.warn(`Skipping duplicate score ${base.chartID} ${base.userID}.`);
return null;
}
const score: ScoreDocument = {
...base,
scoreID,
};
try {
await oldKTDB.get("score-id-lookup").insert({
old: c.scoreID,
new: scoreID,
});
} catch (err) {
// whoops
}
return score;
}
export async function MigrateDDRScores() {
await MigrateRecords(db.scores, "scores", ConvertFn, { game: "ddr" }, true);
}
if (require.main === module) {
(async () => {
await MigrateDDRScores();
process.exit(0);
})();
}
@@ -1,149 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
import { CreateScoreID } from "lib/score-import/framework/score-importing/score-id";
import { GetGameConfig, GetGamePTConfig, ScoreDocument } from "tachi-common";
import MigrateRecords from "../migrate";
import { oldKTDB } from "../old-db";
const logger = CreateLogCtx(__filename);
async function ConvertFn(c: any): Promise<ScoreDocument | null> {
const game = c.game;
const playtype = c.scoreData.playtype;
const gameConfig = GetGameConfig(game);
if (!gameConfig.validPlaytypes.includes(playtype)) {
logger.warn(`Ignored game pt ${game}, ${playtype}`);
throw new Error(`Ignored game pt ${game}, ${playtype}`);
}
const gptConfig = GetGamePTConfig(game, playtype);
if (!gptConfig) {
logger.error(`No gptconfig for ${game} ${playtype}?`);
throw new Error(`No gptconfig for ${game} ${playtype}?`);
}
if (c.songID === 1819) {
c.songID = 1121; // praludium has two songs in kt1 for some reason (tricoro 6)
// this overrides that
}
// @ts-expect-error implicit any is expected
const chartDoc = await db.charts[game].findOne({
songID: c.songID,
difficulty: c.scoreData.difficulty,
playtype,
});
if (!chartDoc) {
logger.warn(`Cannot find ChartDoc for ${c.songID} ${c.scoreData.difficulty} ${playtype} `);
return null;
}
const base: Omit<ScoreDocument<"iidx:SP" | "iidx:DP">, "scoreID"> = {
userID: c.userID,
songID: chartDoc.songID,
playtype,
chartID: chartDoc.chartID,
game: c.game,
timeAdded: c.timeAdded,
timeAchieved: Number.isNaN(c.timeAchieved) ? null : c.timeAchieved,
comment: c.comment ?? null,
highlight: c.highlight ?? false,
service: c.service,
importType: null,
// we'll just recalc calculated data instead of trying to update
calculatedData: {},
isPrimary: chartDoc.isPrimary,
scoreData: {
esd: c.scoreData.esd ?? null,
grade: c.scoreData.grade,
gradeIndex: gptConfig.grades.indexOf(c.scoreData.grade),
lamp: c.scoreData.lamp,
lampIndex: gptConfig.lamps.indexOf(c.scoreData.lamp),
percent: c.scoreData.percent,
score: c.scoreData.score,
judgements: c.scoreData.hitData,
hitMeta: c.scoreData.hitMeta,
},
scoreMeta: {
random: c.scoreMeta?.optionsRandom ?? null,
gauge: c.scoreMeta?.optionsGauge ?? null,
assist: c.scoreMeta?.optionsAssist ?? null,
range: c.scoreMeta?.optionsRange ?? null,
},
};
if (c.scoreMeta) {
if (base.playtype === "DP" && !Array.isArray(base.scoreMeta.random)) {
base.scoreMeta.random = null;
}
if (c.scoreData.hitMeta.gauge < 0) {
c.scoreData.hitMeta.gauge = null;
}
if (!Array.isArray(c.scoreData.hitMeta.gaugeHistory)) {
c.scoreData.hitMeta.gaugeHistory = null;
}
// @ts-expect-error asdf
if (base.scoreMeta.range === "") {
base.scoreMeta.range = "NONE";
}
if (c.scoreMeta.deadMeasure || c.scoreMeta.deadNote) {
base.scoreData.hitMeta.bp = null;
}
}
if (base.scoreData.hitMeta.bp === -1 || Number.isNaN(base.scoreData.hitMeta.bp)) {
base.scoreData.hitMeta.bp = null;
}
if ((base.scoreData.hitMeta.gauge ?? 0) > 200) {
base.scoreData.hitMeta.gauge = null;
}
if (base.scoreData.hitMeta.gaugeHistory) {
base.scoreData.hitMeta.gaugeHistory = base.scoreData.hitMeta.gaugeHistory.map((e) =>
(e ?? 0) > 200 ? null : e
);
}
const scoreID = CreateScoreID(base.userID, base, base.chartID);
const exists = await db.scores.findOne({ scoreID });
if (exists) {
logger.warn(`Skipping duplicate score ${base.chartID} ${base.userID}.`);
return null;
}
const score: ScoreDocument = {
...base,
scoreID,
};
await oldKTDB.get("score-id-lookup").insert({
old: c.scoreID,
new: scoreID,
});
return score;
}
export async function MigrateIIDXScores() {
await MigrateRecords(db.scores, "scores", ConvertFn, { game: "iidx" }, true);
}
if (require.main === module) {
(async () => {
await MigrateIIDXScores();
process.exit(0);
})();
}
@@ -1,33 +0,0 @@
import CreateLogCtx from "lib/logger/logger";
import { MigrateBMSScores } from "./bms";
import { MigrateCHUNITHMScores } from "./chunithm";
import { MigrateIIDXScores } from "./iidx";
import { MigrateMusecaScores } from "./museca";
import { MigrateSDVXScores } from "./sdvx";
const logger = CreateLogCtx(__filename);
(async () => {
logger.info(`Migrating IIDX Scores.`);
await MigrateIIDXScores();
logger.info(`Migrating BMS Scores.`);
await MigrateBMSScores();
logger.info(`Migrating MUSECA Scores.`);
await MigrateMusecaScores();
logger.info(`Migrating SDVX Scores.`);
await MigrateSDVXScores();
logger.info(`Migrating CHUNITHM Scores.`);
await MigrateCHUNITHMScores();
logger.info("Done.");
process.exit(0);
})();
@@ -1,101 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
import { CreateScoreID } from "lib/score-import/framework/score-importing/score-id";
import { GetGamePTConfig, ScoreDocument, StaticConfig } from "tachi-common";
import MigrateRecords from "../migrate";
import { oldKTDB } from "../old-db";
const logger = CreateLogCtx(__filename);
async function ConvertFn(c: any): Promise<ScoreDocument | null> {
if (!StaticConfig.allSupportedGames.includes(c.game)) {
logger.warn(`Ignored game ${c.game}`);
return null;
}
const game = c.game;
// @ts-expect-error implicit any is expected
const chartDoc = await db.charts[game].findOne({
chartID: c.chartID,
});
if (!chartDoc) {
logger.warn(`Cannot find ChartDoc for ${c.songID} ${c.chartID} ${c.scoreData.difficulty}`);
return null;
}
const gptConfig = GetGamePTConfig(game, chartDoc.playtype);
if (!gptConfig) {
logger.error(`Cannot find GPTConfig for ${game} ${chartDoc.playtype}?`);
throw new Error(`Screwed`);
}
const base: Omit<ScoreDocument<"museca:Single">, "scoreID"> = {
userID: c.userID,
songID: chartDoc.songID,
playtype: chartDoc.playtype,
chartID: chartDoc.chartID,
game: c.game,
timeAdded: c.timeAdded,
timeAchieved: Number.isNaN(c.timeAchieved) ? null : c.timeAchieved,
comment: c.comment ?? null,
highlight: c.highlight ?? false,
service: c.service,
importType: null,
// we'll just recalc calculated data instead of trying to update
calculatedData: {},
isPrimary: chartDoc.isPrimary,
scoreData: {
esd: c.scoreData.esd ?? null,
grade: c.scoreData.grade,
gradeIndex: gptConfig.grades.indexOf(c.scoreData.grade),
lamp: c.scoreData.lamp,
lampIndex: gptConfig.lamps.indexOf(c.scoreData.lamp),
percent: c.scoreData.percent,
score: c.scoreData.score,
judgements: c.scoreData.hitData,
hitMeta: c.scoreData.hitMeta,
},
scoreMeta: {},
};
const scoreID = CreateScoreID(base.userID, base, base.chartID);
const exists = await db.scores.findOne({ scoreID });
if (exists) {
logger.warn(`Skipping duplicate score ${base.chartID} ${base.userID}.`);
return null;
}
const score: ScoreDocument = {
...base,
scoreID,
};
try {
await oldKTDB.get("score-id-lookup").insert({
old: c.scoreID,
new: scoreID,
});
} catch (err) {
// whoops
}
return score;
}
export async function MigrateMusecaScores() {
await MigrateRecords(db.scores, "scores", ConvertFn, { game: "museca" }, true);
}
if (require.main === module) {
(async () => {
await MigrateMusecaScores();
process.exit(0);
})();
}
@@ -1,174 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
import { CreateScoreID } from "lib/score-import/framework/score-importing/score-id";
import { GetGameConfig, GetGamePTConfig, ScoreDocument, StaticConfig } from "tachi-common";
import MigrateRecords from "../migrate";
const logger = CreateLogCtx(__filename);
function ConditionalAssign(base: any, baseProp: string, other: any, otherProp: string) {
if (Object.prototype.hasOwnProperty.call(other, otherProp)) {
base[baseProp] = other[otherProp];
}
}
async function ConvertFn(c: any): Promise<ScoreDocument | null> {
if (!StaticConfig.allSupportedGames.includes(c.game)) {
logger.warn(`Ignored game ${c.game}`);
return null;
}
const game = c.game;
const playtype = c.scoreData.playtype;
if (["popn", "jubeat", "gitadora", "usc"].includes(c.game)) {
return null;
}
const gameConfig = GetGameConfig(game);
if (!gameConfig.validPlaytypes.includes(playtype)) {
logger.warn(`Ignored game pt ${game}, ${playtype}`);
throw new Error(`Ignored game pt ${game}, ${playtype}`);
}
const gptConfig = GetGamePTConfig(game, playtype);
if (!gptConfig) {
logger.error(`No gptconfig for ${game} ${playtype}?`);
throw new Error(`No gptconfig for ${game} ${playtype}?`);
}
if (game === "iidx" && c.songID === 1819) {
c.songID = 1121; // praludium has two songs in kt1 for some reason (tricoro 6)
// this overrides that
}
// @ts-expect-error implicit any is expected
const chartDoc = await db.charts[game].findOne({
songID: c.songID,
difficulty: c.scoreData.difficulty,
playtype,
});
if (!chartDoc) {
logger.warn(`Cannot find ChartDoc for ${c.songID} ${c.scoreData.difficulty} ${playtype} `);
return null;
}
const base: Omit<ScoreDocument, "scoreID"> = {
userID: c.userID,
songID: chartDoc.songID,
playtype,
chartID: chartDoc.chartID,
game: c.game,
timeAdded: c.timeAdded,
timeAchieved: Number.isNaN(c.timeAchieved) ? null : c.timeAchieved,
comment: c.comment ?? null,
highlight: c.highlight ?? false,
service: c.service,
importType: null,
// we'll just recalc calculated data instead of trying to update
calculatedData: {},
isPrimary: chartDoc.isPrimary,
scoreData: {
esd: c.scoreData.esd ?? null,
grade: c.scoreData.grade,
gradeIndex: gptConfig.grades.indexOf(c.scoreData.grade),
lamp: c.scoreData.lamp,
lampIndex: gptConfig.lamps.indexOf(c.scoreData.lamp),
percent: c.scoreData.percent,
score: c.scoreData.score,
judgements: c.scoreData.hitData,
hitMeta: c.scoreData.hitMeta,
},
scoreMeta: {},
};
if (c.scoreMeta) {
if (base.game === "iidx") {
ConditionalAssign(base.scoreMeta, "random", c.scoreMeta, "optionsRandom");
ConditionalAssign(base.scoreMeta, "gauge", c.scoreMeta, "optionsGauge");
ConditionalAssign(base.scoreMeta, "assist", c.scoreMeta, "optionsAssist");
ConditionalAssign(base.scoreMeta, "range", c.scoreMeta, "optionsRange");
ConditionalAssign(base.scoreMeta, "pacemaker", c.scoreMeta, "pacemaker");
ConditionalAssign(base.scoreMeta, "pacemakerName", c.scoreMeta, "pacemakerName");
ConditionalAssign(base.scoreMeta, "pacemakerTarget", c.scoreMeta, "pacemakerTarget");
// @ts-expect-error this game is iidx
if (base.playtype === "DP" && !Array.isArray(base.scoreMeta.random)) {
// @ts-expect-error this game is iidx
base.scoreMeta.random = null;
}
// @ts-expect-error asdf
if (base.scoreMeta.range === "") {
// @ts-expect-error asdf
base.scoreMeta.range = "NONE";
}
} else if (base.game === "bms") {
ConditionalAssign(base.scoreMeta, "random", c.scoreMeta, "optionsRandom");
ConditionalAssign(base.scoreMeta, "inputDevice", c.scoreData.hitMeta, "inputDevice");
}
}
// @ts-expect-error shut
if (base.scoreData.hitMeta.bp === -1 || Number.isNaN(base.scoreData.hitMeta.bp)) {
// @ts-expect-error shut
base.scoreData.hitMeta.bp = null;
}
if (base.game === "iidx") {
// @ts-expect-error nope
if (base.scoreData.hitMeta.gauge > 200) {
// @ts-expect-error nope
base.scoreData.hitMeta.gauge = null;
}
// @ts-expect-error nope
if (base.scoreData.hitMeta.gaugeHistory) {
// @ts-expect-error nope
base.scoreData.hitMeta.gaugeHistory = base.scoreData.hitMeta.gaugeHistory.map((e) =>
e > 200 ? null : e
);
}
} else if (base.game === "bms") {
// @ts-expect-error shut
if (base.scoreData.hitMeta.gauge === -1) {
// @ts-expect-error shut
base.scoreData.hitMeta.gauge = null;
}
// @ts-expect-error shut
delete base.scoreData.hitMeta.inputDevice;
} else if (base.game === "sdvx" || base.game === "usc") {
ConditionalAssign(base.scoreData.judgements, "miss", base.scoreData.judgements, "error");
//@ts-expect-error yea
delete base.scoreData.judgements.error;
} else if (base.game === "chunithm") {
if (base.scoreData.percent === 101) {
base.scoreData.grade = "SSS";
}
}
if (base.service === "mm") {
base.service = "maimagic";
}
const scoreID = CreateScoreID(base.userID, base, base.chartID);
const score: ScoreDocument = {
...base,
scoreID,
};
return score;
}
(async () => {
await MigrateRecords(db.scores, "scores", ConvertFn);
process.exit(0);
})();
@@ -1,114 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
import { CreateScoreID } from "lib/score-import/framework/score-importing/score-id";
import { GetGamePTConfig, ScoreDocument, StaticConfig } from "tachi-common";
import MigrateRecords from "../migrate";
import { oldKTDB } from "../old-db";
const logger = CreateLogCtx(__filename);
async function ConvertFn(c: any): Promise<ScoreDocument | null> {
if (!StaticConfig.allSupportedGames.includes(c.game)) {
logger.warn(`Ignored game ${c.game}`);
return null;
}
const game = c.game;
// @ts-expect-error implicit any is expected
const chartDoc = await db.charts[game].findOne({
chartID: c.chartID,
});
if (!chartDoc) {
logger.warn(`Cannot find ChartDoc for ${c.songID} ${c.chartID} ${c.scoreData.difficulty}`);
return null;
}
const gptConfig = GetGamePTConfig(game, chartDoc.playtype);
if (!gptConfig) {
logger.error(`Cannot find GPTConfig for ${game} ${chartDoc.playtype}?`);
throw new Error(`Screwed`);
}
const base: Omit<ScoreDocument<"sdvx:Single">, "scoreID"> = {
userID: c.userID,
songID: chartDoc.songID,
playtype: chartDoc.playtype,
chartID: chartDoc.chartID,
game: c.game,
timeAdded: c.timeAdded,
timeAchieved: Number.isNaN(c.timeAchieved) ? null : c.timeAchieved,
comment: c.comment ?? null,
highlight: c.highlight ?? false,
service: c.service,
importType: null,
// we'll just recalc calculated data instead of trying to update
calculatedData: {},
isPrimary: chartDoc.isPrimary,
scoreData: {
esd: c.scoreData.esd ?? null,
grade: c.scoreData.grade,
gradeIndex: gptConfig.grades.indexOf(c.scoreData.grade),
lamp: c.scoreData.lamp,
lampIndex: gptConfig.lamps.indexOf(c.scoreData.lamp),
percent: c.scoreData.percent,
score: c.scoreData.score,
judgements: c.scoreData.hitData,
hitMeta: {
fast: c.scoreData.hitMeta.fast,
slow: c.scoreData.hitMeta.slow,
maxCombo: c.scoreData.hitMeta.maxCombo,
gauge: c.scoreData.hitMeta.gauge,
},
},
scoreMeta: {
inSkillAnalyser: null,
},
};
if (c.scoreData.hitData.error !== undefined) {
base.scoreData.judgements.miss = c.scoreData.hitData.error;
// @ts-expect-error yeah we know
delete base.scoreData.judgements.error;
}
const scoreID = CreateScoreID(base.userID, base, base.chartID);
const exists = await db.scores.findOne({ scoreID });
if (exists) {
logger.warn(`Skipping duplicate score ${base.chartID} ${base.userID}.`);
return null;
}
const score: ScoreDocument = {
...base,
scoreID,
};
try {
await oldKTDB.get("score-id-lookup").insert({
old: c.scoreID,
new: scoreID,
});
} catch (err) {
// lol
}
return score;
}
export async function MigrateSDVXScores() {
await MigrateRecords(db.scores, "scores", ConvertFn, { game: "sdvx" }, true);
}
if (require.main === module) {
(async () => {
await MigrateSDVXScores();
process.exit(0);
})();
}
@@ -1,109 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
import { CreateSessionID } from "lib/score-import/framework/sessions/sessions";
import { GetGameConfig, integer, SessionDocument, SessionScoreInfo } from "tachi-common";
import { allSupportedGames } from "tachi-common/js/config/static-config";
import MigrateRecords from "./migrate";
import { oldKTDB } from "./old-db";
const logger = CreateLogCtx(__filename);
interface LegacySessionScoreFormat {
pbInfo: {
isGeneralPB: boolean;
isGradePB: boolean;
isLampPB: boolean;
isNewScore: boolean;
lampDelta: integer;
percentDelta: number;
gradeDelta: integer;
scoreDelta: number;
};
scoreID: string;
}
async function ConvertScoreToScoreInfo(
score: LegacySessionScoreFormat
): Promise<SessionScoreInfo | null> {
const scoreIDs = await oldKTDB.get("score-id-lookup").findOne({
old: score.scoreID,
});
if (!scoreIDs) {
logger.verbose(`No score for ${score.scoreID}? Skipping.`);
return null;
}
logger.verbose(`Found score for ${score.scoreID}.`);
if (score.pbInfo.isNewScore) {
return {
isNewScore: true,
scoreID: scoreIDs.new,
};
}
if (score.pbInfo.scoreDelta === null) {
return null;
}
return {
scoreID: scoreIDs.new,
isNewScore: false,
gradeDelta: score.pbInfo.gradeDelta,
lampDelta: score.pbInfo.lampDelta,
percentDelta: score.pbInfo.percentDelta,
scoreDelta: score.pbInfo.scoreDelta,
};
}
async function ConvertFn(c: any): Promise<SessionDocument | null> {
if (!allSupportedGames.includes(c.game)) {
return null;
}
const gameConfig = GetGameConfig(c.game);
if (!gameConfig.validPlaytypes.includes(c.playtype)) {
return null;
}
const scores = [];
for (const sc of c.scores) {
// eslint-disable-next-line no-await-in-loop
const conv = await ConvertScoreToScoreInfo(sc);
if (conv === null) {
continue;
}
scores.push(conv);
}
const sessionDocument: SessionDocument = {
name: c.name,
desc: c.desc,
timeStarted: c.timeStarted,
timeEnded: c.timeEnded,
timeInserted: c.timestamp,
game: c.game,
playtype: c.playtype,
highlight: !!c.highlight,
sessionID: CreateSessionID(),
views: 0,
userID: c.userID,
calculatedData: {},
scoreInfo: scores,
importType: null,
};
return sessionDocument;
}
(async () => {
await MigrateRecords(db.sessions, "sessions", ConvertFn, {}, true);
process.exit(0);
})();
@@ -1,26 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
import { UserGoalDocument } from "tachi-common";
import MigrateRecords from "./migrate";
const logger = CreateLogCtx(__filename);
async function ConvertFn(c: any): Promise<UserGoalDocument | null> {
// const newUG: UserGoalDocument = {};
const relatedGoal = await db.goals.findOne({ goalID: c.goalID });
if (!relatedGoal) {
return null;
}
return c;
}
(async () => {
await MigrateRecords(db["user-goals"], "user-goals", ConvertFn);
process.exit(0);
})();
@@ -1,19 +0,0 @@
import db from "external/mongo/db";
import { PrivateUserInfoDocument } from "tachi-common";
import MigrateRecords from "./migrate";
function ConvertFn(c: any): PrivateUserInfoDocument {
const privateUserInfoDoc: PrivateUserInfoDocument = {
userID: c.id,
password: c.password,
email: c.email,
};
return privateUserInfoDoc;
}
(async () => {
await MigrateRecords(db["user-private-information"], "users", ConvertFn);
process.exit(0);
})();
@@ -1,15 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import db from "external/mongo/db";
import { DEFAULT_USER_SETTINGS } from "server/router/api/v1/auth/auth";
import MigrateRecords from "./migrate";
function ConvertFn(c: any) {
return { userID: c.id, preferences: DEFAULT_USER_SETTINGS };
}
(async () => {
await MigrateRecords(db["user-settings"], "users", ConvertFn);
process.exit(0);
})();
@@ -1,36 +0,0 @@
import db from "external/mongo/db";
import { PublicUserDocument, UserAuthLevels } from "tachi-common";
import MigrateRecords from "./migrate";
function ConvertFn(c: any): PublicUserDocument {
const newUserDoc: PublicUserDocument = {
username: c.username,
usernameLowercase: c.username.toLowerCase(),
about: c.about,
clan: c.clan,
customBannerLocation: null,
customPfpLocation: null,
id: c.id,
lastSeen: c.lastSeen,
socialMedia: {
discord: c.socialmedia.discord || null,
twitter: c.socialmedia.twitter || null,
youtube: c.socialmedia.youtube || null,
twitch: c.socialmedia.twitch || null,
github: c.socialmedia.github || null,
steam: c.socialmedia.steam || null,
},
joinDate: 0,
authLevel: UserAuthLevels.USER,
status: null,
badges: ["beta"],
};
return newUserDoc;
}
(async () => {
await MigrateRecords(db.users, "users", ConvertFn);
process.exit(0);
})();
-213
View File
@@ -1,213 +0,0 @@
/* eslint-disable no-await-in-loop */
import { Command } from "commander";
import db from "external/mongo/db";
import fs from "fs";
import CreateLogCtx from "lib/logger/logger";
import { ServerConfig } from "lib/setup/config";
import path from "path";
import fetch from "utils/fetch";
import { FindChartWithPTDFVersion, FindSDVXChartOnDFVersion } from "utils/queries/charts";
import { FindSongOnTitle } from "utils/queries/songs";
const logger = CreateLogCtx(__filename);
const program = new Command();
program.option("-u, --url <URL>", "The base URL to sync from.");
program.option("-b, --bearer <token>", "The authorization bearer token to use.");
program.option("-g, --game <game>", "Should be exactly iidx or sdvx.");
program.option("-c, --cache", "Use a local cached JSON file, instead of requesting from the api.");
program.parse(process.argv);
const options = program.opts();
if (!options.game) {
throw new Error(`Expected -g or --game parameter.`);
}
if (!["iidx", "sdvx"].includes(options.game)) {
throw new Error(`Expected provided game to be either iidx or sdvx.`);
}
async function GetSongs() {
const allSongs = [];
let url =
options.game === "iidx"
? `${ServerConfig.ARC_API_URL}/api/v1/iidx/28/music/`
: `${ServerConfig.ARC_API_URL}/api/v1/sdvx/5/music/`;
let moreData = true;
while (moreData) {
// eslint-disable-next-line no-await-in-loop
const songs = await fetch(url, {
headers: {
Authorization: `Bearer ${options.bearer}`,
},
}).then((r) => r.json());
if (songs._links._next) {
url = songs._links._next;
} else {
moreData = false;
}
allSongs.push(...songs._items);
}
return allSongs;
}
async function GetCharts() {
const songs = await GetSongs();
const allCharts: any[] = [];
const failed: any[] = [];
async function DoStuff(song: any) {
const url =
options.game === "iidx"
? `${ServerConfig.ARC_API_URL}/api/v1/iidx/28/charts/?music_id=${song._id}&omnimix=true`
: `${ServerConfig.ARC_API_URL}/api/v1/sdvx/5/charts/?music_id=${song._id}`;
try {
logger.info(`Starting Request ${url}.`);
// eslint-disable-next-line no-await-in-loop
const charts = await fetch(url, {
headers: {
Authorization: `Bearer ${options.bearer}`,
},
}).then((r) => r.json());
logger.info(`Parsed: ${charts._related.music[0].title}`);
allCharts.push(charts);
} catch (err) {
logger.error(err.message, { song, err });
failed.push(err);
}
}
for (const song of songs) {
await DoStuff(song);
}
// fast, but ARCs server cant keep up.
// const promises = songs.map((s: any) => DoStuff(s));
// await Promise.all(promises);
logger.info(failed);
logger.info("Retrieved charts.");
return allCharts;
}
const cacheLoc = path.join(__dirname, "cache.json");
async function MergeIDs() {
let charts;
if (options.cache) {
logger.info(`--cache provided, reading cache.`);
try {
charts = JSON.parse(fs.readFileSync(cacheLoc, "utf-8"));
} catch (err) {
throw new Error(`No cache, cannot use --cache!`);
}
} else {
logger.info(`Reading from arc.`);
charts = await GetCharts();
}
fs.writeFileSync(cacheLoc, JSON.stringify(charts));
for (const chartData of charts) {
const songTitle = chartData._related.music[0].title;
// eslint-disable-next-line no-await-in-loop
const song = await FindSongOnTitle(options.game, songTitle);
if (!song) {
logger.error(`Could not resolve song ${songTitle}?`);
continue;
}
for (const chart of chartData._items) {
if (chart.rating === 0) {
continue;
}
const playtype: "SP" | "DP" | "Single" =
options.game === "iidx" ? (chart.play_style === "DOUBLE" ? "DP" : "SP") : "Single";
let difficulty = chart.difficulty === "BLACK" ? "LEGGENDARIA" : chart.difficulty;
const version = options.game === "iidx" ? "28-omni" : "vivid";
// yeah this fails for wacky playtype mismatches -- i don't care.
if (
["ミッドナイト堕天使", "Y&Co. is dead or alive", "State Of The Art"].includes(
songTitle
) &&
difficulty === "LEGGENDARIA"
) {
difficulty = "ANOTHER";
}
let tachiChart;
if (options.game === "sdvx") {
tachiChart = await FindSDVXChartOnDFVersion(
song.id,
difficulty === "INF" ? "ANY_INF" : difficulty,
version as "vivid"
);
} else {
tachiChart = await FindChartWithPTDFVersion(
options.game,
song.id,
playtype,
difficulty,
version
);
}
if (!tachiChart) {
logger.error(
`Could not find chart ${songTitle} ${playtype} ${difficulty} ${version} (SongID ${song.id}).`
);
continue;
}
// eslint-disable-next-line no-await-in-loop
await db.charts[options.game as "sdvx" | "iidx"].update(
{
chartID: tachiChart.chartID,
},
{
$set: {
"data.arcChartID": chart._id,
},
}
);
}
}
await db.charts[options.game as "sdvx" | "iidx"].update(
{
"data.arcChartID": { $exists: false },
},
{ $set: { "data.arcChartID": null } },
{
multi: true,
}
);
logger.info("done.");
process.exit(0);
}
if (require.main === module) {
MergeIDs();
}
@@ -1,117 +0,0 @@
/* eslint-disable no-await-in-loop */
import db from "external/mongo/db";
import fs from "fs";
import CreateLogCtx from "lib/logger/logger";
import path from "path";
import { FindSongOnTitleInsensitive } from "utils/queries/songs";
const logger = CreateLogCtx(__filename);
const comicallyLargeJSONData = JSON.parse(
fs.readFileSync(path.join(__dirname, "./versions.json"), "utf-8")
);
const DIFF_MAP = {
A: "ANOTHER",
H: "HYPER",
N: "NORMAL",
B: "BEGINNER",
X: "LEGGENDARIA",
} as any;
function ConvertVersion(c: string): any {
if (c.startsWith("AC")) {
return c.split("AC")[1];
} else if (c.startsWith("OM")) {
return `${c.split("OM")[1]}-omni`;
} else if (c.startsWith("CS")) {
return `${c.split("CS")[1]}-cs`;
} else if (c === "INF") {
return "inf";
} else if (c === "BMUS") {
return "bmus";
} else {
logger.error(`Invalid Chart Version ${c}.`);
throw new Error("Invalid Chart Version");
}
}
(async () => {
for (const data of comicallyLargeJSONData) {
const song = await FindSongOnTitleInsensitive("iidx", data["MUSIC NAME"]);
if (!song) {
logger.error(`Can't find song with title ${data["MUSIC NAME"]}.`);
continue;
}
const playtype = data.STYLE === "S" ? "SP" : "DP";
const difficulty = DIFF_MAP[data.DIFF];
const relevantVersions = [
"OM27",
"OM26",
"AC27",
"AC26",
"AC25",
"AC24",
"AC23",
"AC22",
"AC21",
"AC20",
"INF",
"CS16",
"CS15",
"CS14",
"CS13",
"CS12",
"CS11",
"CS10",
"CS9",
"CS8",
"CS7",
"BMUS",
"CS6",
"CS5",
"CS4",
"CS3",
]
.filter((e) => data[e] === "1")
.map(ConvertVersion);
if (!relevantVersions.includes("27-omni") && !relevantVersions.includes("inf")) {
if (relevantVersions.includes("26-omni")) {
logger.info(
`Song ${song.title} (${playtype} ${difficulty}) was a very recent removal. Consider deprimarifying it. (had ${relevantVersions})`,
{ keys: Object.keys(data).filter((e) => data[e] === "1") }
);
} else {
logger.verbose(
`Song ${song.title} (${playtype} ${difficulty}) has no relevant versions. (had ${relevantVersions})`,
{ keys: Object.keys(data).filter((e) => data[e] === "1") }
);
}
continue;
}
const chart = await db.charts.iidx.findOne(
{ songID: song.id, difficulty, playtype },
{ projectID: true }
);
if (!chart) {
logger.error(`Can't find chart ${song.title} (${playtype} ${difficulty})`);
continue;
}
relevantVersions.push(...chart.versions.filter((e) => !relevantVersions.includes(e)));
await db.charts.iidx.update({ _id: chart._id }, { $set: { versions: relevantVersions } });
}
logger.info("done");
process.exit(0);
})();
File diff suppressed because it is too large Load Diff
@@ -1,172 +0,0 @@
/* eslint-disable no-await-in-loop */
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
import {
FormatGame,
GetGameConfig,
GetGamePTConfig,
IDStrings,
integer,
StaticConfig,
} from "tachi-common";
import { CreateFolderID } from "utils/folder";
const logger = CreateLogCtx(__filename);
function StrRange(min: integer, max: integer) {
const arr = [];
for (let i = min; i <= max; i++) {
arr.push(i.toString());
}
return arr;
}
// These are the games that have simple, discrete folders.
const STATIC_LEVELS: Partial<Record<IDStrings, string[]>> = {
"iidx:SP": StrRange(1, 12),
"iidx:DP": StrRange(1, 12),
"bms:7K": [],
"bms:14K": [],
"chunithm:Single": [
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"7+",
"8",
"8+",
"9",
"9+",
"10",
"10+",
"11",
"11+",
"12",
"12+",
"13",
"13+",
"14",
"14+",
],
"maimai:Single": [
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"7+",
"8",
"8+",
"9",
"9+",
"10",
"10+",
"11",
"11+",
"12",
"12+",
"13",
"13+",
"14",
],
"museca:Single": StrRange(1, 15),
"sdvx:Single": StrRange(1, 20),
"ddr:SP": StrRange(1, 20),
"ddr:DP": StrRange(1, 20),
};
async function InsertStaticLevelVersionFolders() {
// Little known fact: I invented the cyclomatic complexity warning
for (const { game, playtype } of GPTYielder()) {
const gameConfig = GetGameConfig(game);
const gptConfig = GetGamePTConfig(game, playtype);
for (const version of gptConfig.supportedVersions) {
// @ts-expect-error dont worry
const staticLevels = STATIC_LEVELS[`${game}:${playtype}`];
if (!staticLevels) {
continue;
}
let inactive = false;
if (
!(
gptConfig.currentGameOmniVersion === version ||
gptConfig.currentLatestVersion === version ||
gptConfig.currentLocalVersion === version
)
) {
inactive = true;
}
await db.tables.insert({
tableID: `${game}-${playtype}-${version}-levels`,
description: `Levels for ${FormatGame(game, playtype)} in version ${version}.`,
title: `${FormatGame(game, playtype)} (${version})`,
folders: [],
game,
playtype,
inactive,
});
for (const level of staticLevels) {
const query = {
level,
versions: version,
};
const folderID = CreateFolderID(query, game, playtype);
await db.folders.insert({
folderID,
game,
playtype,
title: `Level ${level} (${version})`,
type: "charts",
data: query,
searchTerms: [],
inactive,
});
await db.tables.update(
{
tableID: `${game}-${playtype}-${version}-levels`,
},
{
$push: {
folders: folderID,
},
}
);
logger.info(`Inserted ${gameConfig.name} Level ${level} (${version})`);
}
}
}
logger.info(`Done.`);
}
function* GPTYielder() {
for (const game of StaticConfig.allSupportedGames) {
const gameConfig = GetGameConfig(game);
for (const playtype of gameConfig.validPlaytypes) {
yield { game, playtype };
}
}
}
// Some games don't use "fixed" levels per se, and as such breaking
// the folders up are quite hard. This is for *those* games.
async function InsertCustomStuff() {}
(async () => {
await InsertStaticLevelVersionFolders();
})();
+1 -1
View File
@@ -26,6 +26,6 @@ db.invites
consumedAt: null,
})
.then(() => {
console.log(`Created invite ${options.code}.`);
logger.info(`Created invite ${options.code}.`);
process.exit(0);
});
@@ -1,16 +0,0 @@
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
const logger = CreateLogCtx(__filename);
(async () => {
logger.info(`Setting tableFolders.`);
const r = await db.charts.bms.update(
{},
{ $set: { "data.tableFolders": [] } },
{ multi: true }
);
logger.info(`Done!`, { r });
process.exit(0);
})();
@@ -1,20 +0,0 @@
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
import { TachiConfig } from "lib/setup/config";
const logger = CreateLogCtx(__filename);
if (require.main === module) {
(async () => {
for (const game of TachiConfig.GAMES) {
// eslint-disable-next-line no-await-in-loop
const res = await db.charts[game].update(
{ tierlistInfo: { $exists: false } },
{ $set: { tierlistInfo: {} } },
{ multi: true }
);
logger.info(`Added tierlistInfo to ${game}'s charts.`, { res });
}
})();
}
@@ -1,50 +0,0 @@
/* eslint-disable no-await-in-loop */
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
import { GetGamePTConfig } from "tachi-common";
import { GenericGetGradeAndPercent } from "lib/score-import/framework/common/score-utils";
import UpdateScore from "lib/score-mutation/update-score";
const logger = CreateLogCtx(__filename);
if (require.main === module) {
(async () => {
const gptConfig = GetGamePTConfig("iidx", "SP");
for (const [key, grade] of gptConfig.grades.entries()) {
const badScores = await db.scores.find({
game: "iidx",
"scoreData.grade": grade,
"scoreData.percent": { $lt: gptConfig.gradeBoundaries[key] },
});
logger.info(`${grade} (${gptConfig.gradeBoundaries[key]}) ${badScores.length}`);
for (const badScore of badScores) {
const chart = await db.charts.iidx.findOne({ chartID: badScore.chartID });
if (!chart) {
logger.severe(
`Couldn't find chart for ${badScore.chartID}, yet scores exist on it?`
);
continue;
}
const newScore = JSON.parse(JSON.stringify(badScore));
const { grade } = GenericGetGradeAndPercent(
"iidx",
badScore.scoreData.score,
chart
);
newScore.scoreData.grade = grade;
newScore.scoreData.gradeIndex = gptConfig.grades.indexOf(grade);
await UpdateScore(badScore, newScore);
}
}
process.exit(0);
})();
}
@@ -1,71 +0,0 @@
/* eslint-disable no-await-in-loop */
import db from "external/mongo/db";
import { rootLogger } from "lib/logger/logger";
import { ChartDocument, Difficulties } from "tachi-common";
import { FindIIDXChartOnInGameID } from "utils/queries/charts";
async function ConvertChart(chart: ChartDocument<"iidx:SP" | "iidx:DP">) {
// We need to get the related official song. The best way to do this is
// probably with song IDs.
const originalChart = await FindIIDXChartOnInGameID(
chart.data.inGameID,
chart.playtype,
chart.difficulty
);
if (!originalChart) {
rootLogger.error(`Can't find original chart.`, { chart });
throw new Error(`Can't find original chart.`);
}
return {
difficulty: `${chart.data["2dxtraSet"]!} ${chart.difficulty}` as Difficulties[
| "iidx:SP"
| "iidx:DP"],
songID: originalChart!.songID,
};
}
if (require.main === module) {
(async () => {
const modCharts = (await db.charts.iidx.find({
"data.2dxtraSet": { $ne: null },
difficulty: { $in: ["BEGINNER", "NORMAL", "HYPER", "ANOTHER", "LEGGENDARIA"] },
})) as ChartDocument<"iidx:SP" | "iidx:DP">[];
rootLogger.info(`Modifying ${modCharts.length} charts.`);
for (const chart of modCharts) {
const setDoc = await ConvertChart(chart);
await db.charts.iidx.update(
{
chartID: chart.chartID,
},
{ $set: setDoc }
);
// We're also going to have to port over old scores.
await db.scores.update(
{
chartID: chart.chartID,
},
{
$set: {
songID: setDoc.songID,
},
}
);
}
rootLogger.info(`Removing ${modCharts.length} songs.`);
await db.songs.iidx.remove({
id: { $in: modCharts.map((e) => e.songID) },
});
rootLogger.info(`Done.`);
})();
}
@@ -1,29 +0,0 @@
import { Command } from "commander";
import fs from "fs";
import path from "path";
const program = new Command();
program.option("-d, --dir <dir>");
program.parse(process.argv);
const options = program.opts();
if (!options.dir) {
throw new Error(`No dir provided, yet one is necessary.`);
}
// @warn THIS SCRIPT IS OUTDATED!
// Tachi now uses /users/${userID}/banner instead of
// /users/banner/${userID}
fs.mkdirSync("users/banner", { recursive: true });
fs.mkdirSync("users/pfp", { recursive: true });
for (const file of fs.readdirSync(options.dir)) {
const dfile = path.join(options.dir, file);
if (file.endsWith("-banner.png")) {
fs.copyFileSync(dfile, `users/banner/${file.split("-banner.png")[0]}`);
} else {
fs.copyFileSync(dfile, `users/pfp/${file.split("-pfp.png")[0]}`);
}
}
@@ -1,44 +0,0 @@
import db from "external/mongo/db";
(async () => {
const folders = await db.folders.find({}, { sort: { tableIndex: 1 } });
for (const folder of folders) {
const { game, playtype } = folder;
const tableID = ((folder as any).table as string)
.toLowerCase()
.replace(/ /gu, "_")
.replace(/\(/gu, "")
.replace(/\)/gu, "");
console.log(game, playtype, tableID, folder.title);
const existingTable = await db.tables.findOne({ game, playtype, tableID });
if (!existingTable) {
await db.tables.insert({
tableID,
game,
playtype,
description: "todo",
folders: [folder.folderID],
// @ts-expect-error yea
title: folder.table,
});
} else {
await db.tables.update(
{
game,
playtype,
tableID,
},
{
$push: {
folders: folder.folderID,
},
}
);
}
}
})();
@@ -1,76 +0,0 @@
/* eslint-disable no-await-in-loop */
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
import { CreatePBDoc, UpdateChartRanking } from "lib/score-import/framework/pb/create-pb-doc";
const logger = CreateLogCtx(__filename);
(async () => {
// in an alternate timeline this would be 2020 10 02,
// but i have to account for *those* idiots.
// who now mean i'm shredding other people scores.
// - not zkldi
const hvSt = new Date(2020, 9, 1);
const charts = await db.charts.iidx.find({
songID: 167, // 761 -> rising in the sun; 167 -> sometime.
isPrimary: false,
});
const chartIDs = charts.map((e) => e.chartID);
const affectedUsers = await db.scores.find({
chartID: { $in: chartIDs },
timeAchieved: {
$gt: hvSt.getTime(),
},
});
const userIDs = affectedUsers.map((e) => e.userID);
const r = await db.scores.remove({
chartID: { $in: chartIDs },
timeAchieved: {
$gt: hvSt.getTime(),
},
});
logger.info(`Destroyed scores.`, { r });
for (const userID of userIDs) {
logger.info(`Reprocessing PBs for ${userID}`);
for (const chartID of chartIDs) {
const scores = await db.scores.find({
chartID,
userID,
});
if (scores.length === 0) {
await db["personal-bests"].remove({
chartID,
userID,
});
} else {
const pbDoc = await CreatePBDoc(userID, chartID, logger);
await db["personal-bests"].update(
{
chartID,
userID,
},
{
$set: pbDoc,
},
{
upsert: true,
}
);
await UpdateChartRanking(chartID);
}
}
}
logger.info(`Done`);
})();
@@ -1,18 +0,0 @@
import db from "external/mongo/db";
(async () => {
const charts = await db.charts.chunithm.find({});
for (const c of charts) {
await db.charts.chunithm.update(
{
_id: c._id,
},
{
$set: {
"data.inGameID": c.songID,
},
}
);
}
})();
@@ -1,55 +0,0 @@
import db from "external/mongo/db";
(async () => {
await db.scores.update(
{ game: "sdvx", "scoreData.lamp": "ULTIMATE CHAIN" },
{
$set: {
"scoreData.judgements.miss": 0,
},
},
{
multi: true,
}
);
await db["personal-bests"].update(
{ game: "sdvx", "scoreData.lamp": "ULTIMATE CHAIN" },
{
$set: {
"scoreData.judgements.miss": 0,
},
},
{
multi: true,
}
);
await db.scores.update(
{ game: "sdvx", "scoreData.lamp": "PERFECT ULTIMATE CHAIN" },
{
$set: {
"scoreData.judgements.miss": 0,
"scoreData.judgements.near": 0,
},
},
{
multi: true,
}
);
await db["personal-bests"].update(
{ game: "sdvx", "scoreData.lamp": "PERFECT ULTIMATE CHAIN" },
{
$set: {
"scoreData.judgements.miss": 0,
"scoreData.judgements.near": 0,
},
},
{
multi: true,
}
);
process.exit(0);
})();
@@ -1,32 +0,0 @@
import db from "external/mongo/db";
if (require.main === module) {
(async () => {
const ugs = await db["user-goals"].find(
{},
{
projectID: true,
}
);
for (const ug of ugs) {
await db["user-goals"].update(
{
_id: ug._id,
},
{
$set: {
progressHuman: ug.progressHuman.toString(),
outOfHuman: ug.outOfHuman.toString(),
lastInteraction: null,
},
$unset: {
note: 1,
},
}
);
}
process.exit(0);
})();
}
@@ -1,25 +0,0 @@
import db from "external/mongo/db";
import fs from "fs";
(async () => {
const all = await db.songs.sdvx.find({});
const humanise = [];
for (const h of all) {
if (!h.title.match(/^[a-zA-Z0-9 ().!?-_]*$/)) {
humanise.push(h);
}
}
fs.writeFileSync(
"needs-humanise.csv",
humanise
.map(
(e) =>
`${e.id}, "${e.title.replace('"', '\\"')}", "${e.artist.replace('"', '\\"')}"`
)
.join("\n")
);
process.exit(0);
})();
@@ -1,21 +0,0 @@
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
import { StaticConfig } from "tachi-common";
const logger = CreateLogCtx(__filename);
(async () => {
for (const game of StaticConfig.allSupportedGames) {
// eslint-disable-next-line no-await-in-loop
await db.songs[game].update(
{},
{ $rename: { "alt-titles": "altTitles", "search-titles": "searchTerms" } },
{ multi: true }
);
logger.info(`Refactored title names for ${game}.`);
}
logger.info(`Done.`);
process.exit(0);
})();
-171
View File
@@ -1,171 +0,0 @@
import db from "external/mongo/db";
import fs from "fs";
import {
USC_DEFAULT_HOLD,
USC_DEFAULT_MISS,
USC_DEFAULT_NEAR,
USC_DEFAULT_PERFECT,
USC_DEFAULT_SLAM,
} from "lib/constants/usc-ir";
import CreateLogCtx from "lib/logger/logger";
import { OrphanScore } from "lib/score-import/framework/orphans/orphans";
import UpdateScore from "lib/score-mutation/update-score";
import { integer, ScoreDocument } from "tachi-common";
import { DeleteScore } from "lib/score-mutation/delete-scores";
import { UpdateAllPBs } from "utils/calculations/recalc-scores";
const logger = CreateLogCtx(__filename);
const oldChartIDtoSHA1 = JSON.parse(fs.readFileSync(`${__dirname}/usc-map.json`, "utf-8"));
if (require.main === module) {
(async () => {
const keep = await db.charts.usc.find(
{ "data.hashSHA1": { $in: Object.values(oldChartIDtoSHA1) } },
{ projection: { chartID: 1, "data.hashSHA1": 1, songID: 1, playtype: 1 } }
);
// @ts-expect-error asdf
const keepHashes = keep.map((e) => e.data.hashSHA1);
const keepChartIDs = Object.entries(oldChartIDtoSHA1)
.filter(([, v]) => keepHashes.includes(v))
.map(([k]) => k);
const rmScores = (await db.scores.find({
game: "usc",
chartID: { $nin: keepChartIDs },
})) as ScoreDocument<"usc:Controller" | "usc:Keyboard">[];
logger.info(`Re-orphaning and unseating ${rmScores.length} scores.`);
let i = 0;
for (const score of rmScores) {
i++;
if (i % 100 === 0) {
logger.info(`${i}/${rmScores.length}...`);
}
const chartSHA1 = oldChartIDtoSHA1[score.chartID];
if (!chartSHA1) {
logger.warn(`Can't find a chartsha1 for ${score.chartID}?`);
continue;
}
await ReOrphanScore(score, chartSHA1);
await DeleteScore(score, false, false);
}
const keepScores = await db.scores.find({
game: "usc",
chartID: { $in: keepChartIDs },
});
logger.info(`Keeping and migrating ${keepScores.length} scores.`);
const sha1ToChartID = Object.fromEntries(
keep.map((e) => [
// @ts-expect-error hashsha1 exists i'm just lazy
`${e.data.hashSHA1}:${e.playtype}`,
{ chartID: e.chartID, songID: e.songID },
])
) as { [key: string]: { chartID: string; songID: integer } };
let j = 0;
for (const score of keepScores) {
j++;
if (j % 100 === 0) {
logger.info(`${j}/${keepScores.length}`);
}
const sha1 = oldChartIDtoSHA1[score.chartID];
const newChartID = sha1ToChartID[`${sha1}:${score.playtype}`].chartID;
const newSongID = sha1ToChartID[`${sha1}:${score.playtype}`].songID;
if (!newChartID) {
logger.error(
`Couldn't resolve old:${score.chartID} -> sha1:${sha1} (playtype: ${score.playtype}) -> new:${newChartID}?`
);
throw new Error("panic");
}
await UpdateScore(
score,
Object.assign({}, score, { songID: newSongID, chartID: newChartID }),
false
);
}
// You'd think the update scripts don't result in pbs that point to
// dead charts, but they do.
logger.info(`Reloading USC PBs.`);
await db["personal-bests"].remove({ game: "usc" });
await UpdateAllPBs(undefined, { game: "usc" });
logger.info(`Done.`);
process.exit(0);
})();
}
function ReOrphanScore(sc: ScoreDocument<"usc:Controller" | "usc:Keyboard">, chartSHA1: string) {
let mirror = false;
let random = false;
if (sc.scoreMeta.noteMod === "MIR-RAN") {
mirror = true;
random = false;
} else if (sc.scoreMeta.noteMod === "RANDOM") {
random = true;
} else if (sc.scoreMeta.noteMod === "MIRROR") {
mirror = true;
}
const gaugeType =
sc.scoreMeta.gaugeMod === "NORMAL"
? 0
: sc.scoreMeta.gaugeMod === "HARD"
? 1
: sc.scoreMeta.gaugeMod === "PERMISSIVE"
? 2
: 0;
return OrphanScore(
"ir/usc",
sc.userID,
{
combo: sc.scoreData.hitMeta.maxCombo ?? null,
crit: sc.scoreData.judgements.critical!,
near: sc.scoreData.judgements.near!,
error: sc.scoreData.judgements.miss!,
early: sc.scoreData.hitMeta.fast ?? null,
late: sc.scoreData.hitMeta.slow ?? null,
gauge: sc.scoreData.hitMeta.gauge!,
options: {
autoFlags: 0,
gaugeOpt: 0,
gaugeType,
mirror,
random,
},
score: sc.scoreData.score,
timestamp: sc.timeAchieved!,
windows: {
perfect: USC_DEFAULT_PERFECT,
good: USC_DEFAULT_NEAR,
hold: USC_DEFAULT_HOLD,
miss: USC_DEFAULT_MISS,
slam: USC_DEFAULT_SLAM,
},
},
{
chartHash: chartSHA1,
playtype: sc.playtype,
timeReceived: sc.timeAchieved!,
},
`Lost parent as a result of USC migration.`,
"usc",
logger
);
}
@@ -1,49 +0,0 @@
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
import { GetGradeFromPercent } from "lib/score-import/framework/common/score-utils";
import UpdateScore from "lib/score-mutation/update-score";
import { ChartDocument, GetGamePTConfig } from "tachi-common";
const logger = CreateLogCtx(__filename);
if (require.main === module) {
let i = 0;
db.scores
.find({ game: "chunithm", "scoreData.grade": null })
// @ts-expect-error dumb
.each(async (oldScore, { pause, resume }) => {
pause();
const chart = (await db.charts.chunithm.findOne({
chartID: oldScore.chartID,
})) as ChartDocument<"chunithm:Single">;
if (!chart) {
logger.severe(`Chart ${oldScore.chartID} has no chart?`);
return resume();
}
const newScore = JSON.parse(JSON.stringify(oldScore));
newScore.scoreData.grade = GetGradeFromPercent(
"chunithm",
oldScore.playtype,
oldScore.scoreData.percent
);
newScore.scoreData.gradeIndex = GetGamePTConfig(
"chunithm",
oldScore.playtype
).grades.indexOf(newScore.scoreData.grade);
await UpdateScore(oldScore, newScore);
i++;
resume();
})
.then(() => {
logger.info(`Fixed ${i} bad scores.`);
process.exit(0);
});
}
@@ -1,54 +0,0 @@
import db from "external/mongo/db";
import CreateLogCtx from "lib/logger/logger";
import { GetGradeFromPercent } from "lib/score-import/framework/common/score-utils";
import UpdateScore from "lib/score-mutation/update-score";
import { ChartDocument, GetGamePTConfig } from "tachi-common";
const logger = CreateLogCtx(__filename);
if (require.main === module) {
(async () => {
let i = 0;
db.scores
.find({ game: "iidx" })
// @ts-expect-error dumb
.each(async (oldScore, { pause, resume }) => {
pause();
const chart = (await db.charts.iidx.findOne({
chartID: oldScore.chartID,
})) as ChartDocument<"iidx:SP">;
if (!chart) {
logger.severe(`Chart ${oldScore.chartID} has no chart?`);
return resume();
}
const percent = (100 * oldScore.scoreData.score) / (chart.data.notecount * 2);
if (Math.abs(percent - oldScore.scoreData.percent) > 0.00001) {
const newScore = JSON.parse(JSON.stringify(oldScore));
newScore.scoreData.percent = percent;
newScore.scoreData.grade = GetGradeFromPercent(
"iidx",
oldScore.playtype,
percent
);
newScore.scoreData.gradeIndex = GetGamePTConfig(
"iidx",
oldScore.playtype
).grades.indexOf(newScore.scoreData.grade);
await UpdateScore(oldScore, newScore);
i++;
}
resume();
})
.then(() => {
logger.info(`Fixed ${i} bad scores.`);
process.exit(0);
});
})();
}
@@ -1,30 +0,0 @@
import db from "external/mongo/db";
if (require.main === module) {
(async () => {
const badScoreInfos = await db.sessions.find({
"scoreInfo.isNewScore": false,
"scoreInfo.scoreDelta": null,
});
for (const session of badScoreInfos) {
const scoreInfo = session.scoreInfo.filter(
(e) => !(!e.isNewScore && e.scoreDelta === null)
);
// eslint-disable-next-line no-await-in-loop
await db.sessions.update(
{
sessionID: session.sessionID,
},
{
$set: {
scoreInfo,
},
}
);
}
process.exit(0);
})();
}
-16
View File
@@ -1,16 +0,0 @@
import CreateLogCtx from "lib/logger/logger";
import { PushToS3 } from "lib/cdn/s3";
const logger = CreateLogCtx(__filename);
if (require.main === module) {
(async () => {
logger.info("Starting request.");
const res = await PushToS3("debug/testfile", "foo.txt");
logger.info("Request done.", res);
process.exit(0);
})();
}
@@ -1,3 +0,0 @@
import UpdateIsPrimaryStatus from "lib/score-mutation/update-isprimary";
UpdateIsPrimaryStatus().then(() => process.exit(0));
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -4,6 +4,7 @@ import { Command } from "commander";
import { Databases, monkDB } from "external/mongo/db";
import { DatabaseSchemas } from "external/mongo/schemas";
import CreateLogCtx from "lib/logger/logger";
import { PrudenceError } from "prudence";
import { FormatPrError } from "utils/prudence";
const program = new Command();
@@ -33,7 +34,7 @@ export async function ValidateCollection(collectionName: Databases): Promise<voi
schemaRunner(c);
success++;
} catch (err) {
logger.error(`[${collectionName}]: ${FormatPrError(err)}`, c);
logger.error(`[${collectionName}]: ${FormatPrError(err as PrudenceError)}`, c);
fails++;
}
});