Steam Show Purchase History by Type

在Steam账户消费历史页面,显示指定类别的消费历史。Show purchases of checked types on Steam account purchase history site.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Steam Show Purchase History by Type
// @namespace    http://tampermonkey.net/
// @version      0.2.2
// @description  在Steam账户消费历史页面,显示指定类别的消费历史。Show purchases of checked types on Steam account purchase history site.
// @author       lyzlyslyc
// @match        http*://store.steampowered.com/account/history*
// @icon         https://store.steampowered.com/favicon.ico
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @connect      open.er-api.com
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    //货币单位和货币缩写的映射
    let currencySymbolMap = {
        "$ USD":"USD",
        "$": "USD",
        "£": "GBP",
        "€": "EUR",
        "CHF": "CHF",
        "pуб.": "RUB",
        "R$": "BRL",
        "¥": "CNY",
        "kr": "SEK",
        "Rp": "IDR",
        "RM": "MYR",
        "P": "PHP",
        "S$": "SGD",
        "฿": "THB",
        "₫": "VND",
        "₩": "KRW",
        "TL": "TRY",
        "₴": "UAH",
        "Mex$": "MXN",
        "CDN$": "CAD",
        "A$": "AUD",
        "NZ$": "NZD",
        "zł": "PLN",
        "₹": "INR",
        "CLP$": "CLP",
        "S/.": "PEN",
        "COL$": "COP",
        "R": "ZAR",
        "HK$": "HKD",
        "NT$": "TWD",
        "SR": "SAR",
        "AED": "AED",
        "ARS$": "ARS",
        "₪": "ILS",
        "Br": "BYN",
        "₸": "KZT",
        "KD": "KWD",
        "QR": "QAR",
        "₡": "CRC",
        "$U": "UYU",
        "лв": "BGN",
        "kn": "HRK",
        "Kč": "CZK",
        "kr.": "DKK",
        "Ft": "HUF",
        "lei": "RON",
        "刀币": "RMB",
        "원": "NXP"
    };

    // Your code here...
    let classified_history = {};
    let market_type = "";
    let market_item_name = "";
    let market_single_type = "";
    let is_market_type_found = false;
    let conversion_type = "充值";
    let is_conversion_type_found = false;
    let walletCurrencyCode = getWalletCurrencyCode();
    let transactions_type = {};
    if(walletCurrencyCode===undefined)walletCurrencyCode="CNY";
    //寻找市场交易的特殊类型
    document.querySelectorAll(".wallet_table_row ").forEach(row=>{
        //"转换"类型
        if(!is_conversion_type_found){
            if(row.querySelector(".wht_wallet_change")==null)return;
            if(row.querySelector(".wht_wallet_change").innerText==""&&row.querySelector(".wht_total").innerText==""){
                let typeStr = row.querySelector("td.wht_type > div:nth-child(1)").innerText.replace(/^\d* */,"");
                classified_history[typeStr]=[];
                conversion_type = typeStr;
                is_conversion_type_found = true;
                return;
            }
        }
        //市场交易复数类型,因为在某些语言下市场交易类型有单复数之分
        if(!is_market_type_found){
            if(row.querySelector("td.wht_type > div:nth-child(1)").innerText.match(/^[023456789](\d+)? */)!=null){
                let typeStr = row.querySelector("td.wht_type > div:nth-child(1)").innerText.replace(/^\d* */,"");
                classified_history[typeStr]=[];
                market_type = typeStr;
                market_item_name = row.querySelector(".wht_items").innerText.strip();
                is_market_type_found=true;
                return;
            }
        }
    })
    //遍历记录
    if(classified_history[conversion_type]===undefined)classified_history[conversion_type]=[];
    document.querySelectorAll(".wallet_table_row ").forEach(row=>{
        //如果是数字充值卡,放入转换类型
        if(row.querySelector("td.wht_type").innerText==""){
            classified_history[conversion_type].push(row);
            row.type = "conversion";
            return;
        }
        let typeStr = row.querySelector("td.wht_type > div:nth-child(1)").innerText.replace(/^\d* */,"");
        if(classified_history[typeStr]===undefined){
            //如果找到市场复数类型,且新类型的物品名称和复数类型的物品名称一样,则说明是市场单数类型
            if(is_market_type_found){
                if(row.querySelector(".wht_items").innerText.strip()==market_item_name){
                    //记录类型名字
                    market_single_type = typeStr;
                }
            }
            classified_history[typeStr]=[];
        }
        //如果类型是市场单数类型,把记录合并进复数类型集合
        if(typeStr==market_single_type||typeStr==market_type){
            classified_history[market_type].push(row);
            row.type = "market";
        }
        //如果是钱包充值,放进转换类型
        else if(row.querySelector(".wht_items > div")==null){
            classified_history[conversion_type].push(row);
            row.type = "wallet";
        }
        else if(row.querySelector(".wht_items > .wth_payment")!=null){
            //礼物类型
            if(row.querySelector(".wht_items > .wth_payment > div")!=null)row.type="gift";
            //内购类型
            else row.type = "ingame";
            //退款类型
            if(row.querySelector(".wht_items > .wth_item_refunded")!=null)row.type="refund";
            classified_history[typeStr].push(row);
        }
        //退款类型
        else if (row.querySelector(".wht_items > .wth_item_refunded") != null) {
            //充值退款放进转换类型
            if (row.querySelector(".wht_items").innerText.indexOf(row.querySelector(".wht_total").innerText) != -1) {
                row.type = "wallet";
                classified_history[conversion_type].push(row);
            }
            //游戏退款
            else {
                row.type = "refund";
                classified_history[typeStr].push(row);
            }
        }
        //购买类型
        else {
            row.type = "purchase";
            classified_history[typeStr].push(row);
        }

        //查询各记录货币情况
        let total = row.querySelector("td.wht_total");
        if(total.innerText=="")total = row.querySelector("td.wht_wallet_balance");
        if(total&&total.querySelector("div")!=null)total=total.children[0];
        if(total==null)row.currencyCode===undefined;
        else row.currencyCode = currencySymbolMap[total.innerText.replace(/\(.*\)/g,"").replace(/\d+((.|,)\d+)*/g,"").strip()];
        if(row.currencyCode===undefined)row.currencyCode = walletCurrencyCode;
        //记录交易id类型
        if(row.getAttribute("onclick")!=null){
            let match = row.getAttribute("onclick").match(/transid=(\d+)/);
            if(match!=null){
                row.transid=match[1];
                if(row.type!="refund")transactions_type[match[1]]=row.type;
            }
        }
    })

    let div = document.createElement("div");
    div.className = "wallet_history_click_hint";
    div.innerHTML="<span style='padding:0px 10px;'>类型</span>";
    //添加搜索框
    let input_span = document.createElement("span");
    input_span.style="float:right;color:#ffffff;";
    input_span.append("搜索:");
    let input = document.createElement("input");
    input.oninput = ()=>{
        if(input.value==""){
            document.querySelectorAll(".wallet_table_row ").forEach(row=>{
                if(row.isShown)row.style.display="table-row";
                else row.style.display="none";
            })
        }
        document.querySelectorAll(".wallet_table_row ").forEach(row=>{
            if(!row.isShown)return;
            if(row.innerText.match(new RegExp(input.value,"i"))!=null)row.style.display="table-row";
            else row.style.display="none";
        })
    }
    input_span.append(input);
    //创建复选框
    for(let type in classified_history){
        //如果是单数类型,不创建按钮
        if(classified_history[type]===undefined||classified_history[type].length<=0)continue;
        let span = document.createElement("span");
        span.className = "history-type-container";
        span.style = "margin:0px 10px;color: #ffffff;";
        let check = document.createElement("input");
        check.value = type;
        check.className = "history-type-checkbox";
        check.type = "checkbox";
        check.style = "vertical-align: text-top;margin-right: 3px;";
        check.addEventListener("click",(e)=>{
            showRows(type,check.checked);
            input.oninput();
        })
        span.append(check);
        span.append(type);
        div.append(span);
    }
    //添加至页面
    div.append(input_span);
    document.querySelector("#main_content").insertBefore(div,document.querySelector("table.wallet_history_table"));

    //礼物计算部分
    let gift_div = document.createElement("div");
    gift_div.className = "wallet_history_click_hint";
    gift_div.innerHTML+=`
    <span style="padding: 0px 10px">一共花费: <span id="spendAmount"></span><span id="refundAmount"></span></span>
	<span style="padding: 0px 10px">送出礼物: <span id="giftAmount"></span><span id="giftRefundAmount"></span></span>
	<span style="padding: 0px 10px">礼物额度(一共花费-送出礼物): <span id="availableAmount"></span></span>`;
    let gift_btn = document.createElement("a");
    gift_btn.className = "btnv6_blue_hoverfade";
    gift_btn.style = "padding: 0px 10px;";
    gift_btn.innerText = "计算";
    gift_btn.href = "javascript:;";
    gift_btn.addEventListener("click",(e)=>{
        Promise.all([loadAll(),getRate(walletCurrencyCode)]).then(results=>{
            let result = calculateGifts(results[1]);
            document.querySelector("#spendAmount").innerText = GStoreItemData.fnFormatCurrency(result.spend);
            document.querySelector("#giftAmount").innerText = GStoreItemData.fnFormatCurrency(result.gift);
            document.querySelector("#availableAmount").innerText = GStoreItemData.fnFormatCurrency(result.gift_remain);
            if(result.refund>0)document.querySelector("#refundAmount").innerText = `(${GStoreItemData.fnFormatCurrency(result.refund)}已退款)`;
            if(result.gift_refund>0) document.querySelector("#giftRefundAmount").innerText = `(${GStoreItemData.fnFormatCurrency(result.gift_refund)}已退款)`;
        })
    })
    gift_div.prepend(gift_btn);
    document.querySelector("#main_content").insertBefore(gift_div,div);


    //记录加载监视器
    let observer = new MutationObserver((mutations)=>{
        mutations.forEach((mutation)=>{
            if(mutation.type=="childList"){
                //如果仍未找到市场复数类型,先寻找该类型
                if(!is_market_type_found||!is_conversion_type_found){
                    mutation.addedNodes.forEach(row=>{
                        if(row.querySelector===undefined)return;
                        if(row.querySelector("td.wht_type").innerText=="")return;
                        let typeStr = row.querySelector("td.wht_type > div:nth-child(1)").innerText.replace(/^\d* */,"");
                        if(!is_conversion_type_found){
                            if(row.querySelector(".wht_wallet_change")&&row.querySelector(".wht_wallet_change").innerText==""&&row.querySelector(".wht_total").innerText==""){
                                classified_history[typeStr]=classified_history[conversion_type].clone();
                                delete classified_history[conversion_type];
                                conversion_type = typeStr;
                                is_conversion_type_found = true;
                            }
                        }
                        if(!is_market_type_found){
                            if(row.querySelector("td.wht_type > div:nth-child(1)").innerText.match(/^[023456789](\d+)? */)!=null){
                                classified_history[typeStr]=[];
                                market_type = typeStr;
                                market_item_name = row.querySelector(".wht_items").innerText.strip();
                                is_market_type_found=true;
                                //将之前的类型合并
                                for(let type in classified_history){
                                    if(type==typeStr)continue;
                                    if(classified_history[type].length<=0)continue;
                                    if(classified_history[type][0].querySelector(".wht_items").innerText.strip()==market_item_name){
                                        for(let i=0;i<classified_history[type].length;i++)classified_history[typeStr].push(classified_history[type][i]);
                                        classified_history[type]=[];
                                        market_single_type=type;
                                    }
                                }
                            }
                        }
                    });
                }
                //遍历新增的记录
                mutation.addedNodes.forEach(row=>{
                    if(row.querySelector===undefined)return;
                    if(row.querySelector("td.wht_type").innerText==""){
                        classified_history[conversion_type].push(row);
                        row.type = "wallet";
                        return;
                    }
                    let typeStr = row.querySelector("td.wht_type > div:nth-child(1)").innerText.replace(/^\d* */,"");
                    //出现新的类型
                    if(classified_history[typeStr]===undefined){
                        if(is_market_type_found){
                            if(row.querySelector(".wht_items").innerText.strip()==market_item_name){
                                market_single_type = typeStr;
                            }
                        }
                        classified_history[typeStr]=[];
                    }
                    //如果类型是市场单数类型,把记录合并进复数类型集合
                    if(typeStr==market_single_type||typeStr==market_type){
                        classified_history[market_type].push(row);
                        row.type = "market";
                    }
                    //如果是钱包充值,放进转换类型
                    else if(row.querySelector(".wht_items > div")==null){
                        classified_history[conversion_type].push(row);
                        row.type = "wallet";
                    }
                    else if(row.querySelector(".wht_items > .wth_payment")!=null){
                        //礼物类型
                        if(row.querySelector(".wht_items > .wth_payment > div")!=null)row.type="gift";
                        //内购类型
                        else row.type = "ingame";
                        //退款类型
                        if(row.querySelector(".wht_items > .wth_item_refunded")!=null)row.type="refund";
                        classified_history[typeStr].push(row);
                    }
                    //退款类型
                    else if (row.querySelector(".wht_items > .wth_item_refunded") != null) {
                        //充值退款放进转换类型
                        if (row.querySelector(".wht_items").innerText.indexOf(row.querySelector(".wht_total").innerText) != -1) {
                            row.type = "wallet";
                            classified_history[conversion_type].push(row);
                        }
                        //游戏退款
                        else {
                            row.type = "refund";
                            classified_history[typeStr].push(row);
                        }
                    }
                    //购买类型
                    else {
                        row.type = "purchase";
                        classified_history[typeStr].push(row);
                    }

                    //确定记录的货币
                    let total = row.querySelector("td.wht_total");
                    if(total.innerText=="")total = row.querySelector("td.wht_wallet_balance");
                    if(total&&total.querySelector("div")!=null)total=total.children[0];
                    if(total==null)row.currencyCode===undefined;
                    else row.currencyCode = currencySymbolMap[total.innerText.replace(/\(.*\)/g,"").replace(/\d+((.|,)\d+)*/g,"").strip()];
                    if(row.currencyCode===undefined)row.currencyCode = walletCurrencyCode;
                    //记录交易id类型
                    if(row.getAttribute("onclick")!=null){
                        let match = row.getAttribute("onclick").match(/transid=(\d+)/);
                        if(match!=null){
                            row.transid=match[1];
                            if(row.type!="refund")transactions_type[match[1]]=row.type;
                        }
                    }
                });

                //记录按钮的状态,并删除勾选框
                let checks = document.querySelectorAll(".history-type-container");
                let checked = {};
                for(let i=0;i<checks.length;i++){
                    let check = checks[i].querySelector(".history-type-checkbox");
                    checked[check.value] = check.checked;
                    checks[i].remove();
                }
                //重新添加勾选框(有可能原先没有市场复数类型,现在有了,所以要重新添加)
                for(let type in classified_history){
                    if(classified_history[type]===undefined||classified_history[type].length<=0)continue;
                    let span = document.createElement("span");
                    span.className = "history-type-container";
                    span.style = "margin-left: 5px;color: #ffffff;";
                    let check = document.createElement("input");
                    check.value = type;
                    check.className = "history-type-checkbox";
                    check.type = "checkbox";
                    check.style = "vertical-align: text-top;margin-right: 3px;";
                    check.addEventListener("click",(e)=>{
                        showRows(type,check.checked);
                        input.oninput();
                    })
                    span.append(check);
                    span.append(type);
                    div.append(span);
                    //还原按钮的状态
                    if(checked[type]!==undefined)check.checked=checked[type];
                    else if((type==market_type)&&(checked[market_single_type]!==undefined))check.checked=checked[market_single_type];
                }
                document.querySelectorAll(".history-type-checkbox").forEach((ele)=>{showRows(ele.value,ele.checked)});
            }
        });
    })
    observer.observe(document.querySelector("table.wallet_history_table > tbody"),{childList:true});
    document.querySelectorAll(".history-type-checkbox").forEach((ele)=>{ele.click()});

    //按照类别显示记录
    function showRows(type,visible){
        for(let i=0;i<classified_history[type].length;i++){
            if(visible==true){
                classified_history[type][i].style.display="table-row";
                classified_history[type][i].isShown = true;
            }
            else {
                classified_history[type][i].style.display="none";
                classified_history[type][i].isShown = false;
            }
        }
    }

    //获取钱包的货币代码
    function getWalletCurrencyCode(){
        let format = GStoreItemData.fnFormatCurrency(0).replace(/\d+((.|,)\d+)*/g,"").strip();
        return currencySymbolMap[format];
    }

    //获取汇率
    function getRate(currencyCode){
        return new Promise((resolve,reject)=>{
            let rates = GM_getValue("rates");
            if(rates===undefined||rates[currencyCode]==undefined||(new Date()-rates[currencyCode].time_last_request_unix>86400000)){
                console.log("Updating rates...");
                GM_xmlhttpRequest({
                    method: "get",
                    url:`https://open.er-api.com/v6/latest/${currencyCode}`,
                    onload: (result)=>{
                        let data = JSON.parse(result.response);
                        data.time_last_request_unix = new Date().getTime();
                        if(rates===undefined)rates={};
                        rates[currencyCode] = data;
                        GM_setValue("rates",rates);
                        console.log(rates);
                        resolve(data.rates);
                    }
                });
            }
            else resolve(rates[currencyCode].rates);
        })
    }

    //计算礼物额度
    function calculateGifts(rates){
        let spend = 0;
        let gift = 0;
        let refund = 0;
        let gift_refund = 0;
        let rows = document.querySelectorAll(".wallet_table_row ");
        for(let i=0;i<rows.length;i++){
            if(rows[i].type!="purchase"&&rows[i].type!="gift"&&rows[i].type!="refund")continue;
            if(rows[i].currencyCode===undefined)rows[i].currencyCode = walletCurrencyCode;
            let total = rows[i].querySelector(".wht_total").innerText;
            let price = parseInt(total.replace(/\(.*\)/g,"").replace(/[^\d]/g,""))/rates[rows[i].currencyCode];
            switch(rows[i].type){
                case "purchase":
                    spend+=price;
                    break;
                case "gift":
                    gift+=price;
                    break;
                case "refund":
                    //只有购买游戏或者礼物才会加入计算
                    if(transactions_type[rows[i].transid]=="purchase")refund+=price;
                    else if(transactions_type[rows[i].transid]=="gift")gift_refund+=price;
                    break;
                default:
                    break;
            }
        }
        return {
            "spend":parseInt(spend),
            "gift":parseInt(gift),
            "gift_remain":parseInt(spend)-parseInt(gift)-parseInt(refund)+parseInt(gift_refund),
            "gift_refund":parseInt(gift_refund),
            "refund":parseInt(refund)
        }
    }

    //加载所有记录
    function loadAll(){
        return loadHistory().then((result)=>{
            if(result=="load")return loadAll();
            else return "done";
        })
    }

    //加载一次记录
    function loadHistory(){
        return new Promise(function(resolve){
            $J('#load_more_button').hide();
            if ( g_historyCursor == null )
                resolve("done");

            var request_data = {
                cursor: g_historyCursor,
                sessionid: g_sessionID
            };

            g_historyCursor = null;

            $J('#wallet_history_loading').show();
            $J.ajax({
                type: "POST",
                url: "https://store.steampowered.com/account/AjaxLoadMoreHistory/",
                data: request_data
            }).done( function( data ) {
                if ( data.html )
                {
                    var elem_prev = $J('#more_history').prev();

                    $J('#more_history').before( data.html );

                    var new_elems = elem_prev.nextAll();
                    new_elems.hide();


                    new_elems.fadeIn( 500 );

                    WalletHistory_BindTooltips();
                }

                if ( data.cursor )
                {
                    g_historyCursor = data.cursor;
                    $J('#load_more_button').fadeIn( 50 );
                    resolve("load");

                }
                else
                {
                    $J('#load_more_button').hide();
                    resolve("done");
                }
            }).always( function() {
                $J('#wallet_history_loading').hide();
            } );
        });
    }
})();