diff --git a/nise-backend/src/main/kotlin/com/nisemoe/nise/database/ScoreService.kt b/nise-backend/src/main/kotlin/com/nisemoe/nise/database/ScoreService.kt index 063043a..1d50cb2 100644 --- a/nise-backend/src/main/kotlin/com/nisemoe/nise/database/ScoreService.kt +++ b/nise-backend/src/main/kotlin/com/nisemoe/nise/database/ScoreService.kt @@ -6,6 +6,7 @@ import com.nisemoe.generated.tables.references.* import com.nisemoe.nise.* import com.nisemoe.nise.integrations.CircleguardService import com.nisemoe.nise.osu.Mod +import com.nisemoe.nise.osu.OsuApi import com.nisemoe.nise.service.AuthService import com.nisemoe.nise.service.CompressJudgements import org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream @@ -14,6 +15,7 @@ import org.jooq.DSLContext import org.jooq.Record import org.jooq.impl.DSL import org.jooq.impl.DSL.avg +import org.slf4j.LoggerFactory import org.springframework.stereotype.Service import java.time.LocalDateTime import java.util.* @@ -24,9 +26,12 @@ class ScoreService( private val dslContext: DSLContext, private val beatmapService: BeatmapService, private val authService: AuthService, + private val osuApi: OsuApi, private val compressJudgements: CompressJudgements ) { + private val logger = LoggerFactory.getLogger(javaClass) + companion object { val osuScoreAlias1 = SCORES.`as`("osu_score_alias1") @@ -44,6 +49,11 @@ class ScoreService( } fun getReplayViewerData(replayId: Long): ReplayViewerData? { + val beatmapId = dslContext.select(SCORES.BEATMAP_ID) + .from(SCORES) + .where(SCORES.REPLAY_ID.eq(replayId)) + .fetchOneInto(Int::class.java) ?: return null + val result = dslContext.select( SCORES.REPLAY, SCORES.MODS, @@ -58,12 +68,25 @@ class ScoreService( val replay = decompressData(replayData) - if(result.get(BEATMAPS.BEATMAP_FILE, String::class.java) == null) return null + var beatmapFile = result.get(BEATMAPS.BEATMAP_FILE, String::class.java) + if(beatmapFile == null) { + beatmapFile = this.osuApi.getBeatmapFile(beatmapId = beatmapId) + + if(beatmapFile == null) { + this.logger.error("Failed to fetch beatmap file for beatmap_id = $beatmapId from osu!api") + return null + } else { + dslContext.update(BEATMAPS) + .set(BEATMAPS.BEATMAP_FILE, beatmapFile) + .where(BEATMAPS.BEATMAP_ID.eq(beatmapId)) + .execute() + } + } val mods = result.get(SCORES.MODS, Int::class.java) return ReplayViewerData( - beatmap = result.get(BEATMAPS.BEATMAP_FILE, String::class.java), + beatmap = beatmapFile, replay = String(replay, Charsets.UTF_8).trimEnd(','), judgements = getJudgements(replayId), mods = mods diff --git a/nise-backend/src/main/kotlin/com/nisemoe/nise/scheduler/FixEntities.kt b/nise-backend/src/main/kotlin/com/nisemoe/nise/scheduler/FixEntities.kt new file mode 100644 index 0000000..13caa73 --- /dev/null +++ b/nise-backend/src/main/kotlin/com/nisemoe/nise/scheduler/FixEntities.kt @@ -0,0 +1,58 @@ +package com.nisemoe.nise.scheduler + +import com.nisemoe.generated.tables.references.BEATMAPS +import com.nisemoe.nise.osu.OsuApi +import org.jooq.DSLContext +import org.slf4j.LoggerFactory +import org.springframework.context.annotation.Profile +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Service + +@Service +@Profile("fix:entities") +class FixEntities( + private val dslContext: DSLContext, + private val osuApi: OsuApi +){ + + private val logger = LoggerFactory.getLogger(javaClass) + + // TODO: Those need to be scheduled + + /** + * This fetches all SCORES that have a beatmap_id that is not in the BEATMAPS table and tries to fetch the beatmap + */ +// @Scheduled(fixedDelay = 120000, initialDelay = 0) +// fun fixMissingBeatmaps() { +// +// } + + /** + * This fetches all BEATMAPS that have a beatmap_file that is null and tries to fetch it. + */ + @Scheduled(cron = "0 0 0 * * *") + fun fixBeatmapsWithoutFile() { + val beatmapIds = dslContext.select(BEATMAPS.BEATMAP_ID) + .from(BEATMAPS) + .where(BEATMAPS.BEATMAP_FILE.isNull) + .fetchInto(Int::class.java) + + this.logger.info("Found ${beatmapIds.size} beatmaps without file") + + beatmapIds.forEachIndexed { index, beatmapId -> + val beatmap = this.osuApi.getBeatmapFile(beatmapId) + + if(beatmap != null) { + val result = dslContext.update(BEATMAPS) + .set(BEATMAPS.BEATMAP_FILE, beatmap) + .where(BEATMAPS.BEATMAP_ID.eq(beatmapId)) + .execute() + + this.logger.info("Updated beatmap $beatmapId, affected rows: $result [${index + 1}/${beatmapIds.size}]") + } else { + this.logger.error("Failed to fetch beatmap $beatmapId") + } + } + } + +} \ No newline at end of file diff --git a/nise-replay-viewer/index.html b/nise-replay-viewer/index.html index ef2506e..6ec771e 100644 --- a/nise-replay-viewer/index.html +++ b/nise-replay-viewer/index.html @@ -4,7 +4,7 @@ - Replay Inspector + /replay/ diff --git a/nise-replay-viewer/src/osu/OsuRenderer.ts b/nise-replay-viewer/src/osu/OsuRenderer.ts index 804ccfe..0f9a7ca 100644 --- a/nise-replay-viewer/src/osu/OsuRenderer.ts +++ b/nise-replay-viewer/src/osu/OsuRenderer.ts @@ -14,6 +14,7 @@ import {Drawer} from "./Drawer"; import {Vec2} from "@osujs/math"; import {clamp, getBeatmap, getReplay} from "@/utils"; import EventEmitter from "eventemitter3"; +import {toast} from "sonner"; export enum OsuRendererEvents { UPDATE = "UPDATE", @@ -224,7 +225,14 @@ export class OsuRenderer { } }); - const data = await response.json(); + let data; + + if (!response.ok) { + toast.error("Failed to load replay :("); + return Promise.reject(); + } else { + data = await response.json(); + } const { beatmap, replay, mods, judgements } = data;