Complete Your Set - Steam Forum Trading Helper

Automatically detects missing cards from a card set, help you auto-fill New Trading Thread input areas

当前为 2018-05-30 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Complete Your Set - Steam Forum Trading Helper
// @icon         https://store.steampowered.com/favicon.ico
// @namespace    https://github.com/tkhquang
// @version      0.8
// @description  Automatically detects missing cards from a card set, help you auto-fill New Trading Thread input areas
// @author       Aleks
// @license      MIT; https://raw.githubusercontent.com/tkhquang/userscripts/master/LICENSE
// @homepage     https://greasyfork.org/en/scripts/368518-complete-your-set-steam-forum-trading-helper/
// @match        *://steamcommunity.com/*/*/gamecards/*
// @match        *://steamcommunity.com/app/*/tradingforum/*
// @match        *://steamcommunity.com/app/*/tradingforum
// @run-at       document-idle
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// ==/UserScript==

var tradeTag = 2;
//1 = #Number of Set in Title
//2 = Card Name in Title
//Default is 2
var tradeMode = 0;
//0 - List both Owned and Unonwed Cards
//1 - Only List Owned Cards
//2 - Only List Unowned Cards
//Default is 0
var badgeMode = 1;
//0 - Don't check for number of cards to full set, this is more like a cards lister
//1 - Only check for game set that you have enough cards to make it full
//2 - Complete your remaining set
//Default is 1
var badgeNumSet = 0;
//0 - Don't set a target number of Card Sets
//Others - Set a target number for Card Sets - This will also set 'badgeMode = 2'
//Default is 0
var useLocalStorage = false;
//Use HTML5 Local Storage instead, set this to true if you're using Greasemonkey
//Default is false
var customBody = "\n[1:1] Trading";
var customTitle = " [1:1]";
var haveListText = "[H]\n";
var wantListText = "[W]\n";
var haveListTextTitle = "[H] ";
var wantListTextTitle = "[W] ";

//Codes

var CYSstorage = {};

var replaceOwned = new Map([
    [/\s{2,}/g, " "],
    [/\s(\d+)\ of \d+\, Series \d+\s$/, "=.=$1"],
    [/^\s\((\d+)\)\s/, "$1=.="]
]);
var replaceUnowned = new Map([
    [/\s{2,}/g, " "],
    [/\s(\d+)\ of \d+\, Series \d+\s$/, "=.=$1"],
    [/^\s/, "0=.="]
]);
function clean(str, replacements) {
    replacements.forEach(function(value, key){
        str = str.replace(key, value);
    });
    return str;
}

function getOwnedCards() {
    let ownedCards = document.querySelectorAll(".badge_card_set_card.owned");
    let owned = [];
    for (let i=0; i < ownedCards.length; i++) {
        owned[i] = clean(ownedCards[i].textContent,replaceOwned);
        owned[i] = owned[i].split("=.=");
    }
    //console.log(owned);
    return owned;
}

function getUnownedCards() {
    let unownedCards = document.querySelectorAll(".badge_card_set_card.unowned");
    let unowned = [];
    for (let i=0; i < unownedCards.length; i++) {
        unowned[i] = clean(unownedCards[i].textContent,replaceUnowned);
        unowned[i] = unowned[i].split("=.=");
    }
    //console.log(unowned);
    return unowned;
}

function sort(arr, index) {
    let sort = [];
    sort = Array(arr.length).fill().map((v,i)=>i+1);
    arr = arr.map(function(item) {
        var n = sort.indexOf(Number(item[index]));
        sort[n] = "";
        return [n, item];
    }).sort().map(function(j) {
        return j[1];
    });
    return arr;
}

var allCards = [];
function getAllCards() {
    let ulallCards = getOwnedCards().concat(getUnownedCards());
    allCards = sort(ulallCards, 2);
    getTotal();
    //console.log(allCards);
}

var totalCards = [];
var total = 0;
function getTotal() {
    for (let i=0; i < allCards.length; i++) {
        let curCard = allCards[i];
        totalCards.push(curCard[0]);
        total += Number(totalCards[i]);
    }
    //console.log(totalCards);
    console.log("Number of cards you've owned: " + total);
    badgeCheck();
}

var badgeNum;
function badgeCheck() {
    if (badgeNumSet !== 0) {
        badgeMode = 2;
        badgeNum = badgeNumSet;
        console.log("Target Set :"+badgeNumSet);
    }
    else {
        switch(badgeMode) {
            case 0:
                badgeNum = 0;
                break;
            case 1:
                badgeNum = Math.floor(total / allCards.length);
                console.log("Your cards are enough to craft " + badgeNum + " badge(s)");
                break;
            case 2:
                var remainSet = (total / allCards.length !== 1) ? true : false;
                if (remainSet === true) {
                    badgeNum = Math.floor(total / allCards.length + 1);
                    console.log("You need some cards to complete your remaining set\nTotal: "+badgeNum);
                }
                if (remainSet === false) {
                    badgeNum = Math.floor(total / allCards.length);
                }
                break;
        }
    }
    function tradeNeed(value) {
        let tradeCheck = false;
        for (let i=0; i < allCards.length; i++) {
            if (totalCards[i] < badgeNum) {
                tradeCheck = true;
                break;
            }
        }
        return tradeCheck === value;
    }
    if (badgeMode !==0 && tradeNeed(false)) {
        console.log("You don't need to do trading for now");
        return;
    }
    console.log("You can visit trading forum to complete your sets");
    calcTrade();
}

var haveList = [];
var wantList = [];
function calcTrade() {
    let dupCards;
    let needCards;
    for (let i=0; i < allCards.length; i++) {
        if (totalCards[i] > badgeNum) {
            let curCard = allCards[i];
            dupCards = (badgeMode === 0) ? Number(totalCards[i]) : totalCards[i] - badgeNum;
            haveList.push([
                dupCards,
                curCard[2],
                curCard[1]
            ]);
        }
        if ((totalCards[i] < badgeNum)||(badgeMode===0&&totalCards[i]==badgeNum)) {
            let curCard = allCards[i];
            needCards = (badgeMode === 0) ? Number(totalCards[i]) : badgeNum - totalCards[i];
            wantList.push([
                needCards,
                curCard[2],
                curCard[1]
            ]);
        }
    }
    //console.log(haveList); console.log(wantList);
    createText();
}

function createText() {
    for (let i=0; i < haveList.length; i++) {
        if (tradeMode !== 2 && haveList.length > 0) {
            let dup = haveList[i];
            haveListText += dup[1] + " - " + dup[2] + " - x" + dup[0] + "\n";
            haveListTextTitle += dup[tradeTag] + " (x" + dup[0] + "), ";
        }
    }
    for (let i=0; i < wantList.length; i++) {
        if (tradeMode !== 1 && wantList.length > 0) {
            let need = wantList[i];
            wantListText += need[1] + " - " + need[2] + " - x" + need[0] + "\n";
            wantListTextTitle += need[tradeTag] + " (x" + need[0] + "), ";
        }
    }
    haveListTextTitle = haveListTextTitle.replace(/\), $/, ") ");
    wantListTextTitle = wantListTextTitle.replace(/\), $/, ")");
    let CYStext = JSON.stringify([
        haveListText+"\n"+wantListText,
        haveListTextTitle + wantListTextTitle,
        window.location.pathname.split("/")[4],
        Date.now()
    ]);
    CYSstorage.storageSet(CYStext);
    createButton();
}

function inTrade() {
    if (document.querySelector(".btn_darkblue_white_innerfade.btn_medium.responsive_OnClickDismissMenu") === null) {
        console.log("CYS - Something is wrong, have you logged in?");
        return;
    }
    document.querySelector(".btn_darkblue_white_innerfade.btn_medium.responsive_OnClickDismissMenu").click();
    document.querySelector(".forumtopic_reply_textarea").textContent = CYSstorage.storageItem(0) + customBody;
    document.querySelector(".forum_topic_input").value = CYSstorage.storageItem(1) + customTitle;
    setTimeout(function(){
        CYSstorage.storageClear();
    }, 1000);
}

function createButton() {
    var a = document.createElement("a");
    a.className = "btn_grey_grey btn_medium";
    a.href = "https://steamcommunity.com/app/"+window.location.pathname.split("/")[4]+"/tradingforum/";
    a.innerHTML = "<span>Visit Trading Forum</span>";
    document.querySelector(".gamecards_inventorylink").appendChild(a);
}

var numChecks = [
    !(Number.isInteger(badgeNumSet)&&badgeNumSet>=0),
    [1,2].indexOf(tradeTag)==-1,
    [0,1,2].indexOf(tradeMode)==-1,
    [0,1,2].indexOf(badgeMode)==-1,
    typeof(useLocalStorage)!=="boolean"
], GMChecks = [
    typeof GM_setValue!=="undefined",
    typeof GM_getValue!=="undefined",
    typeof GM_deleteValue!=="undefined"
];
function configCheck(condi,value) {
    return condi.some(function(config) {
        return config === value;
    });
}

function getStorage(mode) {
    let storageItem,storageInv,storageClear,storageSet;
    if (!mode) {
        storageInv = function() {
            return ((GM_getValue("CYS-STORAGE"))&&(GM_getValue("CYS-STORAGE").length>0)) ? true : false;
        };
        storageItem = function(index) {
            return JSON.parse(GM_getValue("CYS-STORAGE"))[index];
        };
        storageClear = function() {
            GM_deleteValue("CYS-STORAGE");
            console.log("CYS - GM Storage Cleared");
        };
        storageSet = function(content) {
            GM_setValue("CYS-STORAGE", content);
        };
    }
    if (mode) {
        storageInv = function() {
            return ((window.localStorage.cardTrade)&&(window.localStorage.cardTrade.length>0)) ? true : false;
        };
        storageItem = function(index) {
            return JSON.parse(localStorage.cardTrade)[index];
        };
        storageClear = function() {
            window.localStorage.removeItem("cardTrade");
            console.log("CYS - Local Storage Cleared");
        };
        storageSet = function(content) {
            window.localStorage.cardTrade = content;
        };
    }
    return {storageInv,storageItem,storageClear,storageSet};
}

(function() {
    "use strict";

    if (configCheck(numChecks,true)) {
        alert("CYS - Invalid Config Settings\nPlease Check Again!");
        return;
    } else if ((!useLocalStorage)&&configCheck(GMChecks,false)) {
        useLocalStorage=true;
        console.log("CYS - GM functions are not defined - Switch to use HTML5 Local Storage instead");
    }
    CYSstorage = getStorage(useLocalStorage);
    if (/\/gamecards/.test(window.location.pathname)) {
        if (document.querySelector(".gamecards_inventorylink") === null) {
            console.log("Not your profile?");
            return;
        } else if (CYSstorage.storageInv()) {
            CYSstorage.storageClear();
        }
        getAllCards();
    }
    if (/\/tradingforum/.test(window.location.pathname)) {
        if (!CYSstorage.storageInv()) {
            console.log("CYS - No Stored Trade Info In Storage");
            return;
        } else if ((new RegExp(CYSstorage.storageItem(2))).test(window.location.pathname)) {
            let storedTime = Date.now() - CYSstorage.storageItem(3);
            console.log("CYS - Time: "+storedTime+"ms");
            if (storedTime>21600000) {
                if (window.confirm("CYS - It's been more than 6 hours since you checked your cards\n" +
                                   "It's better to check again\n"+
                                   "Press OK to go to your GameCard Page")) {
                    window.open("https://steamcommunity.com/my/gamecards/"+CYSstorage.storageItem(2),"_blank");
                    return;
                }
            }
            setTimeout(inTrade,1000);
        }
    }
})();