diff --git a/package.json b/package.json index 7d0e779..79911f5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "scoresaberutils-script", "version": "1.0.0", - "description": "The TamperMonkey script for ScoreSaber Utils", + "description": "TamperMonkey script for ScoreSaber Utils", "scripts": { "build": "webpack --config webpack.config.js", "dev": "webpack --config webpack.config.js --watch" diff --git a/src/common/page-utils.ts b/src/common/page-utils.ts index 9467784..87319ea 100644 --- a/src/common/page-utils.ts +++ b/src/common/page-utils.ts @@ -24,6 +24,9 @@ export function pageChangeCallback(callback: (path: string) => void) { * @param baseClass The base class of the element */ export function getSvelteClass(baseClass: string): string | null { + if (!baseClass.startsWith(".")) { + baseClass = `.${baseClass.split(" ").join(".")}`; + } const element = document.querySelector(baseClass); if (!element) { return null; diff --git a/src/common/player.ts b/src/common/player.ts index ff9cb00..67d26a6 100644 --- a/src/common/player.ts +++ b/src/common/player.ts @@ -1,4 +1,4 @@ -import {API_URL} from "../consts"; +import { API_URL } from "../consts"; /** * Gets a player from the ScoreSaber Utils API @@ -8,13 +8,15 @@ import {API_URL} from "../consts"; export async function getPlayer(id: string) { const response = await fetch(`${API_URL}/account/${id}`); + const json = await response.json(); + // There was an error fetching the player if (!response.ok) { - throw new Error("Failed to fetch player"); + throw new Error(json.message); } // Return the player's data - return response.json(); + return json; } /** @@ -23,4 +25,4 @@ export async function getPlayer(id: string) { export function getPlayerIdFromUrl(): string { const url = new URL(location.href); return url.pathname.split("/")[2]; -} \ No newline at end of file +} diff --git a/src/pages/impl/player-page.ts b/src/pages/impl/player-page.ts index 64773f6..0ef0e32 100644 --- a/src/pages/impl/player-page.ts +++ b/src/pages/impl/player-page.ts @@ -1,6 +1,6 @@ import Page from "../page"; -import {getElement, getSvelteClass} from "../../common/page-utils"; -import {getPlayer, getPlayerIdFromUrl} from "../../common/player"; +import { getElement, getSvelteClass } from "../../common/page-utils"; +import { getPlayer, getPlayerIdFromUrl } from "../../common/player"; export default class PlayerPage extends Page { constructor() { @@ -8,16 +8,35 @@ export default class PlayerPage extends Page { } public async onLoad() { + let loadingElement; + let titleElement; try { // Wait for the title element to load, so we know the page is fully loaded - const titleElement = await getElement(".title.is-5.player.has-text-centered-mobile", 250); + titleElement = await getElement( + ".title.is-5.player.has-text-centered-mobile", + ); + const id: string = getPlayerIdFromUrl(); - const id = getPlayerIdFromUrl(); - const player = await getPlayer(id); + loadingElement = await this.addLoadingElement(titleElement); + const player: any = await getPlayer(id); + loadingElement(); // Remove the loading element await this.addStats(player); // Add our custom stats } catch (error) { - console.error("Failed to load player page", error); + loadingElement(); // Remove the loading element + + if (error.message.includes("inactive")) { + await this.addLoadingElement( + titleElement, + "This player is inactive, no extra data available", + ); + } + if (error.message.includes("banned")) { + await this.addLoadingElement( + titleElement, + "This player is banned, no extra data available", + ); + } } } @@ -26,11 +45,11 @@ export default class PlayerPage extends Page { * * @param player the player to add stats for */ - private async addStats(player: any) { + private async addStats(player: any): Promise { await this.addStat( "+1 PP", `${player.rawPerGlobalPerformancePoints.toFixed(2)}pp`, - "Raw performance points to gain +1 global PP" + "Raw performance points to gain +1 global PP", ); } @@ -41,16 +60,53 @@ export default class PlayerPage extends Page { * @param value the value of the stat * @param hover the hover text of the stat */ - private async addStat(stat: string, value: string, hover?: string) { - const statsContainer = await getElement(".stats-container"); - const statElement = document.createElement("div"); - const svelteClass = getSvelteClass(".stats-container"); + private async addStat( + stat: string, + value: string, + hover?: string, + ): Promise { + const statsContainer: HTMLElement = await getElement(".stats-container"); + const statElement: HTMLDivElement = document.createElement("div"); + const svelteClass: string = getSvelteClass(".stats-container"); statElement.className = `stat-item ${svelteClass}`; statElement.innerHTML = ` ${stat} ${value}`; - statsContainer.appendChild(statElement); + statsContainer.appendChild(statElement); // Add the stat to the stats container } -} \ No newline at end of file + + /** + * Create a loading element to show the user + * + * @param element the element to append the loading element to + * @param text the text to show in the loading element + * @returns the loading element + */ + private async addLoadingElement( + element: HTMLElement, + text: string = "Loading SSU data...", + ): Promise<() => void> { + const svelteClass: string = getSvelteClass(element.className); + + // The divider element + const dividerElement: HTMLDivElement = document.createElement("div"); + dividerElement.className = `divider ${svelteClass}`; + + // The loading element + const loadingElement: HTMLSpanElement = document.createElement("span"); + loadingElement.className = `title-header ${svelteClass} font-size: 1rem;`; + loadingElement.style.alignSelf = "flex-end"; + loadingElement.innerHTML = ` +

${text}

`; + + element.appendChild(dividerElement); + element.appendChild(loadingElement); + + return () => { + dividerElement.remove(); + loadingElement.remove(); + }; + } +} diff --git a/src/pages/page.ts b/src/pages/page.ts index a068dde..f9df2f6 100644 --- a/src/pages/page.ts +++ b/src/pages/page.ts @@ -2,7 +2,7 @@ export default class Page { /** * The route of the page - * eg: /ranking + * eg: /ranking/ */ private readonly _route: string; @@ -13,7 +13,7 @@ export default class Page { /* * This gets called when the page is loaded */ - public onLoad() {} + public async onLoad() {} /** * The route of the page diff --git a/webpack.config.js b/webpack.config.js index aa7f69a..95cf089 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -27,7 +27,7 @@ module.exports = { author: "fascinated7 (discord)", "run-at": "document-end", match: "https://scoresaber.com/*", - version: `1.0.0-${process.env.GIT_REV.substring(0, 7) || "dev"}`, + version: `1.0.0-${process.env.GIT_REV ? process.env.GIT_REV.substring(0, 7) : "dev"}`, } }) ],