many many change
This commit is contained in:
parent
f87940c01e
commit
82d565f130
@ -1,6 +1,6 @@
|
||||
import fetch from "node-fetch";
|
||||
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_";
|
||||
|
||||
@ -16,9 +16,9 @@ export default async function handler(req, res) {
|
||||
const characteristic = req.query.characteristic;
|
||||
|
||||
const key = `${KEY}${difficulty}-${characteristic}-${mapHash}`;
|
||||
const exists = await RedisUtils.exists(key);
|
||||
const exists = await valueExists(key);
|
||||
if (exists) {
|
||||
const data = await RedisUtils.getValue(key);
|
||||
const data = await getValue(key);
|
||||
res.setHeader("Cache-Status", "hit");
|
||||
|
||||
return res.status(200).json({
|
||||
@ -59,7 +59,7 @@ export default async function handler(req, res) {
|
||||
message: "Unknown Map Hash",
|
||||
});
|
||||
}
|
||||
await RedisUtils.setValue(key, starCount);
|
||||
await setValue(key, starCount);
|
||||
console.log(
|
||||
`[Cache]: Cached BL Star Count for hash ${mapHash} in ${
|
||||
Date.now() - before
|
||||
|
@ -1,6 +1,10 @@
|
||||
import fetch from "node-fetch";
|
||||
import sharp from "sharp";
|
||||
import RedisUtils from "../../../../src/utils/redisUtils";
|
||||
import {
|
||||
getValue,
|
||||
setValue,
|
||||
valueExists,
|
||||
} from "../../../../src/utils/redisUtils";
|
||||
|
||||
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 ext = req.query.ext || "jpg";
|
||||
|
||||
const exists = await RedisUtils.exists(`${KEY}${mapHash}`.replace(" ", ""));
|
||||
const exists = await valueExists(`${KEY}${mapHash}`.replace(" ", ""));
|
||||
if (exists) {
|
||||
const data = await RedisUtils.getValue(`${KEY}${mapHash}`);
|
||||
const data = await getValue(`${KEY}${mapHash}`);
|
||||
const buffer = Buffer.from(data, "base64");
|
||||
res.writeHead(200, {
|
||||
"Content-Type": "image/" + ext,
|
||||
@ -39,7 +43,7 @@ export default async function handler(req, res) {
|
||||
buffer = await sharp(buffer).resize(400, 400).toBuffer();
|
||||
const bytes = buffer.toString("base64");
|
||||
|
||||
await RedisUtils.setValue(`${KEY}${mapHash}`.replace(" ", ""), bytes);
|
||||
await setValue(`${KEY}${mapHash}`.replace(" ", ""), bytes);
|
||||
console.log(
|
||||
`[Cache]: Cached BS Song Art for hash ${mapHash} in ${
|
||||
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) {
|
||||
const mapHash = req.query.hash;
|
||||
|
||||
const mapData = await Utils.getMapData(mapHash.replace("custom_level_", ""));
|
||||
const mapData = await getMapData(mapHash);
|
||||
if (mapData === undefined) {
|
||||
// Check if a map hash was provided
|
||||
return res.status(404).json({
|
||||
|
@ -1,6 +1,6 @@
|
||||
import fetch from "node-fetch";
|
||||
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";
|
||||
|
||||
const KEY = "SS_MAP_STAR_";
|
||||
@ -17,9 +17,9 @@ export default async function handler(req, res) {
|
||||
const characteristic = req.query.characteristic;
|
||||
|
||||
const key = `${KEY}${difficulty}-${characteristic}-${mapHash}`;
|
||||
const exists = await RedisUtils.exists(key);
|
||||
const exists = await valueExists(key);
|
||||
if (exists) {
|
||||
const data = await RedisUtils.getValue(key);
|
||||
const data = await getValue(key);
|
||||
res.setHeader("Cache-Status", "hit");
|
||||
|
||||
return res.status(200).json({
|
||||
@ -55,7 +55,7 @@ export default async function handler(req, res) {
|
||||
message: "Unknown Map Hash",
|
||||
});
|
||||
}
|
||||
await RedisUtils.setValue(key, starCount);
|
||||
await setValue(key, starCount);
|
||||
console.log(
|
||||
`[Cache]: Cached SS Star Count for hash ${mapHash} in ${
|
||||
Date.now() - before
|
||||
|
@ -1,7 +1,7 @@
|
||||
import fetch from "node-fetch";
|
||||
import sharp from "sharp";
|
||||
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 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) {
|
||||
const data = await RedisUtils.getValue(`${KEY}${steamId}`);
|
||||
const data = await getValue(`${KEY}${steamId}`);
|
||||
const buffer = Buffer.from(data, "base64");
|
||||
res.writeHead(200, {
|
||||
"Content-Type": "image/" + ext,
|
||||
@ -49,7 +49,7 @@ export default async function handler(req, res) {
|
||||
buffer = await sharp(buffer).resize(400, 400).toBuffer();
|
||||
const bytes = buffer.toString("base64");
|
||||
|
||||
await RedisUtils.setValue(`${KEY}${steamId}`, bytes);
|
||||
await setValue(`${KEY}${steamId}`, bytes);
|
||||
console.log(
|
||||
`[Cache]: Cached Avatar for id ${steamId} in ${Date.now() - before}ms`
|
||||
);
|
||||
|
@ -1,18 +1,15 @@
|
||||
export default class BeatLeaderCurve {
|
||||
static curve(acc, stars) {
|
||||
var l = 1 - (0.03 * (stars - 3.0)) / 11.0;
|
||||
var a = 0.96 * l;
|
||||
var f = 1.2 - (0.6 * stars) / 14.0;
|
||||
function curve(acc, stars) {
|
||||
var l = 1 - (0.03 * (stars - 3.0)) / 11.0;
|
||||
var a = 0.96 * l;
|
||||
var f = 1.2 - (0.6 * stars) / 14.0;
|
||||
|
||||
return Math.pow(Math.log10(l / (l - acc)) / Math.log10(l / (l - a)), f);
|
||||
}
|
||||
|
||||
static getPP(acc, stars) {
|
||||
if (stars === undefined || acc === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const pp =
|
||||
BeatLeaderCurve.curve(acc / 100, stars - 0.5) * (stars + 0.5) * 42;
|
||||
return Number.isNaN(pp) ? undefined : pp;
|
||||
}
|
||||
return Math.pow(Math.log10(l / (l - acc)) / Math.log10(l / (l - a)), f);
|
||||
}
|
||||
|
||||
export function getBeatLeaderPP(acc, stars) {
|
||||
if (stars === undefined || acc === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const pp = curve(acc / 100, stars - 0.5) * (stars + 0.5) * 42;
|
||||
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
|
||||
// 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) {
|
||||
if (min !== null && value < min) {
|
||||
return min;
|
||||
const starMultiplier = 42.11;
|
||||
const 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],
|
||||
];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
prev = item;
|
||||
}
|
||||
}
|
||||
|
||||
export function getScoreSaberPP(acc, stars) {
|
||||
const ppValue = stars * starMultiplier;
|
||||
const modifier = findPPModifier(acc, ppCurve);
|
||||
|
||||
const finalPP = modifier * ppValue;
|
||||
return Number.isNaN(finalPP) ? undefined : finalPP;
|
||||
}
|
||||
|
42
src/helpers/beatSaverHelpers.js
Normal file
42
src/helpers/beatSaverHelpers.js
Normal file
@ -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 RedisUtils from "../utils/redisUtils";
|
||||
import { getValue, setValue, valueExists } from "../utils/redisUtils";
|
||||
import Utils from "../utils/utils";
|
||||
|
||||
const KEY = "VALID_STEAM_ID_";
|
||||
@ -8,7 +8,7 @@ const TO_CHECK = [
|
||||
LeaderboardType.BeatLeader.ApiUrl.PlayerData,
|
||||
];
|
||||
|
||||
async function isValidSteamId(steamId) {
|
||||
export async function isValidSteamId(steamId) {
|
||||
if (!steamId) {
|
||||
return false;
|
||||
}
|
||||
@ -16,9 +16,9 @@ async function isValidSteamId(steamId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const exists = await RedisUtils.exists(`${KEY}${steamId}`);
|
||||
const exists = await valueExists(`${KEY}${steamId}`);
|
||||
if (exists) {
|
||||
const data = await RedisUtils.getValue(`${KEY}${steamId}`);
|
||||
const data = await getValue(`${KEY}${steamId}`);
|
||||
return Boolean(data);
|
||||
}
|
||||
|
||||
@ -32,13 +32,9 @@ async function isValidSteamId(steamId) {
|
||||
}
|
||||
}
|
||||
|
||||
await RedisUtils.setValue(`${KEY}${steamId}`, valid);
|
||||
await setValue(`${KEY}${steamId}`, valid);
|
||||
console.log(
|
||||
`[Cache]: Cached Steam ID for id ${steamId} in ${Date.now() - before}ms`
|
||||
);
|
||||
return valid;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isValidSteamId,
|
||||
};
|
||||
|
@ -8,7 +8,7 @@ const client = new Redis({
|
||||
});
|
||||
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") {
|
||||
await client.connect().catch(() => {});
|
||||
}
|
||||
@ -16,7 +16,7 @@ async function setValue(key, value, expireAt = 86400) {
|
||||
await client.set(key, value, "EX", expireAt);
|
||||
}
|
||||
|
||||
async function getValue(key) {
|
||||
export async function getValue(key) {
|
||||
if (client.status === "close" || client.status === "end") {
|
||||
await client.connect().catch(() => {});
|
||||
}
|
||||
@ -34,7 +34,7 @@ async function getValue(key) {
|
||||
return maybe;
|
||||
}
|
||||
|
||||
async function exists(key) {
|
||||
export async function valueExists(key) {
|
||||
if (client.status === "close" || client.status === "end") {
|
||||
await client.connect().catch(() => {});
|
||||
}
|
||||
@ -51,9 +51,3 @@ async function exists(key) {
|
||||
const maybe = await yes;
|
||||
return maybe == 1 ? true : false;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getValue,
|
||||
setValue,
|
||||
exists,
|
||||
};
|
||||
|
@ -1,8 +1,4 @@
|
||||
function diffToScoreSaberDiff(diff) {
|
||||
console.log(
|
||||
"🚀 ~ file: scoreSaberUtils.js ~ line 2 ~ diffToScoreSaberDiff ~ diff",
|
||||
diff
|
||||
);
|
||||
export function diffToScoreSaberDiff(diff) {
|
||||
switch (diff) {
|
||||
case "Easy": {
|
||||
return 1;
|
||||
@ -24,7 +20,3 @@ function diffToScoreSaberDiff(diff) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
diffToScoreSaberDiff,
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { default as LeaderboardType } from "../consts/LeaderboardType";
|
||||
import BeatLeaderCurve from "../curve/BeatLeaderCurve";
|
||||
import ScoreSaberCurve from "../curve/ScoreSaberCurve";
|
||||
import { getBeatLeaderPP } from "../curve/BeatLeaderCurve";
|
||||
import { getScoreSaberPP } from "../curve/ScoreSaberCurve";
|
||||
|
||||
export default class Utils {
|
||||
/**
|
||||
@ -32,10 +32,10 @@ export default class Utils {
|
||||
|
||||
static calculatePP(stars, acc, type) {
|
||||
if (type === "BeatLeader") {
|
||||
return BeatLeaderCurve.getPP(acc, stars);
|
||||
return getBeatLeaderPP(acc, stars);
|
||||
}
|
||||
if (type === "ScoreSaber") {
|
||||
return ScoreSaberCurve.getPP(acc, stars);
|
||||
return getScoreSaberPP(acc, stars);
|
||||
}
|
||||
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;
|
||||
},
|
||||
};
|
Reference in New Issue
Block a user