many many change

This commit is contained in:
Liam 2022-10-21 17:12:32 +01:00
parent f87940c01e
commit 82d565f130
13 changed files with 163 additions and 178 deletions

@ -1,6 +1,6 @@
import fetch from "node-fetch"; import fetch from "node-fetch";
import WebsiteTypes from "../../../src/consts/LeaderboardType"; import WebsiteTypes from "../../../src/consts/LeaderboardType";
import RedisUtils from "../../../src/utils/redisUtils"; import { getValue, setValue, valueExists } from "../../../src/utils/redisUtils";
const KEY = "BL_MAP_STAR_"; const KEY = "BL_MAP_STAR_";
@ -16,9 +16,9 @@ export default async function handler(req, res) {
const characteristic = req.query.characteristic; const characteristic = req.query.characteristic;
const key = `${KEY}${difficulty}-${characteristic}-${mapHash}`; const key = `${KEY}${difficulty}-${characteristic}-${mapHash}`;
const exists = await RedisUtils.exists(key); const exists = await valueExists(key);
if (exists) { if (exists) {
const data = await RedisUtils.getValue(key); const data = await getValue(key);
res.setHeader("Cache-Status", "hit"); res.setHeader("Cache-Status", "hit");
return res.status(200).json({ return res.status(200).json({
@ -59,7 +59,7 @@ export default async function handler(req, res) {
message: "Unknown Map Hash", message: "Unknown Map Hash",
}); });
} }
await RedisUtils.setValue(key, starCount); await setValue(key, starCount);
console.log( console.log(
`[Cache]: Cached BL Star Count for hash ${mapHash} in ${ `[Cache]: Cached BL Star Count for hash ${mapHash} in ${
Date.now() - before Date.now() - before

@ -1,6 +1,10 @@
import fetch from "node-fetch"; import fetch from "node-fetch";
import sharp from "sharp"; import sharp from "sharp";
import RedisUtils from "../../../../src/utils/redisUtils"; import {
getValue,
setValue,
valueExists,
} from "../../../../src/utils/redisUtils";
const KEY = "BS_MAP_ART_"; const KEY = "BS_MAP_ART_";
@ -14,9 +18,9 @@ export default async function handler(req, res) {
const mapHash = req.query.hash.replace("custom_level_", "").toLowerCase(); const mapHash = req.query.hash.replace("custom_level_", "").toLowerCase();
const ext = req.query.ext || "jpg"; const ext = req.query.ext || "jpg";
const exists = await RedisUtils.exists(`${KEY}${mapHash}`.replace(" ", "")); const exists = await valueExists(`${KEY}${mapHash}`.replace(" ", ""));
if (exists) { if (exists) {
const data = await RedisUtils.getValue(`${KEY}${mapHash}`); const data = await getValue(`${KEY}${mapHash}`);
const buffer = Buffer.from(data, "base64"); const buffer = Buffer.from(data, "base64");
res.writeHead(200, { res.writeHead(200, {
"Content-Type": "image/" + ext, "Content-Type": "image/" + ext,
@ -39,7 +43,7 @@ export default async function handler(req, res) {
buffer = await sharp(buffer).resize(400, 400).toBuffer(); buffer = await sharp(buffer).resize(400, 400).toBuffer();
const bytes = buffer.toString("base64"); const bytes = buffer.toString("base64");
await RedisUtils.setValue(`${KEY}${mapHash}`.replace(" ", ""), bytes); await setValue(`${KEY}${mapHash}`.replace(" ", ""), bytes);
console.log( console.log(
`[Cache]: Cached BS Song Art for hash ${mapHash} in ${ `[Cache]: Cached BS Song Art for hash ${mapHash} in ${
Date.now() - before Date.now() - before

@ -1,9 +1,9 @@
import Utils from "../../../utils/utils"; import { getMapData } from "../../../src/helpers/beatSaverHelpers";
export default async function handler(req, res) { export default async function handler(req, res) {
const mapHash = req.query.hash; const mapHash = req.query.hash;
const mapData = await Utils.getMapData(mapHash.replace("custom_level_", "")); const mapData = await getMapData(mapHash);
if (mapData === undefined) { if (mapData === undefined) {
// Check if a map hash was provided // Check if a map hash was provided
return res.status(404).json({ return res.status(404).json({

@ -1,6 +1,6 @@
import fetch from "node-fetch"; import fetch from "node-fetch";
import WebsiteTypes from "../../../src/consts/LeaderboardType"; import WebsiteTypes from "../../../src/consts/LeaderboardType";
import RedisUtils from "../../../src/utils/redisUtils"; import { getValue, setValue, valueExists } from "../../../src/utils/redisUtils";
import { diffToScoreSaberDiff } from "../../../src/utils/scoreSaberUtils"; import { diffToScoreSaberDiff } from "../../../src/utils/scoreSaberUtils";
const KEY = "SS_MAP_STAR_"; const KEY = "SS_MAP_STAR_";
@ -17,9 +17,9 @@ export default async function handler(req, res) {
const characteristic = req.query.characteristic; const characteristic = req.query.characteristic;
const key = `${KEY}${difficulty}-${characteristic}-${mapHash}`; const key = `${KEY}${difficulty}-${characteristic}-${mapHash}`;
const exists = await RedisUtils.exists(key); const exists = await valueExists(key);
if (exists) { if (exists) {
const data = await RedisUtils.getValue(key); const data = await getValue(key);
res.setHeader("Cache-Status", "hit"); res.setHeader("Cache-Status", "hit");
return res.status(200).json({ return res.status(200).json({
@ -55,7 +55,7 @@ export default async function handler(req, res) {
message: "Unknown Map Hash", message: "Unknown Map Hash",
}); });
} }
await RedisUtils.setValue(key, starCount); await setValue(key, starCount);
console.log( console.log(
`[Cache]: Cached SS Star Count for hash ${mapHash} in ${ `[Cache]: Cached SS Star Count for hash ${mapHash} in ${
Date.now() - before Date.now() - before

@ -1,7 +1,7 @@
import fetch from "node-fetch"; import fetch from "node-fetch";
import sharp from "sharp"; import sharp from "sharp";
import { isValidSteamId } from "../../src/helpers/validateSteamId"; import { isValidSteamId } from "../../src/helpers/validateSteamId";
import RedisUtils from "../../src/utils/redisUtils"; import { getValue, setValue, valueExists } from "../../src/utils/redisUtils";
const KEY = "STEAM_AVATAR_"; const KEY = "STEAM_AVATAR_";
const ext = "jpg"; const ext = "jpg";
@ -22,9 +22,9 @@ export default async function handler(req, res) {
}); });
} }
const exists = await RedisUtils.exists(`${KEY}${steamId}`); const exists = await valueExists(`${KEY}${steamId}`);
if (exists) { if (exists) {
const data = await RedisUtils.getValue(`${KEY}${steamId}`); const data = await getValue(`${KEY}${steamId}`);
const buffer = Buffer.from(data, "base64"); const buffer = Buffer.from(data, "base64");
res.writeHead(200, { res.writeHead(200, {
"Content-Type": "image/" + ext, "Content-Type": "image/" + ext,
@ -49,7 +49,7 @@ export default async function handler(req, res) {
buffer = await sharp(buffer).resize(400, 400).toBuffer(); buffer = await sharp(buffer).resize(400, 400).toBuffer();
const bytes = buffer.toString("base64"); const bytes = buffer.toString("base64");
await RedisUtils.setValue(`${KEY}${steamId}`, bytes); await setValue(`${KEY}${steamId}`, bytes);
console.log( console.log(
`[Cache]: Cached Avatar for id ${steamId} in ${Date.now() - before}ms` `[Cache]: Cached Avatar for id ${steamId} in ${Date.now() - before}ms`
); );

@ -1,18 +1,15 @@
export default class BeatLeaderCurve { function curve(acc, stars) {
static curve(acc, stars) { var l = 1 - (0.03 * (stars - 3.0)) / 11.0;
var l = 1 - (0.03 * (stars - 3.0)) / 11.0; var a = 0.96 * l;
var a = 0.96 * l; var f = 1.2 - (0.6 * stars) / 14.0;
var f = 1.2 - (0.6 * stars) / 14.0;
return Math.pow(Math.log10(l / (l - acc)) / Math.log10(l / (l - a)), f); return Math.pow(Math.log10(l / (l - acc)) / Math.log10(l / (l - a)), f);
} }
static getPP(acc, stars) { export function getBeatLeaderPP(acc, stars) {
if (stars === undefined || acc === undefined) { if (stars === undefined || acc === undefined) {
return undefined; return undefined;
} }
const pp = const pp = curve(acc / 100, stars - 0.5) * (stars + 0.5) * 42;
BeatLeaderCurve.curve(acc / 100, stars - 0.5) * (stars + 0.5) * 42; return Number.isNaN(pp) ? undefined : pp;
return Number.isNaN(pp) ? undefined : pp;
}
} }

@ -1,83 +1,79 @@
// Yoinked from https://github.com/Shurdoof/pp-calculator/blob/c24b5ca452119339928831d74e6d603fb17fd5ef/src/lib/pp/calculator.ts // Yoinked from https://github.com/Shurdoof/pp-calculator/blob/c24b5ca452119339928831d74e6d603fb17fd5ef/src/lib/pp/calculator.ts
// Thank for for this I have no fucking idea what the maths is doing but it works! // Thank for for this I have no fucking idea what the maths is doing but it works!
export default class ScoreSaberCurve {
static starMultiplier = 42.11;
static ppCurve = [
[1, 7],
[0.999, 6.24],
[0.9975, 5.31],
[0.995, 4.14],
[0.9925, 3.31],
[0.99, 2.73],
[0.9875, 2.31],
[0.985, 2.0],
[0.9825, 1.775],
[0.98, 1.625],
[0.9775, 1.515],
[0.975, 1.43],
[0.9725, 1.36],
[0.97, 1.3],
[0.965, 1.195],
[0.96, 1.115],
[0.955, 1.05],
[0.95, 1],
[0.94, 0.94],
[0.93, 0.885],
[0.92, 0.835],
[0.91, 0.79],
[0.9, 0.75],
[0.875, 0.655],
[0.85, 0.57],
[0.825, 0.51],
[0.8, 0.47],
[0.75, 0.4],
[0.7, 0.34],
[0.65, 0.29],
[0.6, 0.25],
[0.0, 0.0],
];
static clamp(value, min, max) { const starMultiplier = 42.11;
if (min !== null && value < min) { const ppCurve = [
return min; [1, 7],
[0.999, 6.24],
[0.9975, 5.31],
[0.995, 4.14],
[0.9925, 3.31],
[0.99, 2.73],
[0.9875, 2.31],
[0.985, 2.0],
[0.9825, 1.775],
[0.98, 1.625],
[0.9775, 1.515],
[0.975, 1.43],
[0.9725, 1.36],
[0.97, 1.3],
[0.965, 1.195],
[0.96, 1.115],
[0.955, 1.05],
[0.95, 1],
[0.94, 0.94],
[0.93, 0.885],
[0.92, 0.835],
[0.91, 0.79],
[0.9, 0.75],
[0.875, 0.655],
[0.85, 0.57],
[0.825, 0.51],
[0.8, 0.47],
[0.75, 0.4],
[0.7, 0.34],
[0.65, 0.29],
[0.6, 0.25],
[0.0, 0.0],
];
function clamp(value, min, max) {
if (min !== null && value < min) {
return min;
}
if (max !== null && value > max) {
return max;
}
return value;
}
function lerp(v0, v1, t) {
return v0 + t * (v1 - v0);
}
function calculatePPModifier(c1, c2, acc) {
const distance = (c2[0] - acc) / (c2[0] - c1[0]);
return lerp(c2[1], c1[1], distance);
}
function findPPModifier(acc, curve) {
acc = clamp(acc, 0, 100) / 100;
let prev = curve[1];
for (const item of curve) {
if (item[0] <= acc) {
return calculatePPModifier(item, prev, acc);
} }
prev = item;
if (max !== null && value > max) {
return max;
}
return value;
}
static lerp(v0, v1, t) {
return v0 + t * (v1 - v0);
}
static calculatePPModifier(c1, c2, acc) {
const distance = (c2[0] - acc) / (c2[0] - c1[0]);
return ScoreSaberCurve.lerp(c2[1], c1[1], distance);
}
static findPPModifier(acc, curve) {
acc = ScoreSaberCurve.clamp(acc, 0, 100) / 100;
let prev = curve[1];
for (const item of curve) {
if (item[0] <= acc) {
return ScoreSaberCurve.calculatePPModifier(item, prev, acc);
}
prev = item;
}
}
static getPP(acc, stars) {
const ppValue = stars * ScoreSaberCurve.starMultiplier;
const modifier = ScoreSaberCurve.findPPModifier(
acc,
ScoreSaberCurve.ppCurve
);
const finalPP = modifier * ppValue;
return Number.isNaN(finalPP) ? undefined : finalPP;
} }
} }
export function getScoreSaberPP(acc, stars) {
const ppValue = stars * starMultiplier;
const modifier = findPPModifier(acc, ppCurve);
const finalPP = modifier * ppValue;
return Number.isNaN(finalPP) ? undefined : finalPP;
}

@ -0,0 +1,42 @@
import { getValue, setValue, valueExists } from "../utils/redisUtils";
const BEATSAVER_MAP_API =
process.env.NEXT_PUBLIC_HTTP_PROXY +
"/https://api.beatsaver.com/maps/hash/%s";
const KEY = "BS_MAP_DATA_";
/**
* Gets a specified maps data from BeatSaver
*
* @param {string} hash
* @returns The map data
*/
export async function getMapData(hash) {
const mapHash = hash.replace("custom_level_", "").toLowerCase();
const key = `${KEY}${mapHash}`;
const exists = await valueExists(key);
if (exists) {
const data = await getValue(key);
return JSON.parse(data);
}
const before = Date.now();
const data = await fetch(BEATSAVER_MAP_API.replace("%s", mapHash), {
headers: {
"X-Requested-With": "BeatSaber Overlay",
},
});
if (data.status === 404) {
return undefined;
}
const json = await data.json();
await setValue(key, JSON.stringify(json));
console.log(
`[Cache]: Cached BS Map Data for hash ${mapHash} in ${
Date.now() - before
}ms`
);
return json;
}

@ -1,5 +1,5 @@
import { default as LeaderboardType } from "../consts/LeaderboardType"; import { default as LeaderboardType } from "../consts/LeaderboardType";
import RedisUtils from "../utils/redisUtils"; import { getValue, setValue, valueExists } from "../utils/redisUtils";
import Utils from "../utils/utils"; import Utils from "../utils/utils";
const KEY = "VALID_STEAM_ID_"; const KEY = "VALID_STEAM_ID_";
@ -8,7 +8,7 @@ const TO_CHECK = [
LeaderboardType.BeatLeader.ApiUrl.PlayerData, LeaderboardType.BeatLeader.ApiUrl.PlayerData,
]; ];
async function isValidSteamId(steamId) { export async function isValidSteamId(steamId) {
if (!steamId) { if (!steamId) {
return false; return false;
} }
@ -16,9 +16,9 @@ async function isValidSteamId(steamId) {
return false; return false;
} }
const exists = await RedisUtils.exists(`${KEY}${steamId}`); const exists = await valueExists(`${KEY}${steamId}`);
if (exists) { if (exists) {
const data = await RedisUtils.getValue(`${KEY}${steamId}`); const data = await getValue(`${KEY}${steamId}`);
return Boolean(data); return Boolean(data);
} }
@ -32,13 +32,9 @@ async function isValidSteamId(steamId) {
} }
} }
await RedisUtils.setValue(`${KEY}${steamId}`, valid); await setValue(`${KEY}${steamId}`, valid);
console.log( console.log(
`[Cache]: Cached Steam ID for id ${steamId} in ${Date.now() - before}ms` `[Cache]: Cached Steam ID for id ${steamId} in ${Date.now() - before}ms`
); );
return valid; return valid;
} }
module.exports = {
isValidSteamId,
};

@ -8,7 +8,7 @@ const client = new Redis({
}); });
client.connect().catch(() => {}); client.connect().catch(() => {});
async function setValue(key, value, expireAt = 86400) { export async function setValue(key, value, expireAt = 86400) {
if (client.status === "close" || client.status === "end") { if (client.status === "close" || client.status === "end") {
await client.connect().catch(() => {}); await client.connect().catch(() => {});
} }
@ -16,7 +16,7 @@ async function setValue(key, value, expireAt = 86400) {
await client.set(key, value, "EX", expireAt); await client.set(key, value, "EX", expireAt);
} }
async function getValue(key) { export async function getValue(key) {
if (client.status === "close" || client.status === "end") { if (client.status === "close" || client.status === "end") {
await client.connect().catch(() => {}); await client.connect().catch(() => {});
} }
@ -34,7 +34,7 @@ async function getValue(key) {
return maybe; return maybe;
} }
async function exists(key) { export async function valueExists(key) {
if (client.status === "close" || client.status === "end") { if (client.status === "close" || client.status === "end") {
await client.connect().catch(() => {}); await client.connect().catch(() => {});
} }
@ -51,9 +51,3 @@ async function exists(key) {
const maybe = await yes; const maybe = await yes;
return maybe == 1 ? true : false; return maybe == 1 ? true : false;
} }
module.exports = {
getValue,
setValue,
exists,
};

@ -1,8 +1,4 @@
function diffToScoreSaberDiff(diff) { export function diffToScoreSaberDiff(diff) {
console.log(
"🚀 ~ file: scoreSaberUtils.js ~ line 2 ~ diffToScoreSaberDiff ~ diff",
diff
);
switch (diff) { switch (diff) {
case "Easy": { case "Easy": {
return 1; return 1;
@ -24,7 +20,3 @@ function diffToScoreSaberDiff(diff) {
} }
} }
} }
module.exports = {
diffToScoreSaberDiff,
};

@ -1,6 +1,6 @@
import { default as LeaderboardType } from "../consts/LeaderboardType"; import { default as LeaderboardType } from "../consts/LeaderboardType";
import BeatLeaderCurve from "../curve/BeatLeaderCurve"; import { getBeatLeaderPP } from "../curve/BeatLeaderCurve";
import ScoreSaberCurve from "../curve/ScoreSaberCurve"; import { getScoreSaberPP } from "../curve/ScoreSaberCurve";
export default class Utils { export default class Utils {
/** /**
@ -32,10 +32,10 @@ export default class Utils {
static calculatePP(stars, acc, type) { static calculatePP(stars, acc, type) {
if (type === "BeatLeader") { if (type === "BeatLeader") {
return BeatLeaderCurve.getPP(acc, stars); return getBeatLeaderPP(acc, stars);
} }
if (type === "ScoreSaber") { if (type === "ScoreSaber") {
return ScoreSaberCurve.getPP(acc, stars); return getScoreSaberPP(acc, stars);
} }
return undefined; return undefined;
} }

@ -1,36 +0,0 @@
const mapCache = new Map();
module.exports = {
BEATSAVER_MAP_API:
process.env.NEXT_PUBLIC_HTTP_PROXY +
"/https://api.beatsaver.com/maps/hash/%s",
/**
* Gets a specified maps data from BeatSaver
*
* @param {string} hash
* @returns The map data
*/
async getMapData(hash) {
hash = this.BEATSAVER_MAP_API.replace("%s", hash);
if (mapCache.has(hash)) {
// Return from cache
return mapCache.get(hash);
}
const data = await fetch(hash, {
headers: {
origin: "Fascinated Overlay",
},
});
if (data.status === 404) {
return undefined;
}
const json = await data.json();
mapCache.set(hash, json);
setTimeout(() => {
mapCache.delete(hash);
}, 60 * 60 * 1000); // 1h
return json;
},
};