ScoreSaberUtils-Backend/scoresaber-utils.user.js

125 lines
3.7 KiB
JavaScript
Raw Normal View History

2024-04-25 06:11:06 +00:00
// ==UserScript==
// @name ScoreSaber Utils
// @namespace https://ssu.fascinated.cc
2024-04-25 19:05:51 +00:00
// @version 1.0.3
2024-04-25 06:11:06 +00:00
// @description Useful additions to ScoreSaber!
// @author Fascinated
// @match https://scoresaber.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=scoresaber.com
// @license MIT
// @updateURL https://git.fascinated.cc/Fascinated/ScoreSaberUtils-Backend/raw/branch/master/scoresaber-utils.user.js
// @downloadURL https://git.fascinated.cc/Fascinated/ScoreSaberUtils-Backend/raw/branch/master/scoresaber-utils.user.js
// @run-at document-end
2024-04-25 06:11:06 +00:00
// ==/UserScript==
/**
2024-04-25 07:09:59 +00:00
* Fetches data from an API endpoint.
2024-04-25 06:11:06 +00:00
*
2024-04-25 07:09:59 +00:00
* @param {string} url The URL of the API endpoint
* @returns {Promise<any>} The JSON response from the API
2024-04-25 06:11:06 +00:00
*/
2024-04-25 07:09:59 +00:00
async function fetchData(url) {
const response = await fetch(url);
2024-04-25 06:11:06 +00:00
return await response.json();
}
/**
2024-04-25 07:09:59 +00:00
* Inserts a stat into the specified container.
2024-04-25 06:11:06 +00:00
*
2024-04-25 07:09:59 +00:00
* @param {string} containerSelector The selector for the container to insert the stat into
2024-04-25 06:11:06 +00:00
* @param {string} stat The stat name
* @param {string} value The stat value
* @param {string} hoverText The hover text
*/
2024-04-25 07:09:59 +00:00
function addStat(containerSelector, stat, value, hoverText) {
const container = document.querySelector(containerSelector);
if (!container) return;
const svelteClass = container.classList.item(1);
2024-04-25 06:11:06 +00:00
const statElement = document.createElement("div");
statElement.className = `stat-item ${svelteClass}`;
statElement.innerHTML = `
2024-04-25 07:09:59 +00:00
<span class="stat-title ${svelteClass}">${stat}</span>
<span class="stat-spacer ${svelteClass}"></span>
<span class="stat-content ${svelteClass} has-hover" title="${hoverText}">${value}</span>
2024-04-25 06:11:06 +00:00
`;
2024-04-25 07:09:59 +00:00
container.appendChild(statElement);
2024-04-25 06:11:06 +00:00
}
2024-04-25 07:09:59 +00:00
/**
* Delays execution for the specified duration.
*
* @param {number} ms The duration to delay in milliseconds
* @returns {Promise<void>} A promise that resolves after the delay
2024-04-25 07:09:59 +00:00
*/
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
2024-04-25 07:09:59 +00:00
/**
* Loads ScoreSaber Utils data on player pages.
*/
async function loadPlayerData(path) {
if (!path) {
path = window.location.pathname;
}
path = path.replace("https://scoresaber.com", "");
2024-04-25 06:11:06 +00:00
const isPlayerPage = path.startsWith("/u/");
2024-04-25 07:09:59 +00:00
if (!isPlayerPage) {
// Only run on player pages
return;
}
2024-04-25 07:09:59 +00:00
// Wait for the stats container to load
while (!document.querySelector(".stats-container")) {
await sleep(250);
2024-04-25 06:11:06 +00:00
}
2024-04-25 07:09:59 +00:00
const playerId = path.split("/")[2];
// Get the title element
await sleep(250);
2024-04-25 07:09:59 +00:00
const titleElement = document.querySelector(".title.is-5.player.has-text-centered-mobile");
if (!titleElement) {
console.error("Failed to find title element");
return;
}
const svelteClass = titleElement.classList.item(1);
2024-04-25 07:09:59 +00:00
// Add a loading indicator
const loadingElement = document.createElement("span");
loadingElement.className = `title-header pp ${svelteClass}`;
loadingElement.textContent = "Loading ScoreSaber Utils Data...";
titleElement.appendChild(loadingElement);
try {
const playerData = await fetchData(`https://ssu.fascinated.cc/account/${playerId}`);
addStat(
".stats-container",
"+1 PP",
`${playerData.rawPerGlobalPerformancePoints.toFixed(2)}pp`,
"The amount of pp to increase the global pp by 1pp"
);
} catch (error) {
console.error("Failed to load player data:", error);
}
// Remove the loading indicator
loadingElement.remove();
}
2024-04-25 07:09:59 +00:00
loadPlayerData();
// Watch for URL changes
2024-04-25 19:05:51 +00:00
let previousUrl = "";
const observer = new MutationObserver(function (mutations) {
if (location.href !== previousUrl) {
previousUrl = location.href;
loadPlayerData(location.pathname);
2024-04-25 18:56:06 +00:00
}
2024-04-25 19:05:51 +00:00
});
const config = { subtree: true, childList: true };
observer.observe(document, config);