Nitro Type Ban Check (NTL)

Checks if users are banned or flagged from the ntleaderboards website. Made by [NHS]✨superjoelzy✨ based on the original script by dph

目前為 2025-03-10 提交的版本,檢視 最新版本

// ==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();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址