Only cache what we need from BeatSaver
This commit is contained in:
parent
efbbd6b6f1
commit
7665cbbae4
@ -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);
|
|
||||||
}
|
|
@ -11,12 +11,5 @@ export default async function handler(req, res) {
|
|||||||
message: "Unknown Map Hash",
|
message: "Unknown Map Hash",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const data = {
|
res.status(200).json({ status: "OK", data: mapData });
|
||||||
// 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 });
|
|
||||||
}
|
}
|
||||||
|
@ -56,12 +56,11 @@ export default class SongInfo extends Component {
|
|||||||
render() {
|
render() {
|
||||||
const data = this.props.data.songData.status.beatmap;
|
const data = this.props.data.songData.status.beatmap;
|
||||||
const beatSaverData = this.props.data.beatSaverData.data;
|
const beatSaverData = this.props.data.beatSaverData.data;
|
||||||
const songArt = beatSaverData.songArt;
|
const mapArt = beatSaverData.mapArt;
|
||||||
const bsr = beatSaverData.bsr;
|
const bsr = beatSaverData.bsr;
|
||||||
const { songName, songAuthorName, difficulty } = data;
|
const { songName, songAuthorName, difficulty } = data;
|
||||||
// what in the fuck is this?? LMFAO
|
|
||||||
const songTimerPercentage =
|
const songTimerPercentage =
|
||||||
(this.props.data.currentSongTime / 1000 / (data.length / 1000)) * 100000;
|
(this.props.data.currentSongTime / data.length) * 100;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.songInfoContainer}>
|
<div className={styles.songInfoContainer}>
|
||||||
@ -69,7 +68,7 @@ export default class SongInfo extends Component {
|
|||||||
width={150}
|
width={150}
|
||||||
height={150}
|
height={150}
|
||||||
alt="Song artwork"
|
alt="Song artwork"
|
||||||
src={songArt}
|
src={mapArt}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
placeholder="blur"
|
placeholder="blur"
|
||||||
blurDataURL="https://cdn.fascinated.cc/IkQFyodbZv.jpg?raw=true"
|
blurDataURL="https://cdn.fascinated.cc/IkQFyodbZv.jpg?raw=true"
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { BeatSaverMapData } from "../types/BeatSaverMapData";
|
||||||
import { getValue, setValue, valueExists } from "../utils/redisUtils";
|
import { getValue, setValue, valueExists } from "../utils/redisUtils";
|
||||||
|
|
||||||
const BEATSAVER_MAP_API =
|
const BEATSAVER_MAP_API =
|
||||||
@ -6,13 +7,28 @@ const BEATSAVER_MAP_API =
|
|||||||
|
|
||||||
const KEY = "BS_MAP_DATA_";
|
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
|
* Gets a specified maps data from BeatSaver
|
||||||
*
|
*
|
||||||
* @param {string} hash
|
* @param {string} hash
|
||||||
* @returns The map data
|
* @returns The map data
|
||||||
*/
|
*/
|
||||||
export async function getMapData(hash) {
|
export async function getMapData(hash): Promise<MapData | undefined> {
|
||||||
const mapHash = hash.replace("custom_level_", "").toLowerCase();
|
const mapHash = hash.replace("custom_level_", "").toLowerCase();
|
||||||
|
|
||||||
const key = `${KEY}${mapHash}`;
|
const key = `${KEY}${mapHash}`;
|
||||||
@ -31,7 +47,11 @@ export async function getMapData(hash) {
|
|||||||
if (data.status === 404) {
|
if (data.status === 404) {
|
||||||
return undefined;
|
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));
|
await setValue(key, JSON.stringify(json));
|
||||||
console.log(
|
console.log(
|
||||||
`[Cache]: Cached BS Map Data for hash ${mapHash} in ${
|
`[Cache]: Cached BS Map Data for hash ${mapHash} in ${
|
91
src/types/BeatSaverMapData.ts
Normal file
91
src/types/BeatSaverMapData.ts
Normal file
@ -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<Version>;
|
||||||
|
curator: Curator;
|
||||||
|
curatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
lastPublishedAt: string;
|
||||||
|
tags: Array<string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Version = {
|
||||||
|
hash: string;
|
||||||
|
state: string;
|
||||||
|
createdAt: string;
|
||||||
|
sageScore: number;
|
||||||
|
diffs: Array<Difficulty>;
|
||||||
|
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;
|
||||||
|
};
|
Reference in New Issue
Block a user