diff --git a/common/src/lib/schemas.ts b/common/src/lib/schemas.ts index fce2d0adb..c5c2ed372 100644 --- a/common/src/lib/schemas.ts +++ b/common/src/lib/schemas.ts @@ -880,6 +880,7 @@ const PR_BATCH_MANUAL_SCORE = (game: Game, playtype: Playtype): PrudenceSchema = identifier: "string", comment: optNull(p.isBoundedString(3, 240)), difficulty: "*?string", + artist: "*?string", // this is checked in converting instead // the lowest acceptable time is september 9th 2001 - this check saves people who dont diff --git a/common/src/types/batch-manual.ts b/common/src/types/batch-manual.ts index 2fda2c40b..5c4ff40f1 100644 --- a/common/src/types/batch-manual.ts +++ b/common/src/types/batch-manual.ts @@ -34,6 +34,7 @@ export type BatchManualScore = ExtractMetrics comment?: string | null; judgements?: Record; timeAchieved?: number | null; + artist?: string | null; optional?: AllFieldsNullableOptional>; /** diff --git a/server/example/conf.json5 b/server/example/conf.json5 index ac8c60ca3..a746523ff 100644 --- a/server/example/conf.json5 +++ b/server/example/conf.json5 @@ -50,6 +50,7 @@ "maimai", "maimaidx", "itg", + "ongeki", "ddr" ], IMPORT_TYPES: [ diff --git a/server/src/lib/score-import/import-types/common/batch-manual/converter.ts b/server/src/lib/score-import/import-types/common/batch-manual/converter.ts index 164358a3d..c5d164295 100644 --- a/server/src/lib/score-import/import-types/common/batch-manual/converter.ts +++ b/server/src/lib/score-import/import-types/common/batch-manual/converter.ts @@ -233,7 +233,7 @@ export async function ResolveMatchTypeToTachiData( } case "songTitle": { - const song = await FindSongOnTitleInsensitive(game, data.identifier); + const song = await FindSongOnTitleInsensitive(game, data.identifier, data.artist); if (!song) { throw new SongOrChartNotFoundFailure( diff --git a/server/src/utils/queries/songs.ts b/server/src/utils/queries/songs.ts index 758dbf977..437083b8c 100644 --- a/server/src/utils/queries/songs.ts +++ b/server/src/utils/queries/songs.ts @@ -50,21 +50,32 @@ export async function FindSongOnTitle(game: Game, title: string): Promise { // @optimisable: Performance should be tested here by having a utility field for all-titles. - const regex = new RegExp(`^${EscapeStringRegexp(title)}$`, "iu"); + const regexTitle = new RegExp(`^${EscapeStringRegexp(title)}$`, "iu"); + const regexArtist = new RegExp(`^${EscapeStringRegexp(artist ?? "")}$`, "iu"); const res = await db.anySongs[game].find( { - $or: [ - { - title: { $regex: regex }, - }, + $and: [ { - altTitles: { $regex: regex }, + $or: [ + { + title: { $regex: regexTitle }, + }, + { + altTitles: { $regex: regexTitle }, + }, + ], }, + artist + ? { + artist: { $regex: regexArtist }, + } + : {}, ], }, { @@ -75,7 +86,9 @@ export async function FindSongOnTitleInsensitive( if (res.length === 2) { throw new AmbiguousTitleFailure( title, - `Multiple songs exist with the case-insensitive title ${title}. We cannot resolve this. Please try and use a different song resolution method.` + artist + ? `Multiple songs exist with the case-insensitive title ${title} by artist ${artist}. We cannot resolve this. Please try and use a different song resolution method.` + : `Multiple songs exist with the case-insensitive title ${title}. We cannot resolve this. Please try adding an artist field.` ); }