Steam Key Helper

try to take over the world!

目前為 2017-09-02 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Steam Key Helper
// @namespace    http://tampermonkey.net/
// @version      1.2.0
// @description  try to take over the world!
// @icon         http://store.steampowered.com/favicon.ico
// @author       Bisumaruko
// @include      http*://*
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/6.6.6/sweetalert2.min.js
// @resource     SweetAlert2CSS https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/6.6.6/sweetalert2.min.css
// @connect      store.steampowered.com
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @grant        GM_getResourceText
// @noframes
// ==/UserScript==

/* global GM_xmlhttpRequest, GM_setValue, GM_getValue, GM_addStyle, GM_getResourceText,
   swal, g_AccountID, g_sessionID,
   window, document, location */

// setup jQuery
const $ = jQuery.noConflict(true);

// inject swal css
GM_addStyle(GM_getResourceText('SweetAlert2CSS'));

// setup swal
swal.setDefaults({
    timer: 3000,
    useRejections: false
});

// inject CSS
GM_addStyle(`
    .SKH_link {
        color: #57bae8;
        cursor: pointer;
    }
    .SKH_link:hover {
        text-decoration: underline;
    }
    .SKH_activated {
        text-decoration: line-through;
    }
`);

// load config
const config = JSON.parse(GM_getValue('SKH_config') || '{}');
const activated = JSON.parse(GM_getValue('SKH_activated') || '[]');
const excludedTag = ['SCRIPT', 'STYLE', 'IFRAME', 'CANVAS'];
const regKey = /([A-Za-z0-9]{5}-){2,4}[A-Za-z0-9]{5}/g;
const has = Object.prototype.hasOwnProperty;

// text
const i18n = {
    tchinese: {
        errorTitle: '糟糕!',
        errorUnexpected: '發生未知錯誤,請稍後再試',
        errorInvalidKey: '序號錯誤',
        errorUsedKey: '序號已被使用',
        errorRateLimited: '啟動受限',
        errorCountryRestricted: '地區限制',
        errorAlreadyOwned: '產品已擁有',
        errorMissingBaseGame: '未擁有主程式',
        errorPS3Required: '需要PS3 啟動',
        errorGiftWallet: '偵測到禮物卡/錢包序號',
        errorFailedRequest: '處理資料發生錯誤,請稍後再試',
        errorFailedRequestNeedUpdate: '請求發生錯誤,請稍後再試<br>或者嘗試更新SessionID',
        successTitle: '啟動成功!',
        processingTitle: '喵~',
        processingMsg: '啟動序號中,請稍後',
        notLoggedInTitle: '未登入',
        notLoggedInMsg: '請登入Steam 以讓腳本紀錄SessionID',
        missingTitle: '未發現SessionID',
        missingMsg: '請問要更新SessionID 嗎?'
    },
    schinese: {
        errorTitle: '糟糕!',
        errorUnexpected: '发生未知错误,请稍后再试',
        errorInvalidKey: '激活码错误',
        errorUsedKey: '激活码已被使用',
        errorRateLimited: '激活受限',
        errorCountryRestricted: '地区限制',
        errorAlreadyOwned: '产品已永有',
        errorMissingBaseGame: '位永有基础游戏',
        errorPS3Required: '需要PS3 激活',
        errorGiftWallet: '侦测到礼物卡/钱包激活码',
        errorFailedRequest: '处理资料发生错误,请稍后再试',
        errorFailedRequestNeedUpdate: '请求发生错误,请稍后再试<br>或者尝试更新SessionID',
        successTitle: '激活成功!',
        processingTitle: '喵~',
        processingMsg: '激活中,请稍后',
        notLoggedInTitle: '未登入',
        notLoggedInMsg: '请登入Steam 以让脚本记录SessionID',
        missingTitle: '未发现SessionID',
        missingMsg: '请问要更新SessionID 吗?'
    },
    english: {
        errorTitle: 'Opps!',
        errorUnexpected: 'An unexpected error has occured, please try again later',
        errorInvalidKey: 'Invalid Key',
        errorUsedKey: 'Used Key',
        errorRateLimited: 'Rate Limited',
        errorCountryRestricted: 'Country Restricted',
        errorAlreadyOwned: 'Product Already Owned',
        errorMissingBaseGame: 'Missing Base Game',
        errorPS3Required: 'PS3 Activation Required',
        errorGiftWallet: 'Gift Card/Wallet Code Detected',
        errorFailedRequest: 'Result parse failed, please try again',
        errorFailedRequestNeedUpdate: 'Request failed, please try again<br>or update sessionID',
        successTitle: 'Activation Successful!',
        processingTitle: 'Nyaa~',
        processingMsg: 'Activating key, please wait',
        notLoggedInTitle: 'Not Logged-In',
        notLoggedInMsg: 'Please login to Steam so sessionID can be saved',
        missingTitle: 'Missing SessionID',
        missingMsg: 'Do you want to update your Steam sessionID?'
    }
};
const text = has.call(i18n, config.language) ? i18n[config.language] : i18n.english;

// functions
const updateActivated = (key, result) => {
    if (!activated.includes(key)) {
        if (result.success === 1 || [14, 15, 9].includes(result.purchase_result_details)) {
            activated.push(key);
            GM_setValue('SKH_activated', JSON.stringify(activated));
            $(`span:contains(${key})`).addClass('SKH_activated');
        }
    }
};
const getResultMsg = result => {
    const errMsg = {
        title: text.errorTitle,
        html: text.errorUnexpected,
        type: 'error'
    };
    const errors = {
        14: text.errorInvalidKey,
        15: text.errorUsedKey,
        53: text.errorRateLimited,
        13: text.errorCountryRestricted,
        9: text.errorAlreadyOwned,
        24: text.errorMissingBaseGame,
        36: text.errorPS3Required,
        50: text.errorGiftWallet
    };
    const getDetails = items => {
        const details = [];

        items.forEach(item => {
            const detail = [`<b>${item.line_item_description}</b>`];
            if (item.packageid > 0) detail.push(`sub: ${item.packageid}`);
            if (item.appid > 0) detail.push(`app: ${item.appid}`);

            details.push(detail.join(', '));
        });

        return details.join('<br>');
    };

    if (result.success === 1) {
        return {
            title: text.successTitle,
            html: getDetails(result.purchase_receipt_info.line_items),
            type: 'success'
        };
    } else if (result.success === 2) {
        if (has.call(errors, result.purchase_result_details)) {
            errMsg.html = errors[result.purchase_result_details];
        }
        if (result.purchase_receipt_info.line_items.length > 0) {
            errMsg.html += `<br>${getDetails(result.purchase_receipt_info.line_items)}`;
        }
    }

    return errMsg;
};
const activateKey = key => {
    swal({
        title: text.processingTitle,
        text: text.processingMsg,
        timer: null
    });
    swal.showLoading();
    GM_xmlhttpRequest({
        method: 'POST',
        url: 'https://store.steampowered.com/account/ajaxregisterkey/',
        headers: {
            Accept: 'text/javascript, text/html, application/xml, text/xml, */*',
            'Accept-Encoding': 'gzip, deflate, br',
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            Origin: 'https://store.steampowered.com',
            Referer: 'https://store.steampowered.com/account/registerkey'
        },
        data: `product_key=${key}&sessionid=${config.sessionID}`,
        onload: res => {
            swal.close();
            if (res.status === 200) {
                try {
                    const result = JSON.parse(res.response);

                    swal(getResultMsg(result));
                    updateActivated(key, result);
                } catch (e) {
                    swal(text.errorTitle, text.errorFailedRequest, 'error');
                }
            } else {
                swal({
                    title: text.errorTitle,
                    html: text.errorFailedRequestNeedUpdate,
                    type: 'error',
                    timer: null,
                    showCancelButton: true,
                    preConfirm: () => {
                        window.open('https://store.steampowered.com/');
                    }
                });
            }
        }
    });
};
const generateLink = txt => {
    const link = $(`<span class="SKH_link">${txt}</span>`).click(() => {
        activateKey(txt);
    });
    if (activated.includes(txt)) link.addClass('SKH_activated');

    return link[0];
};
const scanText = txt => {
    let matched = true;
    const matches = [];

    while (matched) {
        matched = regKey.exec(txt.data);
        if (matched) matches.push(matched);
    }

    matches.reverse().forEach(match => {
        txt.splitText(match.index);
        txt.nextSibling.splitText(match[0].length);
        txt.parentNode.replaceChild(generateLink(match[0]), txt.nextSibling);
    });
};
const scanElement = element => {
    Array.from(element.childNodes).reverse().forEach(child => {
        if (child.nodeType === 1) {
            // element node
            if (child.type === 'text' && regKey.test(child.value)) {
                const $child = $(child);

                if (activated.includes(child.value)) $child.addClass('SKH_activated');
                $child.click(() => {
                    activateKey(child.value);
                });
            } else if (!excludedTag.includes(child.tagName)) scanElement(child);
        } else if (child.nodeType === 3) {
            // text node
            scanText(child);
        }
    });
};
const init = () => {
    // save sessionID
    if (location.hostname === 'store.steampowered.com') {
        if (g_AccountID > 0) {
            if (config.sessionID !== g_sessionID) config.sessionID = g_sessionID;
            if (config.language !== g_oSuggestParams.l) config.language = g_oSuggestParams.l;
            GM_setValue('SKH_config', JSON.stringify(config));
        } else {
            swal(text.notLoggedInTitle, text.notLoggedInMsg, 'error');
        }
    } else {
        // check sessionID & language
        if (!config.sessionID || !config.language) {
            swal({
                title: text.missingTitle,
                text: text.missingMsg,
                type: 'question',
                timer: null,
                showCancelButton: true,
                preConfirm: () => {
                    window.open('https://store.steampowered.com/');
                }
            });
        }

        scanElement(document.body);
    }
};

$(init);

QingJ © 2025

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