Add scoresaber-utils.user.js
This commit is contained in:
commit
5ba33056b6
123
scoresaber-utils.user.js
Normal file
123
scoresaber-utils.user.js
Normal file
@ -0,0 +1,123 @@
|
||||
// ==UserScript==
|
||||
// @name ScoreSaber Utils
|
||||
// @namespace https://ssu.fascinated.cc
|
||||
// @version 1.0.5
|
||||
// @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
|
||||
// ==/UserScript==
|
||||
|
||||
/**
|
||||
* Fetches data from an API endpoint.
|
||||
*
|
||||
* @param {string} url The URL of the API endpoint
|
||||
* @returns {Promise<any>} The JSON response from the API
|
||||
*/
|
||||
async function fetchData(url) {
|
||||
const response = await fetch(url);
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a stat into the specified container.
|
||||
*
|
||||
* @param {string} containerSelector The selector for the container to insert the stat into
|
||||
* @param {string} stat The stat name
|
||||
* @param {string} value The stat value
|
||||
* @param {string} hoverText The hover text
|
||||
*/
|
||||
function addStat(containerSelector, stat, value, hoverText) {
|
||||
const container = document.querySelector(containerSelector);
|
||||
if (!container) return;
|
||||
|
||||
const svelteClass = container.classList.item(1);
|
||||
|
||||
const statElement = document.createElement("div");
|
||||
statElement.className = `stat-item ${svelteClass}`;
|
||||
statElement.innerHTML = `
|
||||
<span class="stat-title ${svelteClass}">${stat}</span>
|
||||
<span class="stat-spacer ${svelteClass}"></span>
|
||||
<span class="stat-content ${svelteClass} has-hover" title="${hoverText}">${value}</span>
|
||||
`;
|
||||
container.appendChild(statElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads ScoreSaber Utils data on player pages.
|
||||
*/
|
||||
async function loadPlayerData(path) {
|
||||
if (!path) {
|
||||
path = window.location.pathname;
|
||||
}
|
||||
path = path.replace("https://scoresaber.com", "");
|
||||
|
||||
const isPlayerPage = path.startsWith("/u/");
|
||||
|
||||
if (!isPlayerPage) {
|
||||
// Only run on player pages
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for the stats container to load
|
||||
while (!document.querySelector(".stats-container")) {
|
||||
await sleep(250);
|
||||
}
|
||||
const playerId = path.split("/")[2];
|
||||
|
||||
// Get the title element
|
||||
await sleep(250);
|
||||
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);
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
// Watch for URL changes
|
||||
let previousUrl = "";
|
||||
const observer = new MutationObserver(function (mutations) {
|
||||
const currentUrl = location.pathname; // Get the current URL without parameters
|
||||
if (currentUrl !== previousUrl) {
|
||||
previousUrl = currentUrl;
|
||||
|
||||
loadPlayerData(currentUrl);
|
||||
}
|
||||
});
|
||||
const config = { subtree: true, childList: true };
|
||||
observer.observe(document, config);
|
Loading…
Reference in New Issue
Block a user