Did they even play?

Show play stats on Steam Gifts winners pages. Adapted from kelnage's Do You Even Play, Bro? script.

ของเมื่อวันที่ 01-08-2017 ดู เวอร์ชันล่าสุด

// ==UserScript==
// @name         Did they even play?
// @namespace    https://www.steamgifts.com/user/lext
// @version      0.15
// @description  Show play stats on Steam Gifts winners pages. Adapted from kelnage's Do You Even Play, Bro? script.
// @author       Lex
// @match        *://www.steamgifts.com/giveaway/*/winners*
// @require      http://code.jquery.com/jquery-3.2.1.min.js
// @connect      api.steampowered.com
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// ==/UserScript==

(function() {
    'use strict';

    const PLAYTIME_URL = "https://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/"; // takes a steamid and API key
    const ACHIEVEMENTS_URL = "https://api.steampowered.com/ISteamUserStats/GetPlayerAchievements/v0001/"; // takes a steamid, appid and API key
    const SG_USER_URL = "https://www.steamgifts.com/user/";
    const GAME_ACHIEVEMENTS_URL = "http://steamcommunity.com/profiles/$1/stats/$2/achievements/";

    const INVALIDATION_TIME = 30*60*1000; // 30 minute cache time
    const PLAYTIME_CACHE_KEY = "PLAYTIME_CACHE_KEY_";
    function getCachedPlaytime(steamID64, gameID) { return getCachedJSONValue(PLAYTIME_CACHE_KEY + encodeURIComponent(steamID64) + "_g" + encodeURIComponent(gameID)); }
    function setCachedPlaytime(steamID64, gameID, value) { cacheJSONValue(PLAYTIME_CACHE_KEY + encodeURIComponent(steamID64) + "_g" + encodeURIComponent(gameID), value); }
    const ACHIEVEMENTS_CACHE_KEY = "ACHIEVEMENTS_CACHE_KEY_";
    function getCachedAchievements(steamID64, gameID) { return getCachedJSONValue(ACHIEVEMENTS_CACHE_KEY + encodeURIComponent(steamID64) + "_g" + encodeURIComponent(gameID)); }
    function setCachedAchievements(steamID64, gameID, value) { cacheJSONValue(ACHIEVEMENTS_CACHE_KEY + encodeURIComponent(steamID64) + "_g" + encodeURIComponent(gameID), value); }
    const STEAMID_CACHE_KEY = "STEAMID_CACHE_";
    function getCachedSteamID(username) { return GM_getValue(STEAMID_CACHE_KEY + encodeURIComponent(username)); }
    function setCachedSteamID(username, steamID64) { GM_setValue(STEAMID_CACHE_KEY + encodeURIComponent(username), steamID64); }
    const API_KEY_REGEXP = /[0-9A-Z]{32}/;

    const APPID = $("div.featured__inner-wrap a.global__image-outer-wrap").attr('href').match(/\/(\d+)/)[1];

    function getCachedJSONValue(key) {
        try {
            let result = JSON.parse(GM_getValue(key));
            if ((new Date()).getTime() - result.UPDATE_TIME < INVALIDATION_TIME)
                return result;
        } catch (err) { }
    }

    function cacheJSONValue(key, value) {
        value.UPDATE_TIME = (new Date()).getTime();
        GM_setValue(key, JSON.stringify(value));
    }

    var STEAM_API_KEY = GM_getValue("STEAM_API_KEY");

    if (STEAM_API_KEY == "undefined" || STEAM_API_KEY === undefined) {
        var apiDiv = $(`<form><input class="steamApiKey" style="margin-left: 15px; width: 300px" type="text" value="STEAM_API_KEY_HERE"/>
<input style="float:left;" name="btnSubmit" type="button" value="Submit"></input></form>`);
        apiDiv.find("input[name='btnSubmit']").click(function(){
            const api_key = $(this).parents("form:first").find("input.steamApiKey").val();
            if (api_key.match(API_KEY_REGEXP)) {
                GM_setValue("STEAM_API_KEY", api_key);
                $(this).parent().text(" - API key set");
            } else
                alert("Error: Invalid API Key. Please try again.");
        });
        $("div.page__heading__breadcrumbs").append(apiDiv);
        return;
    } else {
        var apiDelDiv = $(`<div style="margin-left: 15px"><a href="#">Delete API Key for Did they even play?</a></div>`);
        apiDelDiv.find("a").one("click", function(){
            $(this).parent().text("Deleted");
            GM_deleteValue("STEAM_API_KEY");
        });
        $("div.page__heading__breadcrumbs").append(apiDelDiv);
        main();
    }

    function fetchGamePlaytimes(steamID64, callback) {
        GM_xmlhttpRequest({
            "method": "GET",
            "url": PLAYTIME_URL + "?steamid=" + steamID64 + "&key=" + STEAM_API_KEY,
            "onload": function(response) {
                try {
                    callback(JSON.parse(response.responseText).response.games);
                } catch(err) {
                    callback();
                }
            }
        });
    }

    function fetchGamePlaytime(steamID64, gameid, callback) {
        const cachedPlaytime = getCachedPlaytime(steamID64, gameid);
        if (cachedPlaytime !== undefined)
            return callback(cachedPlaytime.playtime_forever);
        fetchGamePlaytimes(steamID64, function(games) {
            if (games === undefined)
                callback(-1); // Profile is private, so the games array is empty
            for(var i = 0; i < games.length; i++) {
                if (games[i].appid == gameid) {
                    setCachedPlaytime(steamID64, gameid, games[i]);
                    return callback(games[i].playtime_forever); // playtime in minutes
                }
            }
            callback();
        });
    }

    function fetchAchievementStats(steamID64, appid, callback) {
        const cachedAchievements = getCachedAchievements(steamID64, appid);
        if (cachedAchievements !== undefined)
            return callback(cachedAchievements);
        GM_xmlhttpRequest({
            "method": "GET",
            "url": ACHIEVEMENTS_URL + "?appid=" + appid + "&steamid=" + steamID64 + "&key=" + STEAM_API_KEY,
            "onload": function(response) {
                let results = {"achieved": 0, "total": 0};
                try {
                    const data = JSON.parse(response.responseText);
                    results.achieved = data.playerstats.achievements.filter(function(a) { return a.achieved == 1; }).length;
                    results.total = data.playerstats.achievements.length;
                } catch(err) { }
                setCachedAchievements(steamID64, appid, results);
                return callback(results);
            }
        });
    }

    function fetchSteamID(username, callback) {
        const cachedSteamID = getCachedSteamID(username);
        if (cachedSteamID !== undefined)
            return callback(cachedSteamID);
        GM_xmlhttpRequest({
            "method": "GET",
            "url": SG_USER_URL + username,
            "onload": function(response) {
                const steamID = $('a[data-tooltip="Visit Steam Profile"]', response.responseText).attr("href").match(/\d{17}/)[0];
                setCachedSteamID(username, steamID);
                callback(steamID);
            }
        });
    }

    function steamIDRetrieved(steamID, heading) {
        const achUrl = GAME_ACHIEVEMENTS_URL.replace("$1", steamID).replace("$2", APPID);
        heading.append(`<div style="display:inline-block"><a href="${achUrl}"> - <span class="DTEP_ACHIEVEMENTS"/> <span style="text-decoration:underline">Achievements</span></a><span class="DTEP_PLAYTIME"/></div>`);

        fetchGamePlaytime(steamID, APPID, function(playtime) {
            if (playtime === undefined)
                heading.find(".DTEP_PLAYTIME").parent().text("Game appears unactivated").css({'color':'crimson', "font-weight":"bold"});
            else if (playtime === -1)
                heading.find(".DTEP_PLAYTIME").parent().text("Profile is private").css({'color':'crimson', "font-weight":"bold"});
            else {
                const hours = +(playtime / 60).toFixed(2);
                heading.find(".DTEP_PLAYTIME").text(", " + hours + " hours total");
            }
        });

        fetchAchievementStats(steamID, APPID, function(achievements) {
            if (achievements.total === 0)
                heading.find(".DTEP_ACHIEVEMENTS").parent().text("Game has no achievements");
            else
                heading.find(".DTEP_ACHIEVEMENTS").text(achievements.achieved + " / " + achievements.total + " ");
        });
    }

    function main() {
        $("p.table__column__heading a").each(function(){
            var self = $(this);
            fetchSteamID(self.text(), function(sid) { steamIDRetrieved(sid, self.parents("div:first")); });
        });
    }
})();