return null bio if the raw bio is null
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 1m20s
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 1m20s
This commit is contained in:
parent
2b8b135cf8
commit
ae19233ddf
@ -12,76 +12,96 @@
|
||||
// @run-at document-end
|
||||
// ==/UserScript==
|
||||
|
||||
let loaded = false;
|
||||
|
||||
/**
|
||||
* Fetches the player from ScoreSaber Utils.
|
||||
* Fetches data from an API endpoint.
|
||||
*
|
||||
* @param {string} id the player's ID
|
||||
* @returns the player's data
|
||||
* @param {string} url The URL of the API endpoint
|
||||
* @returns The JSON response from the API
|
||||
*/
|
||||
async function fetchPlayer(id) {
|
||||
const response = await fetch(`https://ssu.fascinated.cc/account/${id}`);
|
||||
async function fetchData(url) {
|
||||
const response = await fetch(url);
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the player page logic.
|
||||
*/
|
||||
async function playerPage() {
|
||||
console.log("Player page loaded!");
|
||||
const id = window.location.pathname.split("/")[2];
|
||||
const player = await fetchPlayer(id);
|
||||
|
||||
addStat(
|
||||
"+1 PP",
|
||||
player.rawPerGlobalPerformancePoints.toFixed(2) + "pp",
|
||||
"The amount of pp to increase the global pp by 1pp"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a stat into the player's stats.
|
||||
* 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(stat, value, hoverText) {
|
||||
const statsElement = document.getElementsByClassName("stats-container")[0];
|
||||
const svelteClass = statsElement.getAttribute("class").split(" ")[1];
|
||||
function addStat(containerSelector, stat, value, hoverText) {
|
||||
const container = document.querySelector(containerSelector);
|
||||
if (!container) return;
|
||||
|
||||
const svelteClass = container.getAttribute("class").split(" ")[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>
|
||||
<span class="stat-title ${svelteClass}">${stat}</span>
|
||||
<span class="stat-spacer ${svelteClass}"></span>
|
||||
<span class="stat-content ${svelteClass} has-hover" title="${hoverText}">${value}</span>
|
||||
`;
|
||||
statsElement.appendChild(statElement);
|
||||
container.appendChild(statElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delays execution for the specified duration.
|
||||
*
|
||||
* @param {number} ms The duration to delay in milliseconds
|
||||
* @returns A promise that resolves after the delay
|
||||
*/
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function load() {
|
||||
"use strict";
|
||||
if (loaded) return;
|
||||
|
||||
/**
|
||||
* Loads ScoreSaber Utils data on player pages.
|
||||
*/
|
||||
async function loadPlayerData() {
|
||||
const path = window.location.pathname;
|
||||
const isPlayerPage = path.startsWith("/u/");
|
||||
|
||||
if (isPlayerPage) {
|
||||
// Wait for the stats container to load
|
||||
while (document.getElementsByClassName("stats-container").length === 0) {
|
||||
await sleep(250);
|
||||
}
|
||||
|
||||
playerPage();
|
||||
if (!isPlayerPage) {
|
||||
// Only run on player pages
|
||||
return;
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
// Wait for the stats container to load
|
||||
while (!document.querySelector(".stats-container")) {
|
||||
await sleep(250);
|
||||
}
|
||||
const playerId = path.split("/")[2];
|
||||
|
||||
// Get the title element
|
||||
const titleElement = document.querySelector(".title.is-5.player.has-text-centered-mobile");
|
||||
if (!titleElement) return;
|
||||
const svelteClass = titleElement
|
||||
.getAttribute("class")
|
||||
.split(" ")
|
||||
.find((c) => c.startsWith("svelte"));
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
load();
|
||||
loadPlayerData();
|
||||
|
@ -163,6 +163,9 @@ public class Account {
|
||||
* @return The bio.
|
||||
*/
|
||||
public static Bio fromRaw(String raw) {
|
||||
if (raw == null || raw.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return new Bio(
|
||||
raw.split("\n"),
|
||||
raw.replaceAll("<[^>]*>", "").split("\n")
|
||||
|
Loading…
x
Reference in New Issue
Block a user