From 7665cbbae4884082f87cdb263213299c11d7bb44 Mon Sep 17 00:00:00 2001 From: Liam <67254223+RealFascinated@users.noreply.github.com> Date: Sat, 22 Oct 2022 12:28:46 +0100 Subject: [PATCH] Only cache what we need from BeatSaver --- pages/api/beatsaver/art/[hash].js | 55 ----------- pages/api/beatsaver/map.js | 9 +- src/components/SongInfo.js | 7 +- ...eatSaverHelpers.js => beatSaverHelpers.ts} | 24 ++++- src/types/BeatSaverMapData.ts | 91 +++++++++++++++++++ 5 files changed, 117 insertions(+), 69 deletions(-) delete mode 100644 pages/api/beatsaver/art/[hash].js rename src/helpers/{beatSaverHelpers.js => beatSaverHelpers.ts} (62%) create mode 100644 src/types/BeatSaverMapData.ts diff --git a/pages/api/beatsaver/art/[hash].js b/pages/api/beatsaver/art/[hash].js deleted file mode 100644 index c2512ac..0000000 --- a/pages/api/beatsaver/art/[hash].js +++ /dev/null @@ -1,55 +0,0 @@ -import fetch from "node-fetch"; -import sharp from "sharp"; -import { - getValue, - setValue, - valueExists, -} from "../../../../src/utils/redisUtils"; - -const KEY = "BS_MAP_ART_"; - -/** - * - * @param {Request} req - * @param {Response} res - * @returns - */ -export default async function handler(req, res) { - const mapHash = req.query.hash.replace("custom_level_", "").toLowerCase(); - const ext = req.query.ext || "jpg"; - - const exists = await valueExists(`${KEY}${mapHash}`.replace(" ", "")); - if (exists) { - const data = await getValue(`${KEY}${mapHash}`); - const buffer = Buffer.from(data, "base64"); - res.writeHead(200, { - "Content-Type": "image/" + ext, - "Content-Length": buffer.length, - "Cache-Status": "hit", - }); - return res.end(buffer); - } - - const before = Date.now(); - const data = await fetch(`https://eu.cdn.beatsaver.com/${mapHash}.${ext}`); - if (data.status === 404) { - return res.status(404).json({ - status: 404, - message: "Unknown Map Hash", - }); - } - - let buffer = await data.buffer(); // Change to arrayBuffer at some point to make it shush - buffer = await sharp(buffer).resize(400, 400).toBuffer(); - const bytes = buffer.toString("base64"); - - await setValue(`${KEY}${mapHash}`.replace(" ", ""), bytes); - console.log( - `[Cache]: Cached BS Song Art for hash ${mapHash} in ${ - Date.now() - before - }ms` - ); - res.setHeader("Cache-Status", "miss"); - res.setHeader("Content-Type", "image/" + ext); - res.status(200).send(buffer); -} diff --git a/pages/api/beatsaver/map.js b/pages/api/beatsaver/map.js index 04185c4..e8813ac 100644 --- a/pages/api/beatsaver/map.js +++ b/pages/api/beatsaver/map.js @@ -11,12 +11,5 @@ export default async function handler(req, res) { message: "Unknown Map Hash", }); } - const data = { - // The maps data from the provided map hash - bsr: mapData.id, - songArt: `http://${req.headers.host}/api/beatsaver/art/${mapHash}?ext=${ - mapData.versions[0].coverURL.split("/")[3].split(".")[1] - }`, - }; - res.status(200).json({ error: false, data: data }); + res.status(200).json({ status: "OK", data: mapData }); } diff --git a/src/components/SongInfo.js b/src/components/SongInfo.js index 4207903..557fbae 100644 --- a/src/components/SongInfo.js +++ b/src/components/SongInfo.js @@ -56,12 +56,11 @@ export default class SongInfo extends Component { render() { const data = this.props.data.songData.status.beatmap; const beatSaverData = this.props.data.beatSaverData.data; - const songArt = beatSaverData.songArt; + const mapArt = beatSaverData.mapArt; const bsr = beatSaverData.bsr; const { songName, songAuthorName, difficulty } = data; - // what in the fuck is this?? LMFAO const songTimerPercentage = - (this.props.data.currentSongTime / 1000 / (data.length / 1000)) * 100000; + (this.props.data.currentSongTime / data.length) * 100; return (
@@ -69,7 +68,7 @@ export default class SongInfo extends Component { width={150} height={150} alt="Song artwork" - src={songArt} + src={mapArt} loading="lazy" placeholder="blur" blurDataURL="https://cdn.fascinated.cc/IkQFyodbZv.jpg?raw=true" diff --git a/src/helpers/beatSaverHelpers.js b/src/helpers/beatSaverHelpers.ts similarity index 62% rename from src/helpers/beatSaverHelpers.js rename to src/helpers/beatSaverHelpers.ts index 2a83d26..853a0d0 100644 --- a/src/helpers/beatSaverHelpers.js +++ b/src/helpers/beatSaverHelpers.ts @@ -1,3 +1,4 @@ +import { BeatSaverMapData } from "../types/BeatSaverMapData"; import { getValue, setValue, valueExists } from "../utils/redisUtils"; const BEATSAVER_MAP_API = @@ -6,13 +7,28 @@ const BEATSAVER_MAP_API = const KEY = "BS_MAP_DATA_"; +function getLatestMapArt(data: BeatSaverMapData) { + console.log(data); + let url: string | undefined = undefined; + for (const version of data.versions) { + url = version.coverURL; + } + console.log(url); + return url; +} + +type MapData = { + bsr: string; + mapArt: string | undefined; +}; + /** * Gets a specified maps data from BeatSaver * * @param {string} hash * @returns The map data */ -export async function getMapData(hash) { +export async function getMapData(hash): Promise { const mapHash = hash.replace("custom_level_", "").toLowerCase(); const key = `${KEY}${mapHash}`; @@ -31,7 +47,11 @@ export async function getMapData(hash) { if (data.status === 404) { return undefined; } - const json = await data.json(); + const jsonResponse = await data.json(); + const json = { + bsr: jsonResponse.id, + mapArt: getLatestMapArt(jsonResponse), + }; await setValue(key, JSON.stringify(json)); console.log( `[Cache]: Cached BS Map Data for hash ${mapHash} in ${ diff --git a/src/types/BeatSaverMapData.ts b/src/types/BeatSaverMapData.ts new file mode 100644 index 0000000..26e7f1f --- /dev/null +++ b/src/types/BeatSaverMapData.ts @@ -0,0 +1,91 @@ +export type BeatSaverMapData = { + id: string; + name: string; + description: string; + uploader: { + id: string; + name: string; + hash: string; + avatar: string; + type: string; + admin: boolean; + curator: boolean; + verifiedMapper: boolean; + }; + metadata: { + bpm: number; + duration: number; + songName: string; + songSubName: string; + songAuthorName: string; + levelAuthorName: string; + }; + stats: { + plays: number; + downloads: number; + upvotes: number; + downvotes: number; + score: number; + }; + uploaded: string; + automapper: boolean; + ranked: boolean; + qualified: boolean; + versions: Array; + curator: Curator; + curatedAt: string; + createdAt: string; + updatedAt: string; + lastPublishedAt: string; + tags: Array; +}; + +export type Version = { + hash: string; + state: string; + createdAt: string; + sageScore: number; + diffs: Array; + downloadURL: string; + coverURL: string; + previewURL: string; +}; + +export type Difficulty = { + njs: number; + offset: number; + notes: number; + bombs: number; + obstacles: number; + nps: number; + length: number; + characteristic: string; + difficulty: DifficultyType; + events: number; + chroma: boolean; + me: boolean; + ne: boolean; + cinema: boolean; + seconds: number; + paritySummary: ParitySummary; + stars: number; + maxScore: number; +}; + +export type DifficultyType = ["Easy", "Normal", "Hard", "Expert", "ExpertPlus"]; + +export type ParitySummary = { + errors: number; + warns: number; + resets: number; +}; + +export type Curator = { + id: number; + name: string; + hash: string; + avatar: string; + type: string; + admin: boolean; + curator: boolean; +};