TMVN Cup HOF

Trophymanager: hall of fame of tournament

// ==UserScript==
// @name         TMVN Cup HOF
// @namespace    https://trophymanager.com
// @version      3
// @description  Trophymanager: hall of fame of tournament
// @match        https://trophymanager.com/history/cup/*
// @grant        none
// ==/UserScript==

(function () {
    /* --------------------------- STORE --------------------------- */
    const championsBySeason = new Map();             // season -> {id, nth}
    const championIdOfSeason = new Map();            // season -> clubId (raw, before nth calc)
    const titleCounter      = new Map();             // clubId -> running nth counter
    const clubNameById      = new Map();             // clubId -> latest name

    const cupChampTotal     = new Map();             // clubId -> #champion
    const cupRunnerTotal    = new Map();             // clubId -> #runner‑up
    const lastSeasonAppear  = new Map();             // clubId -> most recent season they reached final

    /* --------------------------- HELPERS ------------------------- */
    const inc = (map, key) => map.set(key, (map.get(key) || 0) + 1);

    function ensureRightColumn() {
        let column = document.querySelector('div.column3_a');
        if (!column) {
            const old = document.querySelector('div.column3');
            if (old) old.parentNode.removeChild(old);
            column = document.createElement('div');
            column.className = 'column3_a';
            const centers = document.querySelectorAll('div.main_center');
            const target  = centers[centers.length === 4 ? 3 : 2];
            target.appendChild(column);
        }
        return column;
    }

    function renderTables() {
        /* Champions by season table (desc) */
        const seasonsDesc = Array.from(championsBySeason.keys()).sort((a,b)=>b-a);
        let championsHTML = "<table><tr><th>Season</th><th>Club</th><th align='right'>Nth</th></tr>";
        seasonsDesc.forEach((season,idx) => {
            const {id,nth} = championsBySeason.get(season);
            const name = clubNameById.get(id);
            const odd  = (idx & 1) ? " class='odd'" : "";
            championsHTML += `<tr${odd}><td>${season}</td><td><span onclick=\"window.open('https://trophymanager.com/club/${id}')\">${name}</span></td><td align='right'>${nth}</td></tr>`;
        });
        championsHTML += "</table>";

        /* Hall of Fame */
        const allIds = new Set([...cupChampTotal.keys(), ...cupRunnerTotal.keys()]);
        const hofList = Array.from(allIds).sort((a,b)=>{
            const scoreB = (cupChampTotal.get(b)||0)*1000 + (cupRunnerTotal.get(b)||0);
            const scoreA = (cupChampTotal.get(a)||0)*1000 + (cupRunnerTotal.get(a)||0);
            if (scoreB !== scoreA) return scoreB - scoreA;
            // tie‑break by most recent appearance (descending season)
            return (lastSeasonAppear.get(b)||0) - (lastSeasonAppear.get(a)||0);
        });
        let hofHTML = "<table><tr><th>#</th><th>Club</th><th align='right'>#1</th><th align='right'>#2</th></tr>";
        hofList.forEach((id,index)=>{
            const name = clubNameById.get(id);
            const c = cupChampTotal.get(id)||'';
            const r = cupRunnerTotal.get(id)||'';
            const odd = (index & 1) ? " class='odd'" : "";
            hofHTML += `<tr${odd}><td>${index+1}</td><td><span onclick=\"window.open('https://trophymanager.com/club/${id}')\">${name}</span></td><td align='right'>${c}</td><td align='right'>${r}</td></tr>`;
        });
        hofHTML += "</table>";

        /* inject */
        const col = ensureRightColumn();
        if (!document.getElementById('tmvn_cup_champions')) {
            col.insertAdjacentHTML('beforeend', `<div class='box' id='tmvn_cup_champions'><div class='box_head'><h2 class='std'>CHAMPION LIST</h2></div><div class='box_body'><div class='box_shadow'></div>${championsHTML}</div><div class='box_footer'><div></div></div></div>`);
        } else {
            document.querySelector('#tmvn_cup_champions .box_body').innerHTML = `<div class='box_shadow'></div>${championsHTML}`;
        }
        if (!document.getElementById('tmvn_cup_hof')) {
            col.insertAdjacentHTML('beforeend', `<div class='box' id='tmvn_cup_hof'><div class='box_head'><h2 class='std'>HALL OF FAME</h2></div><div class='box_body'><div class='box_shadow'></div>${hofHTML}</div><div class='box_footer'><div></div></div></div>`);
        } else {
            document.querySelector('#tmvn_cup_hof .box_body').innerHTML = `<div class='box_shadow'></div>${hofHTML}`;
        }
    }

    /* --------------------------- SCAN --------------------------- */
    const currentSeason = parseInt(document.querySelector('#top_menu a.none.white.small').innerText.split(/(\s+)/)[2],10);
    const country = location.href.split('/')[5];
    let scanned = 0;

    for (let season = 1; season < currentSeason; season++) {
        $.ajax(`https://trophymanager.com/history/cup/${country}/${season}`, {
            type: 'GET', dataType: 'html', crossDomain: true,
            success: response => {
                const final = $('.match_list.border_bottom li', response)[0];
                if (final) {
                    const a   = final.querySelectorAll('a');
                    const id1 = a[0].getAttribute('club_link');
                    const id2 = a[2].getAttribute('club_link');
                    const name1 = a[0].innerText;
                    const name2 = a[2].innerText;
                    clubNameById.set(id1, name1);
                    clubNameById.set(id2, name2);
                    const [s1,s2] = a[1].innerText.split('-').map(n=>parseInt(n,10));
                    const champId = s1 > s2 ? id1 : id2;
                    const runId   = s1 > s2 ? id2 : id1;

                    championIdOfSeason.set(season, champId); // save raw champ -> compute nth later

                    inc(cupChampTotal, champId);
                    inc(cupRunnerTotal, runId);

                    lastSeasonAppear.set(champId, season);
                    lastSeasonAppear.set(runId,  season);
                }
                if (++scanned === currentSeason-1) finalize();
            },
            error: () => { if (++scanned === currentSeason-1) finalize(); }
        });
    }

    function finalize() {
        /* compute nth titles in chronological order to avoid async issues */
        const seasonsAsc = Array.from(championIdOfSeason.keys()).sort((a,b)=>a-b);
        seasonsAsc.forEach(season=>{
            const champId = championIdOfSeason.get(season);
            if (!champId) return;
            inc(titleCounter, champId);
            const nth = titleCounter.get(champId);
            championsBySeason.set(season, {id: champId, nth});
        });
        renderTables();
    }
})();