Nitro Type Leaderboards (Star Track)

Uses brute-force click for speed, Startrack's card layout for style, and adds footer/title features.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Nitro Type Leaderboards (Star Track)
// @namespace    https://ntstartrack.org
// @version      9.2
// @description  Uses brute-force click for speed, Startrack's card layout for style, and adds footer/title features.
// @author       [NTPD1]Captain.Loveridge // adapted from Ginfino & Daymare
// @match        https://www.nitrotype.com/*
// @match        https://www.nitromath.com/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    // --- Configuration ---
    const IFRAME_URL = 'https://ntstartrack.org/leaderboards';
    const TAB_CLASS = 'nt-custom-tab-leaderboards';
    const TAB_ID = 'ntCustomLeaderboardLink'; // ID for our click listener

    /**
     * The "Brute Force" Method (for Clicks)
     * Instantly replaces content without waiting for 404.
     */
    function embedLeaderboards_BruteForce(event) {
        if (event) event.preventDefault(); // Hijack the click

        const main = document.querySelector('main.structure-content');
        if (!main) return; // Main content not found

        // Use Startrack's clean card structure
        main.innerHTML = `
            <section class="card card--b card--shadow card--o card--grit card--f mtxs mbm">
                <div class="well--p well--l_p pll" style="padding:0;">
                    <div style="display:flex;flex-direction:column;align-items:center;width:100%;">
                        <h1 class="tc-i mbs tbs" style="margin:20px 0 10px;">Leaderboards</h1>
                        <div style="width:100%;height:85vh;border-radius:8px;overflow:hidden;">
                            <iframe
                                src="${IFRAME_URL}"
                                style="width:100%;height:100%;border:none;"
                                loading="lazy">
                            </iframe>
                        </div>
                    </div>
                </div>
            </section>
        `;

        // Manually update state
        setActiveTab();
        setTabTitle();
        window.history.pushState({}, '', '/leaderboards');
    }

    /**
     * The "Polite" Method (for Direct Page Loads)
     * Waits for 404 error to replace content.
     */
    function embedLeaderboards_Polite() {
        const main = document.querySelector('main.structure-content');
        if (!main || main.querySelector(`iframe[src="${IFRAME_URL}"]`)) {
            return; // Not ready or already embedded
        }

        // Use Startrack's clean card structure
        main.innerHTML = `
            <section class="card card--b card--shadow card--o card--grit card--f mtxs mbm">
                <div class="well--p well--l_p pll" style="padding:0;">
                    <div style="display:flex;flex-direction:column;align-items:center;width:100%;">
                        <h1 class="tc-i mbs tbs" style="margin:20px 0 10px;">Leaderboards</h1>
                        <div style="width:100%;height:85vh;border-radius:8px;overflow:hidden;">
                            <iframe
                                src="${IFRAME_URL}"
                                style="width:100%;height:100%;border:none;"
                                loading="lazy">
                            </iframe>
                        </div>
                    </div>
                </div>
            </section>
        `;

        setActiveTab();
        setTabTitle();
    }

    /**
     * Inserts the tab before "News" (8.6 style)
     * and adds the brute-force click listener.
     */
    function insertLeaderboardTab() {
        if (document.getElementById(TAB_ID)) return; // Already inserted

        const navList = document.querySelector('.nav-list');
        if (!navList) return;

        const li = document.createElement('li');
        li.className = `nav-list-item ${TAB_CLASS}`;
        // Use href="#" to allow our click listener to take over
        li.innerHTML = `<a href="#" class="nav-link" id="${TAB_ID}">Leaderboards</a>`;

        const newsButton = Array.from(navList.children).find((child) =>
            child.textContent.trim().includes('News')
        );

        if (newsButton) {
            navList.insertBefore(li, newsButton);
        } else {
            navList.appendChild(li);
        }

        // Add the brute-force click listener
        document.getElementById(TAB_ID).addEventListener('click', embedLeaderboards_BruteForce);
    }

    /**
     * Adds a "Leaderboards" link to the site footer.
     */
    function addLeaderboardsToFooter() {
        if (document.querySelector('a.footer-menuLink[href="/leaderboards"]')) return;

        const footerLists = document.querySelectorAll('.footer-menuLink');
        if (footerLists.length > 0) {
            const siteMapLink = footerLists[footerLists.length - 1];
            if (siteMapLink && siteMapLink.href.includes('/support/sitemap')) {
                const leaderboardsLink = document.createElement('a');
                leaderboardsLink.className = 'list-item link link--s link--nav footer-menuLink';
                leaderboardsLink.href = '/leaderboards';
                leaderboardsLink.textContent = 'Leaderboards';
                siteMapLink.parentNode.insertBefore(leaderboardsLink, siteMapLink.nextSibling);
            }
        }
    }

    /**
     * Sets the browser tab title dynamically.
     */
    function setTabTitle() {
        if (window.location.pathname === '/leaderboards') {
            if (window.location.hostname.includes('nitrotype.com')) {
                document.title = 'Nitro Type Leaderboards';
            } else if (window.location.hostname.includes('nitromath.com')) {
                document.title = 'Nitro Math Leaderboards';
            }
        }
    }

    /**
     * Highlights the "Leaderboards" tab as the active one.
     */
    function setActiveTab() {
        document.querySelectorAll('.nav-list-item').forEach(li => li.classList.remove('is-current'));
        const tab = document.querySelector('.' + TAB_CLASS);
        if (tab) {
            tab.classList.add('is-current');
        }
    }

    /**
     * Main function to handle page loads and navigation changes.
     */
    function handlePage() {
        // Always ensure the tab and footer link are present
        insertLeaderboardTab();
        addLeaderboardsToFooter();

        // If we are on the /leaderboards page (from a direct load or link)
        // we MUST use the "polite" 404-waiter method.
        if (location.pathname === '/leaderboards') {
            // Check if it was our click that got us here. If so, it's already handled.
            if (document.querySelector(`iframe[src="${IFRAME_URL}"]`)) {
                setActiveTab(); // Just make sure the tab is active
                return;
            }

            // If not, use the "polite" 404-waiter
            const observer = new MutationObserver(() => {
                const err = document.querySelector('.error');
                const main = document.querySelector('main.structure-content');
                if (err || (main && main.children.length === 0)) {
                    embedLeaderboards_Polite();
                    observer.disconnect();
                }
            });
            observer.observe(document.body, { childList: true, subtree: true });

            if (document.querySelector('.error')) {
                embedLeaderboards_Polite();
                observer.disconnect();
            }
        }
    }

    // Use a persistent MutationObserver for SPA navigation
    const obs = new MutationObserver(handlePage);
    obs.observe(document.body, { childList: true, subtree: true });

    // Run the handler once on script load
    handlePage();
})();