ASF STM

ASF bot list trade matcher

目前為 2020-06-09 提交的版本,檢視 最新版本

// ==UserScript==
// @name        ASF STM
// @language    English
// @namespace   https://gf.qytechs.cn/users/2205
// @description ASF bot list trade matcher
// @include     http*://steamcommunity.com/id/*/badges
// @include     http*://steamcommunity.com/id/*/badges/
// @include     http*://steamcommunity.com/profiles/*/badges
// @include     http*://steamcommunity.com/profiles/*/badges/
// @version     0.3
// @connect     asf.justarchi.net
// @grant       GM.xmlhttpRequest
// @grant       GM_xmlhttpRequest
// ==/UserScript==

/* global g_steamID */

(function()
 {
    const limiter = 500;
    const debug = false;
    const maxErrors = 5;
    let errors=0;
    let bots;
    let assets=[];
    let descriptions=[];
    let mybadges=[];
    let userbadges=[];
    let maxpages;

    function debugProfile(name){
        if (debug) {
            console.time(name);
        }
    }

    function debugProfileEnd(name){
        if (debug) {
            console.timeEnd(name);
        }
    }
    function debugPrint(msg){
    	if (debug) {
    	  console.log(msg);
    	}
    }

    function getPartner(str) {
        return (BigInt(str)%4294967296n).toString();
    }

    function EnableButton(){
        let buttondiv=document.getElementById("asf_stm_button_div");
        buttondiv.setAttribute("class","profile_small_header_additional");
        let button=document.getElementById("asf_stm_button");
        button.addEventListener("click",ButtonPressed, false);
    }

    function DisableButton(){
        let buttondiv=document.getElementById("asf_stm_button_div");
        buttondiv.setAttribute("class","profile_small_header_additional btn_disabled");
        let button=document.getElementById("asf_stm_button");
        button.removeEventListener("click",ButtonPressed, false);
    }

    function UpdateMessage(text){
        let message=document.getElementById("asf_stm_message");
        message.textContent=text;
    }

    function HideMessage(){
        let messagebox=document.getElementById("asf_stm_messagebox");
        messagebox.setAttribute("style","display: none;");
    }
    function HideThrobber(){
        let throbber=document.getElementById("throbber");
        throbber.setAttribute("style","display: none;");
    }

    function UpdateProgress(index){
        let bar=document.getElementById("asf_stm_progress");
        let progress = (100*((index+1)/bots.length));
        bar.setAttribute("style","width: "+progress+"%;");
    }
    function populateCards(item) {
        let classlist = "";
        let htmlCards = ""
        for (let j=0;j<item.cards.length; j++) {
            let item_icon = item.cards[j].icon_url;
            let item_name = item.cards[j].item.substring(item.cards[j].item.indexOf("-")+1);
            for (let k=0; k<item.cards[j].count; k++) {
                if (classlist!=""){
                    classlist+=";";
                }
                classlist+=item.cards[j].class;
                let cardTemplate =`
                          <div class="showcase_slot">
                            <img class="image-container" src="https://steamcommunity-a.akamaihd.net/economy/image/${item_icon}/98x115">
                            <div class="commentthread_subscribe_hint" style="width: 98px;">${item_name}</div>
                          </div>
                `;
                htmlCards+=cardTemplate;
            }
        }
        return {"htmlCards":htmlCards,"classlist": classlist};
    }

    function AddMatchRow(itemsToSend,itemsToReceive,botname,index){
        let tradeurl="https://steamcommunity.com/tradeoffer/new/?partner="+getPartner(bots[index].steam_id)+"&token="+bots[index].trade_token+"&source=stm";
        let globalyou="";
        let globalthem="";
        let matches = "";
        if (bots[index].match_everything==1) {
            botname = botname+`&nbsp;<sup><span class="avatar_block_status_in-game" style="font-size: 8px; cursor:help" title="This bots trades for any cards within same set">&nbsp;ANY&nbsp;</span></sup>`;
        }
        for (let i=0;i<itemsToSend.length;i++) {
            let appid = itemsToSend[i].appid;
            let itemToReceive = itemsToReceive.find(a => a.appid == appid);
            let gameName = itemsToSend[i].title;

            let sendResult = populateCards(itemsToSend[i]);
            let receiveResult = populateCards(itemToReceive);

            let tradeurlappid=tradeurl+"&them="+receiveResult.classlist+"&you="+sendResult.classlist;

            let matchTemplate = `
                  <div class="badge_sort_option">
                    <div class="badge_row is_link goo_untradable_note showcase_slot">
                      <div class="notLoggedInText">
			            <img alt="${gameName}" src="https://steamcdn-a.akamaihd.net/steam/apps/${appid}/capsule_184x69.jpg">
                        <div>
                          <div title="View badge progress for this game">
                            <a target="_blank" href="https://steamcommunity.com/my/gamecards/${appid}/">${gameName}</a>
                          </div>
                        </div>
                        <div class="btn_darkblue_white_innerfade btn_medium">
                          <span>
                            <a href="${tradeurlappid}" target="_blank" rel="noopener">Offer a trade</a>
                          </span>
                        </div>
                      </div>
                      <div class="showcase_slot">
                          <div class="showcase_slot profile_header">
                              <div class="badge_info_unlocked profile_xp_block_mid avatar_block_status_in-game badge_info_title badge_row_overlay" style="height: 15px;">You</div>
                              ${sendResult.htmlCards}
                          </div>
                          <span class="showcase_slot badge_info_title booster_creator_actions">
                              <h1>&#10145;</h1>
                          </span>
                      </div>
                      <div class="showcase_slot profile_header">
                          <div class="badge_info_unlocked profile_xp_block_mid avatar_block_status_online badge_info_title badge_row_overlay ellipsis" style="height: 15px;">
                            ${botname}
                          </div>
                        ${receiveResult.htmlCards}
                      </div>
                    </div>
                  </div>
            `;
            matches+=matchTemplate;
            if (globalyou!=""){
                globalyou+=";";
            };
            globalyou+=sendResult.classlist;
            if (globalthem!=""){
                globalthem+=";";
            };
            globalthem+=receiveResult.classlist
        }
        let tradeurlfull = tradeurl+"&them="+globalthem+"&you="+globalyou;
        let rowTemplate = `
            <div class="badge_row">
              <div class="badge_row_inner">
                <div class="badge_title_row guide_showcase_contributors">
                  <div class="badge_title_stats">
                    <div class="btn_darkblue_white_innerfade btn_medium">
                      <span>
                        <a href="${tradeurlfull}" target="_blank" rel="noopener" >Offer a trade for all</a>
                      </span>
                    </div>
                  </div>
                  <div class="badge_title">
                    ${botname}
                  </div>
                </div>
                <div class="badge_title_rule"></div>
                  ${matches}
              </div>
            </div>
        `;
        let template = document.createElement('template');
        template.innerHTML = rowTemplate.trim();
        let maincontent = document.getElementsByClassName("maincontent")[0];
        maincontent.appendChild(template.content.firstChild);
    }

    function DeepClone(object) {
        return JSON.parse(JSON.stringify(object));
    }

    function fetchinventory(steamid,startasset,callback) {
        let url="https://steamcommunity.com/inventory/"+steamid+"/753/6?l=english&count=5000&l=english";
        if (startasset>0) {
            url=url+"&start_assetid="+startasset.toString();
        } else {
            assets.clear();
            descriptions.clear();
        }
        debugPrint(url);
        let xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.responseType = 'json';
        xhr.onload = function() {
            debugPrint("...");
            let status = xhr.status;
            let lastasset=startasset;
            if (status === 200) {
                errors = 0;
                if (typeof(xhr.response) !== 'undefined') {
                    if (typeof(xhr.response.descriptions) !== 'undefined') {
                        assets=assets.concat(xhr.response.assets);
                        descriptions=descriptions.concat(xhr.response.descriptions);
                        if (typeof(xhr.response.last_assetid) == 'undefined') { //end of inventory
                            debugPrint("total_inventory_count = "+xhr.response.total_inventory_count);
                            callback();
                            return;
                        } else {
                            lastasset=xhr.response.last_assetid;
                        }
                    }
                }
            } else {
                errors++;
                debugPrint("HTTP Error="+status);
            }
            if (status==403) {
                assets.clear(); //switch to next bot
                console.log(403);
                callback();
            } else if ((status<400 || status>=500 || status==408)&&(errors <= maxErrors)) {
                setTimeout((function(steamid,startasset,callback) { return function(){ fetchinventory(steamid,startasset,callback); };})(steamid,lastasset,callback), limiter);
            } else {
                UpdateMessage("Error getting inventory, ERROR "+status);
                HideThrobber();
                EnableButton();
            }
        }
        xhr.onerror = function() {
            debugPrint("error getting inventory");
            UpdateMessage("Error getting inventory");
            HideThrobber();
            EnableButton();
        }
        xhr.send();
    }

    function CalcState(badge) { //state 0 - less than max sets; state 1 - we have max sets, even out the rest, state 2 - all even
        let state = 0;
        if (badge.cards[0].count == badge.lastset) {
            return 2; //nothing to do
        } else if (badge.cards[badge.maxcards-1].count == badge.maxsets) {
            return 1; //max sets are here, but we can distribute cards further
        }
        return 0; //less than max sets
    }

    function CompareCards(index,callback) {
        let itemsToSend=[];
        let itemsToReceive=[];
        userbadges.clear();
        userbadges = DeepClone(mybadges);
        for (let i = 0; i < userbadges.length; i++) {
            userbadges[i].cards.clear();
        }
        PopulateExistingCards(userbadges,false);
        debugPrint("bot's cards");
        debugPrint(DeepClone(userbadges));
        debugPrint("our cards");
        debugPrint(DeepClone(mybadges));

        for(let i = 0; i < userbadges.length; i++) {
            let mybadge = DeepClone(mybadges[i]);
            let theirbadge = DeepClone(userbadges[i]);
            let mystate=CalcState(mybadge);
            while (mystate<2) {
                let foundmatch=false;
                for (let j = 0; j<theirbadge.maxcards; j++) { //index of card they give
                    if (theirbadge.cards[j].count > 0) {
                        //try to match
                        //if (bots[index].match_everything) {}
                        let myInd = mybadge.cards.findIndex(a => a.item == theirbadge.cards[j].item); //index of slot where we receive card
                        if (myInd==-1) {
                            debugPrint("we don't have it");
                            let empty = mybadge.cards.find(card => card.item==null);
                            if (empty != undefined) {
                                debugPrint("found a place!");
                                empty.item=theirbadge.cards[j].item;
                                empty.icon_url=theirbadge.cards[j].icon_url;
                                myInd=mybadge.cards.indexOf(empty);
                            } else {
                                debugPrint("Error! We found more cards than expected");
                                debugPrint(DeepClone(mybadge.cards));
                                debugPrint(DeepClone(theirbadge.cards));
                            }
                        }
                        if ((mystate==0 && mybadge.cards[myInd].count < mybadge.maxsets) ||
                            (mystate==1 && mybadge.cards[myInd].count < mybadge.lastset)) { //we need this ^Kfor the Emperor
                            debugPrint("we need this: "+theirbadge.cards[j].item+" ("+theirbadge.cards[j].count+")");
                            //find a card to match.
                            for (let k = 0; k < myInd; k++) { //index of card we give
                                debugPrint("i="+i+" j="+j+" k="+k+" mystate="+mystate);
                                debugPrint("we have this: "+mybadge.cards[k].item+" ("+mybadge.cards[k].count+")");
                                if ((mystate==0 && mybadge.cards[k].count>mybadge.maxsets) ||
                                    (mystate==1 && mybadge.cards[k].count>mybadge.lastset)) { //that's fine for us
                                    debugPrint("it's a good trade for us");
                                    let theirInd = theirbadge.cards.findIndex(a => a.item == mybadge.cards[k].item); //index of slot where they will receive card
                                    if (theirInd == -1) { //they don't even know this card
                                        theirInd = theirbadge.cards.findIndex(a => a.item == null); //index of empty space
                                        //it's safe to assign item name to this card, they don't have it
                                        theirbadge.cards[theirInd].item = mybadge.cards[k].item;
                                    }
                                    if (bots[index].match_everything==0) { //make sure it's neutral+ for them
                                        if (theirbadge.cards[theirInd].count >= theirbadge.cards[j].count) {
                                            debugPrint("Not fair for them")
                                            debugPrint("they have this: "+theirbadge.cards[theirInd].item+" ("+theirbadge.cards[theirInd].count+")");
                                            continue; //it's not neutral+, check other options
                                        }
                                    }
                                    debugPrint("it's a match!");
                                    let itemToSend = {"item":mybadge.cards[k].item,"count":1, "class":mybadge.cards[k].class, "icon_url":mybadge.cards[k].icon_url};
                                    let itemToReceive = {"item":theirbadge.cards[j].item,"count":1, "class":theirbadge.cards[j].class, "icon_url":theirbadge.cards[j].icon_url};
                                    //fill items to send
                                    let sendmatch = itemsToSend.find(item => item.appid == mybadges[i].appid);
                                    if (sendmatch == undefined) {
                                        let newmatch = {"appid":mybadges[i].appid, "title":mybadge.title ,"cards":[ itemToSend ]};
                                        itemsToSend.push(newmatch);
                                    } else {
                                        let existingCard = sendmatch.cards.find(a => a.item == itemToSend.item);
                                        if (existingCard == undefined) {
                                            sendmatch.cards.push(itemToSend);
                                        } else {
                                            existingCard.count += 1;
                                        }
                                    }
                                    //add this item to their inventory
                                    theirbadge.cards[theirInd].count +=1;
                                    //remove this item from our inventory
                                    mybadge.cards[k].count -= 1;

                                    //fill items to receive
                                    let receivematch = itemsToReceive.find(item => item.appid == mybadges[i].appid);
                                    if (receivematch == undefined) {
                                        let newmatch = {"appid":mybadges[i].appid,"title":mybadge.title,"cards":[ itemToReceive ]};
                                        itemsToReceive.push(newmatch);
                                    } else {
                                        let existingCard = sendmatch.cards.find(a => a.item == itemToReceive.item);
                                        if (existingCard == undefined) {
                                            receivematch.cards.push(itemToReceive);
                                        } else {
                                            existingCard.count += 1;
                                        }
                                    }
                                    //add this item to our inventory
                                    mybadge.cards[myInd].count +=1;
                                    //remove this item from their inventory
                                    theirbadge.cards[j].count -= 1;
                                    foundmatch=true;
                                    break; //found a match!
                                }
                            }
                        }
                    }
                }
                if (!foundmatch) {
                    break; //found no matches - move to next badge
                }
                mybadge.cards.sort((a,b)=>b.count-a.count);
                theirbadge.cards.sort((a,b)=>b.count-a.count);
                mystate=CalcState(mybadge);
            }
        }
        debugPrint("items to send");
        debugPrint(DeepClone(itemsToSend));
        debugPrint("items to receive");
        debugPrint(DeepClone(itemsToReceive));
        if (itemsToSend.length>0){
                let url="https://steamcommunity.com/profiles/"+bots[index].steam_id+"?xml=1";
                let xhr = new XMLHttpRequest();
                xhr.open('GET', url, true);
                xhr.responseType = 'text';
                //xhr.setRequestHeader("Range","bytes=0-200"); //fuck it, get the whole page
                xhr.onload = function() {
                    let status = xhr.status;
                    let username=bots[index].steam_id;
                    debugPrint("getting username");
                    if (status === 200) {
                        errors = 0;
                        let re = /<steamID><!\[CDATA\[(.+)]]><\/steamID>/g;
                        username = re.exec(xhr.response)[1];
                        debugPrint(username);
                    }
                    AddMatchRow(itemsToSend,itemsToReceive,username,index);
                    callback();
                };
                xhr.onerror = function() {
                    debugPrint("error");
                    UpdateMessage("Error getting username data");
                    HideThrobber();
                    EnableButton();
                };
            xhr.send();
        } else {
            debugPrint("no matches");
            callback();
        }
    }

    function checkuser(index){
        debugPrint(index);
        UpdateMessage("Fetching bot "+(index+1).toString()+" of "+bots.length.toString());
        UpdateProgress(index);
        fetchinventory(bots[index].steam_id,0,function() {
            debugPrint(bots[index].steam_id);
            debugPrint(assets.length);
            CompareCards(index, function() {
            if (index<bots.length-1) {
                    setTimeout((function(index) { return function(){ checkuser(index); };})(index+1), limiter);
            } else {
                debugPrint("finished");
                if (debug) {
                    console.log(new Date(Date.now()));
                }
                HideThrobber();
                HideMessage();
                UpdateProgress(bots.length);
                EnableButton();
            }
            });
        });
    }

    function PopulateExistingCards(badges, filter){
        debugProfile("PopulateExistingCards1");
        debugPrint(DeepClone(assets));
        debugPrint(DeepClone(descriptions));
        descriptions=descriptions.filter(desc=>badges.find(item=>item.appid==desc.market_hash_name.split("-")[0])!=undefined);
        assets=assets.filter(asset=>descriptions.find(item=>item.classid==asset.classid)!=undefined);
        for (let i = 0; i < assets.length; i++){
            debugPrint(".");
            let descr = descriptions.find(desc=>desc.classid==assets[i].classid);
            if (descr != undefined) {
                let appid=descr.market_hash_name.split("-")[0];
                let title=appid;
                let game_tag=descr.tags.find(tag=>tag.category=="Game");
                if (game_tag != undefined) {
                    title=game_tag.localized_tag_name;
                }
                let item_class_tag=descr.tags.find(tag=>tag.category=="item_class");
                if (item_class_tag != undefined) {
                    if (item_class_tag.internal_name == "item_class_2") {
                        let cardborder_tag=descr.tags.find(tag=>tag.category=="cardborder");
                        if (cardborder_tag != undefined) {
                            if (cardborder_tag.internal_name == "cardborder_0") {
                                let badge = badges.find(badge=>badge.appid==appid);
                                if (badge != undefined) {
                                    let card=badge.cards.find(card=>card.item==descr.market_hash_name);
                                    if (card == undefined) {
                                        let newcard = {"item":descr.market_hash_name, "count":1,"class": assets[i].classid ,"icon_url":descr.icon_url};
                                        badge.cards.push(newcard);
                                        badge.title = title;
                                    } else {
                                        card.count+=1;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        debugProfileEnd("PopulateExistingCards1");
        debugProfile("PopulateExistingCards2");
        for (let i = badges.length-1; i >=0; i--) {
            for (let j = badges[i].cards.length; j < badges[i].maxcards; j++){
                badges[i].cards.push({"item":null, "count":0,"class":0, "icon_url":null}); //fill missing cards with dummy element
            }
            badges[i].cards.sort((a,b)=>b.count-a.count);
            if (filter) {
                if (badges[i].cards[0].count-badges[i].cards[badges[i].cards.length-1].count<2) {
                    //nothing to match, remove from list.
                    badges.splice(i,1);
                    continue;
                }
            }
            let totalcards = 0;
            for (let j = 0; j<badges[i].maxcards; j++) {
                totalcards+=badges[i].cards[j].count;
            }
            badges[i].maxsets = Math.floor(totalcards/badges[i].maxcards);
            badges[i].lastset = Math.ceil(totalcards/badges[i].maxcards);
        }
        debugProfileEnd("PopulateExistingCards2");
    }

    function PopulateMaxcards(index){
        while (index < mybadges.length) {
            if (mybadges[index].maxcards === 0) {
                let url="https://steamcommunity.com/my/gamecards/"+mybadges[index].appid+"?l=english";
                let xhr = new XMLHttpRequest();
                xhr.open('GET', url, true);
                xhr.responseType = 'document';
                xhr.onload = function() {
                    let status = xhr.status;
                    let lastasset=0;
                    if (status === 200) {
                        errors = 0;
                        debugPrint("processing badge "+mybadges[index].appid);
                        UpdateMessage("Getting badge data for "+mybadges[index].appid);
                        let maxcards = xhr.response.documentElement.getElementsByClassName("gamecard").length;
                        mybadges[index].maxcards=maxcards;
                        index++;
                    } else {
                        errors++;
                    }
                    if ((status<400 || status>=500)&&(errors <= maxErrors)) {
                        setTimeout((function(index) { return function(){ PopulateMaxcards(index); };})(index), limiter);
                    } else {
                        UpdateMessage("Error getting badge data, ERROR "+status);
                        HideThrobber();
                        EnableButton();
                    }

                };
                xhr.onerror = function() {
                    debugPrint("error");
                    UpdateMessage("Error getting badge data");
                    HideThrobber();
                    EnableButton();
                };
                xhr.send();
                return; //do this synchronously to avoid rate limit
            } else {
                index++;
            }
        }
        debugPrint("populated");
        UpdateMessage("Fetching own inventory");
        //g_steamID is a global steam variable
        fetchinventory(g_steamID,0,function(){
            debugPrint("fetched");
            debugPrint(DeepClone(assets));
            debugPrint(DeepClone(descriptions));
            debugPrint("our cards");
            debugPrint(DeepClone(mybadges));
            PopulateExistingCards(mybadges,true);
            checkuser(0);
        });
    }

    function getbadges(page){
        let url="https://steamcommunity.com/my/badges?p="+page+"&l=english";
        let xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.responseType = 'document';
        xhr.onload = function() {
            let status = xhr.status;
            if (status === 200) {
                errors = 0;
                debugPrint("processing page "+page);
                UpdateMessage("Processing badges page "+page);
                if (page===1) {
                    let pagelinks=xhr.response.documentElement.getElementsByClassName("pagelink");
                    if (pagelinks.length>0) {
                        maxpages=Number(pagelinks[pagelinks.length-1].textContent.trim());
                    }
                }
                let badges=xhr.response.documentElement.getElementsByClassName("badge_row_inner");
                for (let i=0;i<badges.length;i++){
                    if (badges[i].getElementsByClassName("owned").length>0){ //we only need badges where we have at least one card, and no special badges
                        let appidNodes = badges[i].getElementsByClassName("card_drop_info_dialog");
                        if (appidNodes.length>0) {
                            let appidText=appidNodes[0].getAttribute("id");
                            let appidSplitted = appidText.split("_");
                            if (appidSplitted.length >= 5) {
                                let appid = Number(appidSplitted[4]);
                                let maxcards=0;
                                if (badges[i].getElementsByClassName("badge_craft_button").length === 0 ){
                                    let maxcardsText=badges[i].getElementsByClassName("badge_progress_info")[0].innerText.trim()
                                    let maxcardsSplitted=maxcardsText.split(" ");
                                    maxcards = Number(maxcardsSplitted[2]);
                                }
                                let badge_stub = {"appid":appid,"title":null, "maxcards":maxcards, "maxsets":0, "lastset":0, "cards":[]};
                                mybadges.push(badge_stub);
                            }
                        }
                    }
                }
                page++;
            } else {
                errors++;
            }
            if ((status<400 || status>=500)&&(errors <= maxErrors)) {
                if (page<=maxpages) {
                    setTimeout((function(page) { return function(){ getbadges(page); };})(page), limiter);
                } else {
                    debugPrint("all badge pages processed");
                    if (mybadges.length===0){
                        HideThrobber();
                        UpdateMessage("No cards to match");
                        return;
                    } else {
                        PopulateMaxcards(0);
                    }
                }
            } else {
                UpdateMessage("Error getting badge data, ERROR "+status);
                HideThrobber();
                EnableButton();
            }
        };
        xhr.onerror = function() {
            debugPrint("error getting badge page");
            UpdateMessage("Error getting badge page");
            HideThrobber();
            EnableButton();
        };
        xhr.send();
    }

    function ButtonPressed(){
        DisableButton();
        if (debug) {
            console.log(new Date(Date.now()));
        }
        let maincontent = document.getElementsByClassName("maincontent")[0];
        maincontent.textContent="";
        maincontent.style.width="90%";
        maincontent.innerHTML=`
          <div class="profile_badges_header">
            <div id="throbber">
				<div class="LoadingWrapper">
					<div class="LoadingThrobber">
						<div class="Bar Bar1"></div>
						<div class="Bar Bar2"></div>
						<div class="Bar Bar3"></div>
					</div>
				</div>
			</div>
            <div>
            <div id="asf_stm_messagebox" class="profile_badges_header">
			   <div id="asf_stm_message" class="profile_badges_header_title" style="text-align: center;">Initialization</div>
		    </div>
            </div>
            <div class="profile_xp_block_remaining_bar">
				<div id="asf_stm_progress" class="profile_xp_block_remaining_bar_progress" style="width: 0%"></div>
			</div>
          </div>
        `;
        maxpages=1;
        getbadges(1);
    }

    if (document.getElementsByClassName("badge_details_set_favorite").length != 0) {
        let requestURL = 'https://asf.justarchi.net/Api/Bots';
        GM_xmlhttpRequest({
            method: "GET",
            url: requestURL,
            onload: function(response) {
                let re = /("steam_id":)(\d+)/g;
                let fixedjson = response.response.replace(re, '$1\"$2\"'); //because fuck js
                bots = JSON.parse(fixedjson);
                //bots.filter(bot=>bot.matchable_cards===1||bot.matchable_foil_cards===1);  //I don't think this is really needed
                bots.sort(function(a,b) { //sort received array as I like it.
                    let result = b.match_everything - a.match_everything; //bots with match_everything go first
                    if (result===0) {
                        result = b.items_count - a.items_count; //then by items_counts descending
                    }
                    if (result===0) {
                        result = b.games_count - a.games_count; //then by games_count descending
                    }
                    return result;
                });
                debugPrint ("found total "+bots.length+" bots");
                let buttondiv =document.createElement("div");
                buttondiv.setAttribute("class","profile_small_header_additional");
                buttondiv.setAttribute("style","margin-top: 40px;");
                buttondiv.setAttribute("id","asf_stm_button_div");
                let button = document.createElement("a");
                button.setAttribute("class","btnv6_blue_hoverfade btn_medium");
                button.setAttribute("id","asf_stm_button");
                button.appendChild(document.createElement("span"));
                button.firstChild.appendChild(document.createTextNode("Scan ASF STM"))
                buttondiv.appendChild(button);
                let anchor = document.getElementsByClassName("profile_small_header_texture")[0];
                anchor.appendChild(buttondiv);
                EnableButton();
            }
        });
    }
})();


QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址