// ==UserScript==
// @name Nitro Type Ban Check (NTL)
// @namespace http://tampermonkey.net/
// @version 1.5
// @description Checks if users are banned or flagged from the ntleaderboards website. Made by [NHS]✨superjoelzy✨ based on the original script by dph
// @match https://www.nitrotype.com/team/*
// @match https://www.nitrotype.com/racer/*
// @match https://www.nitrotype.com/leagues
// @grant GM_xmlhttpRequest
// @connect ntleaderboards.com
// @license MIT
// ==/UserScript==
(function () {
'use strict';
console.log("[DEBUG] Script initialized for all pages.");
function init() {
const path = window.location.pathname;
if (path.startsWith("/team")) {
console.log("[DEBUG] Detected /team page.");
handleTeamPage();
} else if (path.startsWith("/racer")) {
console.log("[DEBUG] Detected /racer page.");
handleRacerPage();
} else if (path === "/leagues") {
console.log("[DEBUG] Detected /leagues page.");
handleLeaguesPage();
}
}
// ========================
// Shared Functions
// ========================
function fetchAndDisplayStatus(username, element, context, callback = null) {
const url = `https://ntleaderboards.com/is_user_banned/${username}`;
console.log(`[DEBUG] Fetching status for: ${username} (Context: ${context})`);
GM_xmlhttpRequest({
method: "GET",
url: url,
onload: function (response) {
if (response.status === 200) {
const data = response.responseText.trim();
console.log(`[DEBUG] Status fetched for ${username}: ${data}`);
let status, color;
if (data === "N") {
status = "Legit";
color = "rgb(0, 255, 0)";
} else if (data === "Y (ban)") {
status = "Banned";
color = "rgb(255, 165, 0)";
} else if (data === "Y (ban+flag)") {
status = "Banned (Flagged)";
color = "rgb(255, 0, 0)";
} else {
status = "Unknown";
color = "rgb(255, 255, 0)";
}
if (callback) callback(status, color);
else updateMemberStatus(element, status, color);
} else {
console.error(`[DEBUG] Failed to fetch status for ${username}. HTTP Status: ${response.status}`);
}
},
onerror: function (error) {
console.error(`[DEBUG] Error fetching status for ${username}:`, error);
}
});
}
function updateMemberStatus(element, status, color) {
let statusField;
if (element.classList.contains('table-row')) {
statusField = element.querySelector('.tsi.tc-lemon.tsxs');
} else if (element.classList.contains('profile-title')) {
statusField = element;
} else {
const allRows = document.querySelectorAll('.table-row');
allRows.forEach(row => {
const racerContainer = row.querySelector('.player-name--container');
if (racerContainer && racerContainer.getAttribute('title') === element.getAttribute('title')) {
statusField = row.querySelector('.tsi.tc-lemon.tsxs');
}
});
}
if (!statusField) return;
const statusLabel = document.createElement('span');
statusLabel.textContent = ` ${status}`;
statusLabel.style.color = color;
statusLabel.style.marginLeft = "5px";
const existing = statusField.querySelector('.status-label');
if (existing) existing.remove();
statusLabel.classList.add('status-label');
statusField.appendChild(statusLabel);
}
function observeDOMChanges(callback) {
const observer = new MutationObserver(() => {
callback();
});
observer.observe(document.body, { childList: true, subtree: true });
}
// ========================
// /team Page Implementation
// ========================
const TEAM_API_URL = "https://www.nitrotype.com/api/v2/teams/";
const processedMembers = new Set();
function handleTeamPage() {
const teamSlug = getTeamSlugFromUrl();
if (teamSlug) {
fetchTeamData(teamSlug);
} else {
console.error("[DEBUG] No team slug found in URL.");
}
}
function getTeamSlugFromUrl() {
const pathParts = window.location.pathname.split('/');
return pathParts[pathParts.length - 1];
}
function fetchTeamData(teamSlug) {
const url = `${TEAM_API_URL}${teamSlug}`;
GM_xmlhttpRequest({
method: "GET",
url: url,
onload: function (response) {
if (response.status === 200) {
const teamData = JSON.parse(response.responseText);
if (teamData && teamData.results && teamData.results.members) {
processTeamMembers(teamData.results.members);
}
}
},
onerror: function (error) {
console.error("Error fetching team data:", error);
}
});
}
function processTeamMembers(members) {
members.forEach(member => {
const username = member.username;
const displayName = member.displayName || username;
const memberElement = findMemberElement(displayName);
if (memberElement && !processedMembers.has(username)) {
processedMembers.add(username);
fetchAndDisplayStatus(username, memberElement, "Team");
}
});
}
function findMemberElement(displayName) {
const elements = document.querySelectorAll('.player-name--container[title]');
return Array.from(elements).find(element => element.getAttribute('title').trim() === displayName.trim());
}
// ========================
// /racer Page Implementation
// ========================
function handleRacerPage() {
const username = getUsernameFromUrl();
if (username) {
const profileTitleElement = document.querySelector('.profile-title');
if (profileTitleElement) {
const statusSpan = document.createElement('span');
statusSpan.style.marginLeft = "5px";
fetchAndDisplayStatus(username, profileTitleElement, "Racer", (status, color) => {
statusSpan.textContent = ` ${status}`;
statusSpan.style.color = color;
profileTitleElement.appendChild(statusSpan);
});
} else {
console.log("[DEBUG] Profile title not found. Observing DOM changes...");
observeDOMChanges(() => {
if (document.querySelector('.profile-title')) {
handleRacerPage();
}
});
}
}
}
function getUsernameFromUrl() {
const pathParts = window.location.pathname.split('/');
return pathParts[pathParts.length - 1];
}
// ========================
// /leagues Page Implementation
// ========================
async function handleLeaguesPage() {
const NT_TOKEN = `Bearer ${localStorage.getItem("player_token")}`;
async function fetchUserActivity() {
try {
const response = await fetch("https://www.nitrotype.com/api/v2/leagues/user/activity", {
headers: {
accept: "application/json, text/plain, */*",
authorization: NT_TOKEN,
},
referrer: "https://www.nitrotype.com/leagues",
referrerPolicy: "same-origin",
method: "GET",
mode: "cors",
credentials: "include"
});
const data = await response.json();
if (data.status === "OK") {
const standings = data.results.standings;
standings.sort((a, b) => b.experience - a.experience);
const userMap = {};
standings.forEach(user => {
const { displayName, username } = user;
userMap[displayName || username] = username;
});
return userMap;
} else {
console.error("[DEBUG] Error: ", data.status);
return null;
}
} catch (error) {
console.error("[DEBUG] Fetch error: ", error);
return null;
}
}
const userMap = await fetchUserActivity();
if (userMap) {
setTimeout(() => { observeDOMChangesLeagues(userMap); }, 100);
} else {
console.error("[DEBUG] Failed to fetch user activity.");
}
}
function processLeaderboardRows(rows, userMap) {
rows.forEach(row => {
const playerElement = row.querySelector('.player-name--container[title]');
if (!playerElement) return;
const displayName = playerElement.getAttribute('title');
const username = userMap[displayName];
if (username && !row.classList.contains('status-processed')) {
console.log(`[DEBUG] Processing user: ${username} (Display: ${displayName})`);
fetchAndDisplayStatus(username, row, "Leagues");
row.classList.add('status-processed');
}
});
}
function observeDOMChangesLeagues(userMap) {
const observer = new MutationObserver(() => {
const leaderboardRows = document.querySelectorAll('.table-row');
if (leaderboardRows.length > 0) {
console.log(`[DEBUG] Found ${leaderboardRows.length} leaderboard rows via MutationObserver.`);
processLeaderboardRows(leaderboardRows, userMap);
}
});
console.log("[DEBUG] MutationObserver initialized for /leagues.");
observer.observe(document.body, { childList: true, subtree: true });
}
init();
})();