Nitro Type Leaderboards (Star Track)

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

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴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();
})();