Lex's SG Chart Maker

Create bundle charts for Steam Gifts.

当前为 2017-08-24 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Lex's SG Chart Maker
// @namespace    https://www.steamgifts.com/user/lext
// @version      0.1.1
// @description  Create bundle charts for Steam Gifts.
// @author       Lex
// @match        http://store.steampowered.com/*
// @require      http://code.jquery.com/jquery-3.2.1.min.js
// @require      http://code.jquery.com/ui/1.12.1/jquery-ui.min.js
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @connect      api.isthereanydeal.com
// ==/UserScript==

(function() {
    'use strict';

    //GM_deleteValue("gameOrder");
    //GM_deleteValue("games");
    var ITAD_API_KEY = GM_getValue("ITAD_API_KEY");
    const API_KEY_REGEXP = /[0-9A-Za-z]{40}/;
    const GameID = window.location.pathname.split('/').splice(1,2).join("/");
    const BUNDLE_BLACKLIST = ["DailyIndieGame", "Chrono.GG", "Chrono.gg", "Ikoid", "Humble Mobile Bundle", "PlayInjector", "Vodo",
                              "Get Loaded", "GreenMan Gaming", "Indie Ammo Box", "MacGameStore", "PeonBundle", "Select n'Play", "StackSocial",
                              "StoryBundle", "Bundle Central", "Cult of Mac", "GOG", "Gram.pl", "Indie Fort", "IUP Bundle", "Paddle",
                              "SavyGamer", "Shinyloot", "Sophie Houlden", "Unversala", "Indie Game Stand", "Fourth Wall Games"];

    $("head").append ('<link ' +
        'href="//ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/base/jquery-ui.min.css" ' +
        'rel="stylesheet" type="text/css">'
    );

    function getGames() { return JSON.parse(GM_getValue("games", '{}')); }
    function getGameOrder() { return JSON.parse(GM_getValue("gameOrder", '[]')); }

    function itad_getplains(appids, callback) {
        appids = appids.join(",");
        GM_xmlhttpRequest({
            "method": "GET",
            "url": "https://api.isthereanydeal.com/v01/game/plain/id/?key=" + ITAD_API_KEY + "&shop=steam&ids=" + appids,
            "onload": function(response) {
                callback(JSON.parse(response.responseText).data);
            }
        });
    }

    function itad_getbundles(plains, callback) {
        plains = plains.join(",");
        GM_xmlhttpRequest({
            "method": "GET",
            "url": "https://api.isthereanydeal.com/v01/game/bundles/us/?key=" + ITAD_API_KEY + "&limit=-1&expired=1&plains=" + plains,
            "onload": function(response) {
                callback(JSON.parse(response.responseText).data);
            }
        });
    }

    function addAppToChart() {
        var game = {
            gameid: GameID,
            appid: window.location.pathname.split('/')[2],
            name: $(".apphub_AppName").text(),
            rating: $("div[itemprop=aggregateRating]").attr('data-store-tooltip').replace(/(\d+)% of the ([\d,]+) user.*/, "$1% of $2 reviews"),
            cards: $(".game_area_details_specs").text().includes("Steam Trading Cards"),
            price: $.trim($(".game_area_purchase_game:first .price,.game_area_purchase_game:first .discount_original_price").text()),
            url: window.location.href,
            dlc: $(".game_area_dlc_bubble").length,
            bundles: undefined,
        };
        if (game.rating.startsWith("Need more")) {
            let total = $("label[for=review_type_all]").text().match(/[\d,]+/)[0];
            let pos = $("label[for=review_type_positive]").text().match(/[\d,]+/)[0];
            game.rating = Math.round(100*pos/total);
            game.rating = game.rating + `% of ${total} reviews`;
        }
        var games = getGames();
        games[GameID] = game;
        GM_setValue("games", JSON.stringify(games));

        let gorder = getGameOrder();
        if (!gorder.includes(GameID)) {
            gorder.push(GameID);
            GM_setValue("gameOrder", JSON.stringify(gorder));
        }
    }

    function bundleCount(bundleList) {
        return bundleList.filter(function(b){
            // Bundles not on blacklist and at least 24 hours old
            return !BUNDLE_BLACKLIST.includes(b.bundle) && (Date.now()/1000 - b.start) > 24*60*60;
        }).length;
    }

    function loadBundleInfo() {
        var gameids = getGameOrder();
        itad_getplains(gameids, function(plainArr){
            var plains = Object.values(plainArr).filter((v) => v !== null);
            itad_getbundles(plains, function(bundles) {
                var games = getGames();
                for (let plain in bundles) {
                    let gid = Object.keys(plainArr).find(key => plainArr[key] === plain);
                    games[gid].bundlesUrl = bundles[plain].urls.bundles;
                    games[gid].bundles = bundleCount(bundles[plain].list);
                }
                GM_setValue("games", JSON.stringify(games));
                dumpListing();
            });
        });
    }

    function showChartMaker() {
        if (!$("#lcm_dialog").length) {
            GM_addStyle("#lcm_dialog { display: flex; flex-direction: column; } " +
                        "#lcm_list { list-style-type: none; margin: 0 auto; padding: 0; width: 60%; }" +
                        "#lcm_list a { color: blue; text-decoration: underline; }" +
                        "#lcm_dump { margin: 25px auto 0 auto; display: block; flex-grow: 1; resize: none; width: 95%; }" +
                        "#lcm_bundle_info { float: right; }" +
                        "#lcm_itad { margin-bottom: 5px; }");
            var d = $(`<div id="lcm_dialog"><div><button id="lcm_bundle_info" class="ui-button ui-widget ui-corner-all">Load Bundle Info</button>
<div id="lcm_itad"><div>IsThereAnyDeal API Key: <input type="text"></input><button>Submit</button></div><a style="display:none" href="javascript:">Delete ITAD API Key?</a></div>
<ul id="lcm_list"></ul></div>
<textarea id="lcm_dump"></textarea></div>`);
            $("body").append(d);
            if (GM_getValue("ITAD_API_KEY") !== undefined)
                $("#lcm_itad div,#lcm_itad a").toggle();
            $("#lcm_itad button").click(function(){
                try{
                    ITAD_API_KEY = $("#lcm_itad input").val().match(API_KEY_REGEXP)[0];
                    GM_setValue("ITAD_API_KEY", ITAD_API_KEY);
                    $("#lcm_itad div,#lcm_itad a").toggle();
                }catch(err){
                    alert("Error setting API key");
                }
            });
            // Delete key
            $("#lcm_itad a").click(function(){
                GM_deleteValue("ITAD_API_KEY");
                ITAD_API_KEY = undefined;
                $("#lcm_itad div,#lcm_itad a").toggle();
            });

            $("#lcm_dialog").dialog({
                modal: false,
                title: "Lex's SG Chart Maker",
                position: {
                    my: "center",
                    at: "center",
                    of: window,
                    collusion: "none"
                },
                width: 800,
                height: 400,
                minWidth: 400,
                minHeight: 200,
                zIndex: 3666,
            })
            .dialog("widget").draggable("option", "containment", "none");
            $("#lcm_list").sortable({
                deactivate: function(event, ui) {
                    dumpListing();
                }
            });
            $("#lcm_bundle_info").click(loadBundleInfo);
        } else {
            $("#lcm_dialog").dialog();
        }
        updateListing();
        dumpListing();
    }

    function updateListing() {
        $("#lcm_list").empty();
        for (let id of getGameOrder()) {
            var games = getGames();
            let g = games[id];
            let li = $(`<li class="ui-state-default" data-appid="${id}"><a href="${g.url}">${g.name}</a> - ${g.appid} - ${g.price}
<a href="javascript:" style="float:right; color:red; margin-top:-3px">✖</a></li>`);
            $("#lcm_list").append(li);
            li.find("a:last").click(function(){
                deleteGame($(this).parent().attr("data-appid"));
                updateListing();
                dumpListing();
            });
        }
    }

    function saveGameOrder() {
        let gameOrder = $("#lcm_list li.ui-state-default").map(function(){return this.getAttribute("data-appid");}).get();
        GM_setValue("gameOrder", JSON.stringify(gameOrder));
    }

    function dumpListing() {
        saveGameOrder();
        const games = getGames();

        var dump = "Game | Ratings | Cards | Bundled | Retail Price\n :- | :-: | :-: | :-: | :-:\n";
        $("#lcm_list li.ui-state-default").each(function(idx, li) {
            const g = games[li.getAttribute("data-appid")];
            let link = `[**${g.name}**](${g.url})`;
            if (g.dlc)
                link += " (DLC)";
            let cards = "-";
            if (g.cards === true) {
                cards = `[**?**](http://www.steamcardexchange.net/index.php?gamepage-appid-${g.appid})`;
                if (g.dlc === true)
                    cards = "(Base game has cards)";
            }
            let bundles = g.bundles !== undefined ? g.bundles : "?";
            if (g.bundlesUrl)
                bundles = "[" + bundles + "](" + g.bundlesUrl + ")";
            dump += [link, g.rating, cards, bundles, g.price].join(" | ");
            dump += "\n";
        });
        $("#lcm_dump").val(dump);
    }

    function deleteGame(aid) {
        var games = getGames();
        delete games[aid];
        GM_setValue("games", JSON.stringify(games));

        let gameOrder = getGameOrder();
        gameOrder.splice(gameOrder.indexOf(aid), 1);
        GM_setValue("gameOrder", JSON.stringify(gameOrder));
        $("#lcm_add_btn").removeClass("queue_btn_active");
    }

    let btn = $(`<a id="lcm_add_btn" class="btnv6_blue_hoverfade btn_medium btn_steamdb"><span>+ <span style="position:relative;top:-1px">&#x229e;</span> Chart</span></a>`);
    btn.click(function(){
        /*$(this).toggleClass("queue_btn_active");
        if (GameID in getGames())
            deleteGame(GameID);
        else*/
        addAppToChart();
        showChartMaker();
    });
    btn.toggleClass("queue_btn_active", GameID in getGames());
    $(`.apphub_OtherSiteInfo`).append(btn);
})();