Survev Quick Stats

Custom stats panel with stats + match history.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

You will need to install an extension such as Tampermonkey to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

// ==UserScript==
// @name         Survev Quick Stats
// @namespace    https://survev.io/
// @author       piesimp
// @version      1.0
// @description  Custom stats panel with stats + match history.
// @match        https://survev.io/*
// @run-at       document-end
// @grant        GM_xmlhttpRequest
// @connect      api.survev.io
// ==/UserScript==

(function () {
    'use strict';


    function modifyLeftColumn() {
        const socialBlock = document.getElementById("social-share-block");
        if (socialBlock) socialBlock.remove();

        const kofiLink = document.querySelector('#ad-block-left a[href="https://ko-fi.com/survev"]');
        if (kofiLink) kofiLink.remove();

        const survivShirts = document.querySelector('#ad-block-left .surviv-shirts');
        if (survivShirts) survivShirts.remove();
    }


    function buildEmptyStatsPanel() {

        const adBlock = document.getElementById("ad-block-left");
        const newsBlock = document.getElementById("news-block");
        if (!adBlock) return;

        adBlock.innerHTML = "";

        const container = document.createElement("div");
        container.id = "custom-stats-panel";

        container.innerHTML = `
            <div class="stats-header">
    <div class="stats-title">Your Stats</div>
    <div class="refresh-btn" title="Refresh Stats">⟳</div>
</div>

            <div class="stats-row">
                <div class="stat">
                    <div class="stat-label">Wins</div>
                    <div class="stat-value" id="stat-wins"></div>
                </div>
                <div class="stat">
                    <div class="stat-label">Kills</div>
                    <div class="stat-value" id="stat-kills"></div>
                </div>
                <div class="stat">
                    <div class="stat-label">Games</div>
                    <div class="stat-value" id="stat-games"></div>
                </div>
                <div class="stat">
                    <div class="stat-label">K/G</div>
                    <div class="stat-value" id="stat-kg"></div>
                </div>
            </div>

            <div class="recent-title">Recent Matches</div>

            <div class="recent-list">
                <div class="recent-item">
                    <div class="recent-mode"></div>
                    <div class="recent-time"></div>
                </div>
                <div class="recent-item">
                    <div class="recent-mode"></div>
                    <div class="recent-time"></div>
                </div>
                <div class="recent-item">
                    <div class="recent-mode"></div>
                    <div class="recent-time"></div>
                </div>
            </div>

            <div class="leaderboard-link">Global Leaderboard →</div>
        `;

        adBlock.appendChild(container);
        const refreshBtn = container.querySelector(".refresh-btn");

refreshBtn.onclick = () => {
    refreshBtn.classList.add("spinning");

    const username = window.currentSurvevPlayer;
    if (!username) return;

    fetchAndFillStats(username);
    fetchMatchHistory(username);

    setTimeout(() => {
        refreshBtn.classList.remove("spinning");
    }, 800);
};

        if (newsBlock) {
            const h = newsBlock.offsetHeight;
            adBlock.style.minHeight = (h + 3.8) + "px";
            container.style.minHeight = (h + 140) + "px";
        }

        container.querySelector(".leaderboard-link").onclick = () => {
            window.location.href = "https://survev.io/stats/";
        };
    }


    function fetchAndFillStats(username) {

        GM_xmlhttpRequest({
            method: "POST",
            url: "https://api.survev.io/api/user_stats",
            headers: {
                "Content-Type": "application/json; charset=UTF-8",
                "Accept": "*/*",
                "Origin": "https://survev.io",
                "Referer": "https://survev.io/"
            },
            data: JSON.stringify({
                slug: username,
                interval: "alltime",
                mapIdFilter: "-1"
            }),
            onload: function (response) {
                const data = JSON.parse(response.responseText);
                if (!data || data.banned) return;

                document.getElementById("stat-wins").textContent = data.wins || "";
                document.getElementById("stat-kills").textContent = data.kills || "";
                document.getElementById("stat-games").textContent = data.games || "";
                document.getElementById("stat-kg").textContent = data.kpg || "";
            }
        });
    }



    function fetchMatchHistory(username) {

        GM_xmlhttpRequest({
            method: "POST",
            url: "https://api.survev.io/api/match_history",
            headers: {
                "Content-Type": "application/json; charset=UTF-8",
                "Accept": "*/*",
                "Origin": "https://survev.io",
                "Referer": "https://survev.io/"
            },
            data: JSON.stringify({
                slug: username,
                offset: 0,
                count: 3,
                teamModeFilter: 7
            }),
            onload: function (response) {
                const matches = JSON.parse(response.responseText);
                if (!Array.isArray(matches)) return;

                const items = document.querySelectorAll(".recent-item");

                matches.slice(0, 3).forEach((match, i) => {

                    const modeMap = {
                        1: "Solo",
                        2: "Duo",
                        3: "Trio",
                        4: "Squad"
                    };

                    const mode = modeMap[match.team_count] || "Mode";
                    const placement = `#${match.rank}`;

                    const endTime = new Date(match.end_time);
                    const now = new Date();
                    const diff = Math.floor((now - endTime) / 1000);

                    let timeAgo;
                    if (diff < 60) timeAgo = `${diff}s ago`;
                    else if (diff < 3600) timeAgo = `${Math.floor(diff / 60)}m ago`;
                    else if (diff < 86400) timeAgo = `${Math.floor(diff / 3600)}h ago`;
                    else timeAgo = `${Math.floor(diff / 86400)}d ago`;

                    const modeDiv = items[i].querySelector(".recent-mode");
                    const timeDiv = items[i].querySelector(".recent-time");

                    modeDiv.textContent = `${mode} ${placement}`;
                    timeDiv.textContent = timeAgo;
                });
            }
        });
    }


    function detectAccountAndLoadStats() {

        const nameElement = document.getElementById("account-player-name");
        const adBlock = document.getElementById("ad-block-left");
        if (!nameElement || !adBlock) return;

        const rawName = nameElement.textContent.trim().toLowerCase();
const playerName = rawName.replace(/\s+/g, "-");

        const notLoggedInTexts = ["log in", "create account", "sign in", "guest"];
        const isLoggedOut = notLoggedInTexts.some(text =>
            playerName.includes(text)
        );

        if (isLoggedOut) {
            adBlock.innerHTML = `
                <div style="color:red; font-weight:bold; padding:15px; text-align:center;">
                    You must be logged in!
                </div>
            `;
            return;
        }
        window.currentSurvevPlayer = playerName;

        buildEmptyStatsPanel();
        fetchAndFillStats(playerName);
        fetchMatchHistory(playerName);
    }

    function injectStyles() {
        const style = document.createElement("style");
        style.textContent = `
        #custom-stats-panel {
            border-radius: 10px;
            padding: 15px;
            color: white;
            font-family: Arial, sans-serif;
            width: 100%;
            box-sizing: border-box;
        }

        .stats-title {
            font-weight: bold;
            color: #f7c948;
            margin-bottom: 10px;
        }

        .stats-row {
            display: flex;
            justify-content: space-between;
            margin-bottom: 15px;
        }

        .stat { text-align: center; flex: 1; }

        .stat-label { font-size: 12px; opacity: 0.8; }

        .stat-value {
            font-size: 18px;
            color: #00e5ff;
            margin-top: 4px;
            min-height: 20px;
        }

        .recent-title {
            margin-top: 10px;
            margin-bottom: 8px;
            font-weight: bold;
        }

        .recent-item {
            display: flex;
            justify-content: space-between;
            background: rgba(0,0,0,0.3);
            padding: 6px 8px;
            border-radius: 6px;
            margin-bottom: 6px;
            font-size: 13px;
        }

        .recent-mode { font-weight: bold; }
        .recent-time { opacity: 0.7; }

        .leaderboard-link {
            text-align: center;
            color: #00e5ff;
            cursor: pointer;
            font-size: 13px;
        }
        .stats-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 10px;
}

.refresh-btn {
    cursor: pointer;
    font-size: 16px;
    opacity: 0.7;
    transition: 0.2s ease;
}

.refresh-btn:hover {
    opacity: 1;
    transform: scale(1.1);
}

.refresh-btn.spinning {
    animation: spin 0.6s linear infinite;
}

@keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}
        `;
        document.head.appendChild(style);
    }



    window.addEventListener("load", function () {
        setTimeout(() => {
            modifyLeftColumn();
            injectStyles();
            detectAccountAndLoadStats();
        }, 1);
    });

})();