antimYT / PvPRO scripts

// ==UserScript==
// @name         PvPRO scripts
// @namespace    https://github.com/antimYT/
// @version      2.00
// @license      MIT
// @icon         https://www.pvpro.com/img/favicon.ico
// @updateURL    https://openuserjs.org/meta/antimYT/PvPRO_scripts.meta.js
// @downloadURL  https://openuserjs.org/install/antimYT/PvPRO_scripts.user.js
// @copyright    2020, antimYT (https://openuserjs.org/users/antimYT)
// @description  PvPRO scripts
// @author       /antim/
// @match        https://www.pvpro.com/*
// @grant       unsafeWindow
// @grant       GM.info
// @grant       GM_setValue
// @grant       GM_getValue
// @grant       none
// @require     https://gist.githubusercontent.com/arantius/3123124/raw/grant-none-shim.js
// ==/UserScript==

// ==Changelog==
//
// v1.96 -> v2.00:
// - reworked everything
//
// ==/Changelog==

function timeSince(date) {
    var seconds = Math.abs(Math.floor((new Date() - date) / 1000));

    var years = Math.floor(seconds / 31536000);
    var months = Math.floor(seconds / 2592000);
    var days = Math.floor(seconds / 86400);
    var hours = Math.floor(seconds / 3600);
    var minutes = Math.floor(seconds / 60);
    if (months >= 12) return years + "yrs";
    if (days > 30) return months + "months";
    if (hours >= 24) return days + "d";
    if (minutes >= 60) return hours + "hrs";
    if (seconds >= 60) return minutes + "min";
    return Math.floor(seconds) + " seconds";
}

function filterTournaments(tournaments_box, modename, dontfilter){
    var tours = tournaments_box.find('.grid-competitions-items-row');
    tours.each(function( index ) {
        if(dontfilter == true){
            $( this ).css("display", "");
        } else {
            if($(this).find('.mode').text() == modename)
                $( this ).css("display", "");
            else
                $( this ).css("display", "none");
        }
    });
}

function GetMissionsHtmlForMainHeader(initialStateData){
    var missions_html = "";
    $.each( initialStateData.payload.promoQuests, function( index, value ){
        //missions without 'scheduledFinishDate' are not real
        try{
            if(value.project == initialStateData.payload.defaultSportProjects.CSGO && Date.now() < Date.parse(value.scheduledFinishDate)){
                //show mission
                console.log(value);
                var challenge = initialStateData.payload.account.challengeRegistrations[value.id];
                console.log(challenge);
                if(challenge != null && challenge.status == "FINISHED")
                    return; //same as continue;
                var prizehtml = "";
                if(value.prizeDistributionPolicy.prize.value.credits > 0)
                    prizehtml = '<span class="currency"> — <img src="https://www.pvpro.com/img/pvpro_coin.png" width="15" class="coin mr-xs"><span>' + value.prizeDistributionPolicy.prize.value.credits + '</span></span>';
                else if(value.prizeDistributionPolicy.prize.value.crystals > 0)
                    prizehtml = '<span class="currency"> — <img src="https://www.pvpro.com/img/pvpro_crystal.png" width="15" class="crystal mr-xs"><span>' + value.prizeDistributionPolicy.prize.value.crystals + '</span></span>';
                if(challenge != null)
                    missions_html += '<div class="row mx-xs align-items-center" style="background-color:#008eff45;border-radius:16px;max-width:320px;height:50px"><div class="col-auto mr-20"><img src="' + value.imageUrl + '" style="height:45px;padding: 0.25em;"></div><div class="col"><div class="heading-wrapper px-sm"><div class="heading-labels"><h6 class="heading heading-6">' + value.performanceDescription + '</h6><div class="sub-heading sub-heading-6">' + challenge.score + prizehtml + '</div></div></div></div></div>';
                else
                    missions_html += '<div class="row mx-xs align-items-center" style="background-color:#008eff45;border-radius:16px;max-width:320px;height:50px"><div class="col-auto mr-20"><img src="' + value.imageUrl + '" style="height:45px;padding: 0.25em;"></div><div class="col"><div class="heading-wrapper px-sm"><div class="heading-labels"><h6 class="heading heading-6">' + value.performanceDescription + '*</h6><div class="sub-heading sub-heading-6">' + value.defaultPlayerScore + prizehtml + '</div></div></div></div></div>';
            }
        }catch(ex){
            console.log(ex);
        }
    });
    return missions_html;
}

function GetLeaguesHtmlForMainHeader(initialStateData, elementAppendTo){
    $.each( initialStateData.payload.account.challengeRegistrations, function( index, value ){
        //missions without 'scheduledFinishDate' are not real
        try{
            if(value.status == "ACTIVE" && value.parentId != null && parseFloat(value.score) > 0.0){
                //show mission
                console.log(value);
                //
                $.ajax({
                    url: "https://webapi.pvpro.com/pvpro/challenge/details?challengeId=" + value.parentId + "&section=details",
                    dataType: 'json',
                    xhrFields: { withCredentials: true },
                    success: function(data) {
                        if(data.success == true){
                            //alert("Data: " + data + "\nStatus: " + status);
                            console.log(data);
                            elementAppendTo.append('<div class="row mx-xs align-items-center" onclick="window.location.href=\'https://www.pvpro.com/challenge/details/' + value.parentId + '?positionsChallengeId=' + value.challengeId + '&section=results\'" style="background-color:#008eff45;border-radius:16px;max-width:320px;height:50px"><div class="col-auto mr-20"><img src="' + data.payload.imageUrl + '" style="height:45px;padding: 0.25em;"></div><div class="col"><div class="heading-wrapper px-sm"><div class="heading-labels"><h6 class="heading heading-6">' + data.payload.name + '</h6><div class="sub-heading sub-heading-6">Score: ' + value.score + '</div></div></div></div></div>');

                            //initialStateData=data;
                        }
                    }
                });
            }
        }catch(ex){
            console.log(ex);
        }
    });
}

function onLoadFunc(){
    var lastUrl = window.location.href;
    var initialStateData = null;
    $.ajax({
        url: "https://webapi.pvpro.com/pvpro/app/loadInitialState",
        dataType: 'json',
        xhrFields: { withCredentials: true },
        success: function(data) {
            if(data.success == true){
                //alert("Data: " + data + "\nStatus: " + status);
                console.log(data);
                initialStateData=data;
            }else
                console.log('FAILED TO LOAD initialStateData');
        }
    });
    setInterval(function(){
        if(initialStateData == null)
            return;
        var main_header = $(".main-header");
        var tournaments_box = $(".Tournament > .grid-competitions");
        var sidebar_profile = $(".sidebar-profile");
        var accept_game_modal = $(".accept-game-modal");
        //var main_header_logo = main_header.find('.header-logo>img');
        var mini_profile_modal = $('div.modal-layout.mini-profile-modal');
        var active_game_body = $('div.active-game-body');
        var game_lobby_details = active_game_body.find('div.game-lobby-details');
        var mini_profile = $('div.mini-profile');

        // =============================
        // url changed
        // =============================
        if(lastUrl != window.location.href){
            //url changed
            console.log(window.location.href);
            lastUrl = window.location.href;
        }

        // =============================
        // tournaments page updated
        // =============================
        if(tournaments_box.length > 0 && tournaments_box.hasClass("antim_class") == false){
            tournaments_box.addClass("antim_class");
            tournaments_box.prepend( '<div class="row flex-grow-1"><div class="col-auto d-flex flex-wrap align-items-center pr-gap"><div class="form-input-wrapper fill flex-grow-1"><div class="control-group flex-grow-1">'
                                    + '<button type="button" id="antim_tournaments_filterall" class="button radio dark antim_tournaments active">All</button>'
                                    + '<button type="button" id="antim_tournaments_filter1v1" class="button radio dark antim_tournaments">1v1</button>'
                                    + '<button type="button" id="antim_tournaments_filter2v2" class="button radio dark antim_tournaments">2v2</button>'
                                    + '<button type="button" id="antim_tournaments_filter3v3" class="button radio dark antim_tournaments">3v3</button>'
                                    + '<button type="button" id="antim_tournaments_filter5v5" class="button radio dark antim_tournaments">5v5</button>'
                                    + '</div></div></div></div>' );
            $("#antim_tournaments_filterall").click(function() {
                $(".antim_tournaments").removeClass("active");
                $(this).addClass("active");
                filterTournaments(tournaments_box, "", true);
            });
            $("#antim_tournaments_filter1v1").click(function() {
                $(".antim_tournaments").removeClass("active");
                $(this).addClass("active");
                filterTournaments(tournaments_box, "1v1", false);
            });
            $("#antim_tournaments_filter2v2").click(function() {
                $(".antim_tournaments").removeClass("active");
                $(this).addClass("active");
                filterTournaments(tournaments_box, "2v2", false);
            });
            $("#antim_tournaments_filter3v3").click(function() {
                $(".antim_tournaments").removeClass("active");
                $(this).addClass("active");
                filterTournaments(tournaments_box, "3v3", false);
            });
            $("#antim_tournaments_filter5v5").click(function() {
                $(".antim_tournaments").removeClass("active");
                $(this).addClass("active");
                filterTournaments(tournaments_box, "5v5", false);
            });
        }

        // =============================
        // sidebar profile changed
        // =============================
        if(false && sidebar_profile.length > 0 && sidebar_profile.hasClass("antim_class") == false){
            sidebar_profile.addClass("antim_class");
            console.log("sidebar-profile changed");
            try{
                var rank_progressbar = sidebar_profile.find('.progress-bar-filler');
                var rank_percent = rank_progressbar[0].style.width;
                rank_percent = rank_percent.substr(0, rank_percent.length-1);
                var infoline = sidebar_profile.find('.justify-content-between');
                infoline.append( '<span>(+0)</span>' );
                console.log(infoline);
            }catch(ex){console.log(ex);}
            //sidebar_profile.prepend( '<div class="row flex-grow-1"><div class="col-auto d-flex flex-wrap align-items-center pr-gap"><div class="form-input-wrapper fill flex-grow-1"><div class="control-group flex-grow-1">'
            //                         + '<button type="button" id="antim_tournaments_filterall" class="button radio dark antim_tournaments active">All</button>'
            //                           + '<button type="button" id="antim_tournaments_filter1v1" class="button radio dark antim_tournaments">1v1</button>'
            //                             + '</div></div></div></div>' );
            //  $("#antim_tournaments_filterall").click(function() {
            //      $(".antim_tournaments").removeClass("active");
            //      $(this).addClass("active");
            //      filterTournaments(tournaments_box, "", true);
            //  });
        }

        // =============================
        // autoaccept
        // =============================
        if(accept_game_modal.length > 0){
            accept_game_modal.find("button.accept-game").click();
            console.log("auto accepted!");
        }

        // =============================
        // main header changed
        // =============================
        if(main_header.length > 0 && main_header.hasClass("antim_class") == false){
            main_header.addClass("antim_class");
            console.log("main header changed");
            main_header.find('div.text-light').after('<div style="display: grid;height: 75%;padding: 0 1rem">'
                                                     + '<button id="antim_header_showmissions" class="button fill sm ml-auto lightsweep success antim_header_button" style="font-size:0.9em;padding:0 1rem;width:100%;border-bottom-right-radius:0px;border-bottom-left-radius:0px;">Missions</button>'
                                                     + '<button id="antim_header_showleagues" class="button fill sm ml-auto lightsweep antim_header_button" style="font-size:0.9em;padding:0 1rem;width:100%;border-top-right-radius:0px;border-top-left-radius:0px;">Leagues</button>'
                                                     + '</div>'
                                                     + '<div id="antim_header_missions" class="flex-grow-1 antim_header_tab" style="display: flex;align-items: center;">' + GetMissionsHtmlForMainHeader(initialStateData) + '</div>'
                                                     + '<div id="antim_header_leagues" class="flex-grow-1 antim_header_tab" style="display: none;align-items: center;"></div>');
            GetLeaguesHtmlForMainHeader(initialStateData, $('#antim_header_leagues'));
            $("#antim_header_showmissions").click(function() {
                $(".antim_header_button").removeClass("success");
                $(this).addClass("success");
                $(".antim_header_tab").css("display", "none");
                $("#antim_header_missions").css("display", "flex");
            });
            $("#antim_header_showleagues").click(function() {
                $(".antim_header_button").removeClass("success");
                $(this).addClass("success");
                $(".antim_header_tab").css("display", "none");
                $("#antim_header_leagues").css("display", "flex");
            });
        }

        // =============================
        // replace logo
        // =============================
        if(false && main_header_logo.length > 0 && main_header_logo.hasClass("antim_class") == false){
            main_header_logo.addClass("antim_class");
            console.log("logo changed");
            main_header_logo.attr("src", "https://raw.githubusercontent.com/antimYT/antimYT.github.io/master/pvpro_content/pvpro_logo.gif");
            main_header.find('.header-logo').css('width', '280px');
        }

        // =============================
        // mini profile modal changed/appeared
        // =============================
        if(mini_profile_modal.length > 0 && mini_profile_modal.hasClass("antim_class") == false){
            mini_profile_modal.addClass("antim_class");
            console.log("mini profile modal changed");
            var username = mini_profile_modal.find('h2.heading>span').text();
            //additional info
            $.ajax({
                url: "https://webapi.pvpro.com/pvpro/secured/community/profile/mini?playerToViewUsername=" + username + "&sport=CSGO",
                dataType: 'json',
                xhrFields: { withCredentials: true },
                success: function(data) {
                    if(data.success == true){
                        //console.log(data);
                        var leaver = "?";
                        var noShower = "?";
                        var detected = "?";
                        var leaver2 = "?";
                        var noShower2 = "?";
                        var detected2 = "?";
                        var prime = "?";
                        try{ leaver = data.payload.player.actionProfile.stats.timesLeaver; }catch(ex){}
                        try{ noShower = data.payload.player.actionProfile.stats.timesNoShower; }catch(ex){}
                        try{ detected = data.payload.player.actionProfile.stats.numAcDetections; }catch(ex){}
                        try{ leaver2 = data.payload.gameStats.stats.COMPETITIVE.timesLeaver; }catch(ex){}
                        try{ noShower2 = data.payload.gameStats.stats.COMPETITIVE.timesNoShower; }catch(ex){}
                        try{ detected2 = data.payload.gameStats.stats.COMPETITIVE.numAcDetections; }catch(ex){}
                        try{ prime = data.payload.player.actionProfile.isPrimeAccount; }catch(ex){}
                        mini_profile_modal.find('div.col-12.col-md-8.col-xl-9').append('<div class="bg-dark flex-grow-1 mt-sm d-flex flex-wrap align-items-center"><div class="table-grid grid-stats flex-grow-1"><table class="table"><tbody><tr class="grid-header grid-stats-header">'
                                                                                       + '<td class="grid-header-item grid-stats-header-item text-center">Leaver</td>'
                                                                                       + '<td class="grid-header-item grid-stats-header-item text-center">No shower</td>'
                                                                                       + '<td class="grid-header-item grid-stats-header-item text-center">Detected (AC)</td>'
                                                                                       + '<td class="grid-header-item grid-stats-header-item text-center">Prime</td>'
                                                                                       + '</tr><tr class="grid-items-row grid-stats-items-row">'
                                                                                       + '<td class="grid-item grid-stats-item text-center">' + leaver + ' (' + leaver2 + ')</td>'
                                                                                       + '<td class="grid-item grid-stats-item text-center">' + noShower + ' (' + noShower2 + ')</td>'
                                                                                       + '<td class="grid-item grid-stats-item text-center">' + detected + ' (' + detected2 + ')</td>'
                                                                                       + '<td class="grid-item grid-stats-item text-center">' + prime + '</td>'
                                                                                       + '</tr></tbody></table></div></div>');
                    }
                }
            });
            //check for ban
            $.ajax({
                url: "https://webapi.pvpro.com/pvpro/leaderboards/hallOfShame/list?searchUsername=" + username,
                dataType: 'json',
                xhrFields: { withCredentials: true },
                success: function(data) {
                    try{
                        var bannedPlayer = null;
                        if(data.success == true && data.payload.data != null && data.payload.data.length > 0){
                            $.each( data.payload.data, function( index, value ){
                                if(Date.now() < Date.parse(value.ban.expirationDate) && value.username == username){
                                    bannedPlayer = value;
                                    return false; //same as break;
                                }
                            });
                        }
                        if(bannedPlayer == null){
                            mini_profile_modal.find('div.modal-layout-header').find('h2.heading').append(' — <span style="color: #2e7d32">not banned</span>');
                        } else {
                            console.log(bannedPlayer);
                            var reason = bannedPlayer.ban.reason;
                            var expirationDate = "?";
                            var banDate = bannedPlayer.ban.banDate;
                            var permanent = "?";
                            var until = "";
                            var bannedTimeAgo = " " + timeSince(Date.parse(banDate)) + " ago";
                            try{ expirationDate = bannedPlayer.ban.expirationDate; }catch(ex){}
                            try{ permanent = bannedPlayer.ban.permanent; }catch(ex){}
                            //Date.now() < Date.parse(value.scheduledFinishDate)
                            if(permanent != true){
                                until = ", left " + timeSince(Date.parse(expirationDate));
                            }
                            mini_profile_modal.find('div.modal-layout-header').find('h2.heading').append(' — <span style="color: #c62828">BANNED FOR ' + reason + bannedTimeAgo + until + '</span>');
                        }
                    }catch(ex){ console.log(ex); }
                }
            });
        }

        // =============================
        // game_lobby_details (connect game details) changed/appeared
        // =============================
        if(game_lobby_details.length > 0 && game_lobby_details.hasClass("antim_class") == false){
            game_lobby_details.addClass("antim_class");
            console.log("game_lobby_details changed");
            var players = active_game_body.find('div.game-lobby-team-member');
            if(false){
                $.ajax({
                    url: "https://webapi.pvpro.com/pvpro/secured/community/profile/mini?playerToViewUsername=" + username + "&sport=CSGO",
                    dataType: 'json',
                    xhrFields: { withCredentials: true },
                    success: function(data) {
                        if(data.success == true){
                            //console.log(data);
                            var leaver = "?";
                            var noShower = "?";
                            var detected = "?";
                            var leaver2 = "?";
                            var noShower2 = "?";
                            var detected2 = "?";
                            var prime = "?";
                            try{ leaver = data.payload.player.actionProfile.stats.timesLeaver; }catch(ex){}
                            try{ noShower = data.payload.player.actionProfile.stats.timesNoShower; }catch(ex){}
                            try{ detected = data.payload.player.actionProfile.stats.numAcDetections; }catch(ex){}
                            try{ leaver2 = data.payload.gameStats.stats.COMPETITIVE.timesLeaver; }catch(ex){}
                            try{ noShower2 = data.payload.gameStats.stats.COMPETITIVE.timesNoShower; }catch(ex){}
                            try{ detected2 = data.payload.gameStats.stats.COMPETITIVE.numAcDetections; }catch(ex){}
                            try{ prime = data.payload.player.actionProfile.isPrimeAccount; }catch(ex){}
                            mini_profile_modal.find('div.col-12.col-md-8.col-xl-9').append('<div class="bg-dark flex-grow-1 mt-sm d-flex flex-wrap align-items-center"><div class="table-grid grid-stats flex-grow-1"><table class="table"><tbody><tr class="grid-header grid-stats-header">'
                                                                                           + '<td class="grid-header-item grid-stats-header-item text-center">Leaver</td>'
                                                                                           + '<td class="grid-header-item grid-stats-header-item text-center">No shower</td>'
                                                                                           + '<td class="grid-header-item grid-stats-header-item text-center">Detected (AC)</td>'
                                                                                           + '<td class="grid-header-item grid-stats-header-item text-center">Prime</td>'
                                                                                           + '</tr><tr class="grid-items-row grid-stats-items-row">'
                                                                                           + '<td class="grid-item grid-stats-item text-center">' + leaver + ' (' + leaver2 + ')</td>'
                                                                                           + '<td class="grid-item grid-stats-item text-center">' + noShower + ' (' + noShower2 + ')</td>'
                                                                                           + '<td class="grid-item grid-stats-item text-center">' + detected + ' (' + detected2 + ')</td>'
                                                                                           + '<td class="grid-item grid-stats-item text-center">' + prime + '</td>'
                                                                                           + '</tr></tbody></table></div></div>');
                        }
                    }
                });
            }
        }

        // =============================
        // profile: games tab, game line changed/appeared
        // TODO: ability to report players
        // =============================
        if(false && lastUrl.indexOf("secured/account/profile/csgo/game/history") >= 0){
            try{
                var gamelines = $('div.acountPayments').find('table.table').find('tr.grid-items-row:not(.antim_class)');
                if(gamelines.length > 0){
                    gamelines.addClass("antim_class");
                    gamelines.find('grid-list-item')[0].click = function(){

                    }
                    console.log(gamelines);
                }
            } catch(ex) { console.log(ex); }
        }

        // =============================
        // mini_profile changed
        // =============================
        if(mini_profile.length > 0 && mini_profile.hasClass("antim_class") == false){
            mini_profile.addClass("antim_class");
            console.log("account_profile changed");
            var profile_tickets = mini_profile.find('div.profile-tickets');
            profile_tickets.find('img.ticket').each(function() {
                var ticketName = $(this).attr('title');
                var ticket = null;
                $.each( initialStateData.payload.account.player.tickets, function( index, value ){
                    if(value.name != ticketName) return;
                    ticket = value;
                });
                if(ticket != null){
                    $(this).after('<span>x' + ticket.total + '</span>')
                }
            });
        }

        // =============================
        // ==== END
        // =============================
    }, 500);
}

(function() {
    'use strict';
    //append jquery
	var script = document.createElement('script');
	script.src = 'https://code.jquery.com/jquery-3.4.1.min.js';
	script.type = 'text/javascript';
	document.getElementsByTagName('head')[0].appendChild(script);
    //onload function
    var _scriptloaded = false;
    function _docload(){
        setTimeout(function() {
            _docload();
        }, 200);
        if(_scriptloaded == true){
            return;
        }
        $( document ).ready(function() {
            onLoadFunc();
        });
        _scriptloaded = true;
        console.log("a-script loaded");
    }
    setTimeout(function() {
        _docload();
    }, 100);
	//DeleteAds();
})();