// ==UserScript==
// @name Steam Bundle Sites Extension
// @namespace http://tampermonkey.net/
// @version 1.0.1
// @description try to take over the world!
// @icon http://store.steampowered.com/favicon.ico
// @author Bisumaruko
// @include http*://store.steampowered.com/*
// @include https://www.indiegala.com/gift*
// @include http*://*bundlestars.com/*
// @include https://www.humblebundle.com/downloads*
// @include http*://*dailyindiegame.com/*
// @include http*://bundle.ccyycn.com/order/*
// @include http*://*agiso.com/*
// @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
// @run-at document-start
// @noframes
// ==/UserScript==
/* global GM_xmlhttpRequest, GM_setValue, GM_getValue, GM_addStyle, GM_getResourceText,
swal, g_AccountID, g_sessionID, g_oSuggestParams,
window, document, location, fetch, MutationObserver, Option */
// setup jQuery
const $ = jQuery.noConflict(true);
$.fn.pop = [].pop;
$.fn.shift = [].shift;
// inject swal css
GM_addStyle(
GM_getResourceText('SweetAlert2CSS'),
);
// setup swal
swal.setDefaults({
timer: 3000,
useRejections: false,
});
const config = JSON.parse(GM_getValue('SBSE_config') || '{}');
const activated = JSON.parse(GM_getValue('SBSE_activated') || '[]');
const regKey = /([A-Za-z0-9]{5}-){2,4}[A-Za-z0-9]{5}/g;
const has = Object.prototype.hasOwnProperty;
const unique = a => [...new Set(a)];
// text
const i18n = {
tchinese: {
name: '繁體中文',
successStatus: '成功',
successDetail: '無資料',
activatedStatus: '已啟動',
failStatus: '失敗',
failTitle: '糟糕!',
failDetailUnexpected: '發生未知錯誤,請稍後再試',
failDetailInvalidKey: '序號錯誤',
failDetailUsedKey: '序號已被使用',
failDetailRateLimited: '啟動受限',
failDetailCountryRestricted: '地區限制',
failDetailAlreadyOwned: '產品已擁有',
failDetailMissingBaseGame: '未擁有主程式',
failDetailPS3Required: '需要PS3 啟動',
failDetailGiftWallet: '偵測到禮物卡/錢包序號',
failDetailParsingFailed: '處理資料發生錯誤,請稍後再試',
failDetailRequestFailedNeedUpdate: '請求發生錯誤,請稍後再試<br>或者嘗試更新SessionID',
noItemDetails: '無產品詳細資料',
notLoggedInTitle: '未登入',
notLoggedInMsg: '請登入Steam 以讓腳本紀錄SessionID',
missingTitle: '未發現SessionID',
missingMsg: '請問要更新SessionID 嗎?',
emptyInput: '未發現Steam 序號',
settingsTitle: '設定',
settingsAutoUpdateSessionID: '自動更新SessionID',
settingsSessionID: '我的SessionID',
settingsLanguage: '語言',
DIGEasyBuyPurchase: '購買',
DIGEasyBuySelectAll: '全選',
DIGEasyBuySelectCancel: '取消',
DIGButtonPurchasing: '購買中',
buttonReveal: '刮開',
buttonRetrieve: '提取',
buttonActivate: '啟動',
buttonCopy: '複製',
buttonReset: '清空',
checkboxIncludeGameTitle: '遊戲名',
checkboxJoinKeys: '合併',
BSselectConnector: '至',
},
schinese: {
name: '简体中文',
successStatus: '成功',
successDetail: '无信息',
activatedStatus: '已激活',
failStatus: '失败',
failTitle: '糟糕!',
failDetailUnexpected: '发生未知错误,请稍后再试',
failDetailInvalidKey: '激活码错误',
failDetailUsedKey: '激活码已被使用',
failDetailRateLimited: '激活受限',
failDetailCountryRestricted: '地区限制',
failDetailAlreadyOwned: '产品已永有',
failDetailMissingBaseGame: '未拥有基础游戏',
failDetailPS3Required: '需要PS3 激活',
failDetailGiftWallet: '侦测到礼物卡/钱包激活码',
failDetailParsingFailed: '处理资料发生错误,请稍后再试',
failDetailRequestFailedNeedUpdate: '请求发生错误,请稍后再试<br>或者尝试更新SessionID',
noItemDetails: '无产品详细信息',
notLoggedInTitle: '未登入',
notLoggedInMsg: '请登入Steam 以让脚本记录SessionID',
missingTitle: '未发现SessionID',
missingMsg: '请问要更新SessionID 吗?',
emptyInput: '未批配到Steam 激活码',
settingsTitle: '設置',
settingsAutoUpdateSessionID: '自动更新SessionID',
settingsSessionID: '我的SessionID',
settingsLanguage: '语言',
DIGEasyBuyPurchase: '购买',
DIGEasyBuySelectAll: '全选',
DIGEasyBuySelectCancel: '取消',
DIGButtonPurchasing: '购买中',
buttonReveal: '刮开',
buttonRetrieve: '提取',
buttonActivate: '激活',
buttonCopy: '复制',
buttonReset: '清空',
checkboxIncludeGameTitle: '游戏名',
checkboxJoinKeys: '合并',
BSselectConnector: '至',
},
english: {
name: 'English',
successStatus: 'Success',
successDetail: 'No Detail',
activatedStatus: 'Activated',
failStatus: 'Fail',
failTitle: 'Opps!',
failDetailUnexpected: 'Unexpected Error',
failDetailInvalidKey: 'Invalid Key',
failDetailUsedKey: 'Used Key',
failDetailRateLimited: 'Rate Limited',
failDetailCountryRestricted: 'Country Restricted',
failDetailAlreadyOwned: 'Product Already Owned',
failDetailMissingBaseGame: 'Missing Base Game',
failDetailPS3Required: 'PS3 Activation Required',
failDetailGiftWallet: 'Gift Card/Wallet Code Detected',
failDetailParsingFailed: 'Result parse failed',
failDetailRequestFailedNeedUpdate: 'Request failed, please try again<br>or update sessionID',
noItemDetails: 'No Item Details',
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?',
emptyInput: 'Could not find Steam code',
settingsTitle: 'Settings',
settingsAutoUpdateSessionID: 'Auto Update SessionID',
settingsSessionID: 'Your sessionID',
settingsLanguage: 'Language',
DIGEasyBuyPurchase: 'Purchase',
DIGEasyBuySelectAll: 'Select All',
DIGEasyBuySelectCancel: 'Cancel',
DIGButtonPurchasing: 'Purchassing',
buttonReveal: 'Reveal',
buttonRetrieve: 'Retrieve',
buttonActivate: 'Activate',
buttonCopy: 'Copy',
buttonReset: 'Reset',
checkboxIncludeGameTitle: 'Include Game Title',
checkboxJoinKeys: 'Join Keys',
BSselectConnector: 'to',
},
};
let text = has.call(i18n, config.language) ? i18n[config.language] : i18n.english;
// inject settings panel css
GM_addStyle(`
.SBSE_settings .name {
text-align: right;
}
.SBSE_settings .value {
text-align: left;
}
.SBSE_settings .value > * {
height: 30px;
margin: 10px 20px;
}
.SBSE_settings .switch {
position: relative;
display: inline-block;
width: 60px;
}
.SBSE_settings .switch input {
display: none;
}
.SBSE_settings .slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: 0.4s;
}
.SBSE_settings .slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 2px;
bottom: 2px;
background-color: white;
transition: 0.4s;
}
.SBSE_settings input:checked + .slider {
background-color: #2196F3;
}
.SBSE_settings input:focus + .slider {
box-shadow: 0 0 1px #2196F3;
}
.SBSE_settings input:checked + .slider:before {
transform: translateX(30px);
}
.SBSE_settings > span {
display: inline-block;
cursor: pointer;
color: white;
}
`);
// functions
const settings = {
construct() {
const panelHTML = `
<div class="SBSE_settings">
<table>
<tr>
<td class="name">${text.settingsAutoUpdateSessionID}</td>
<td class="value">
<label class="switch">
<input type="checkbox" class="autoUpdateSessionID">
<span class="slider"></span>
</label>
</td>
</tr>
<tr>
<td class="name">${text.settingsSessionID}</td>
<td class="value">
<input type="text" class="sessionID" value="${config.sessionID}" disabled>
</td>
</tr>
<tr>
<td class="name">${text.settingsLanguage}</td>
<td class="value">
<select class="language"></select>
</td>
</tr>
</table>
</div>
`;
return panelHTML;
},
display() {
swal({
title: text.settingsTitle,
html: this.construct(),
timer: null,
});
// apply settings
const $panel = $(swal.getContent());
const $autoUpdateSessionID = $panel.find('.autoUpdateSessionID');
const $sessionID = $panel.find('.sessionID');
const $language = $panel.find('.language');
$autoUpdateSessionID.prop('checked', has.call(config, 'autoUpdateSessionID') ? config.autoUpdateSessionID : true);
$autoUpdateSessionID.change(() => {
swal.showLoading();
const state = $panel.find('.autoUpdateSessionID:checked').length || 0;
config.autoUpdateSessionID = state;
GM_setValue('SBSE_config', JSON.stringify(config));
$sessionID.attr('disabled', !!state);
setTimeout(swal.hideLoading, 500);
});
$sessionID.change(() => {
swal.showLoading();
config.sessionID = $sessionID.val();
GM_setValue('SBSE_config', JSON.stringify(config));
setTimeout(swal.hideLoading, 500);
});
Object.keys(i18n).forEach((language) => {
$language.append(new Option(i18n[language].name, language));
});
$panel.find(`option[value=${config.language}]`).prop('selected', true);
$language.change(() => {
swal.showLoading();
config.language = $language.val();
GM_setValue('SBSE_config', JSON.stringify(config));
text = has.call(i18n, config.language) ? i18n[config.language] : i18n.english;
setTimeout(swal.hideLoading, 500);
});
},
};
const activateHandler = {
keys: [],
results: {},
updateResults(txt = null) {
const $textarea = $('.SBSE_container > textarea');
if (txt) {
$textarea.val(txt);
} else {
const results = this.results;
const parsed = [];
Object.values(results).forEach((result) => {
parsed.push(result.join(' | '));
});
$textarea.val(parsed.join("\n"));
}
},
getResultStatus(result) {
let status = text.failStatus;
let statusMsg = text.failDetailUnexpected;
const errors = {
14: text.failDetailInvalidKey,
15: text.failDetailUsedKey,
53: text.failDetailRateLimited,
13: text.failDetailCountryRestricted,
9: text.failDetailAlreadyOwned,
24: text.failDetailMissingBaseGame,
36: text.failDetailPS3Required,
50: text.failDetailGiftWallet,
};
if (result.success === 1) {
status = text.successStatus;
statusMsg = text.successDetail;
} else if (result.success === 2) {
if (has.call(errors, result.purchase_result_details)) {
statusMsg = errors[result.purchase_result_details];
}
}
return `${status}/${statusMsg}`;
},
getResultItems(info) {
const descriptions = [];
if (info && info.line_items) {
info.line_items.forEach((item) => {
const description = [];
if (item.packageid > 0) description.push(`sub: ${item.packageid}`);
if (item.appid > 0) description.push(`app: ${item.appid}`);
description.push(item.line_item_description);
descriptions.push(description.join(' '));
});
}
return descriptions.join(', ');
},
activateKey(callback) {
const self = this;
const key = self.keys.shift();
if (key) {
if (activated.includes(key)) {
self.results[key].push(text.activatedStatus, text.noItemDetails);
self.updateResults();
// next key
self.activateKey(callback);
} else {
GM_xmlhttpRequest({
method: 'POST',
url: 'https://store.steampowered.com/account/ajaxregisterkey/',
headers: {
Accept: 'text/javascript, text/html, application/xml, text/xml, */*',
'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) => {
if (res.status === 200) {
let status = '';
let items = '';
try {
const result = JSON.parse(res.response);
status = self.getResultStatus(result);
items = self.getResultItems(result.purchase_receipt_info);
// update activated
const failCode = result.purchase_result_details;
if (result.success === 1 || [14, 15, 9].includes(failCode)) {
activated.push(key);
GM_setValue('SBSE_activated', JSON.stringify(activated));
}
} catch (e) {
status = `${text.failStatus}/${text.failDetailParsingFailed}`;
items = text.noItemDetails;
}
self.results[key].push(status, items);
self.updateResults();
// next key
setTimeout(self.activateKey.bind(self, callback), 2000);
} else {
swal({
title: text.failTitle,
html: text.failDetailRequestFailedNeedUpdate,
type: 'error',
timer: null,
showCancelButton: true,
}).then(() => {
window.open('https://store.steampowered.com/');
});
callback();
}
},
});
}
} else callback();
},
activateKeys(input, callback) {
const self = this;
const keys = unique(input.match(regKey));
if (keys.length > 0) {
keys.forEach((key) => {
self.results[key] = [key];
});
self.keys = Object.keys(self.results);
self.updateResults();
self.activateKey(callback);
} else {
self.updateResults(text.emptyInput);
callback();
}
},
};
const bundleSitesBox = () => {
GM_addStyle(`
.SBSE_container {
width: 100%;
height: 200px;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.SBSE_container > textarea {
width: 100%;
height: 150px;
border: none;
box-sizing: border-box;
resize: none;
outline: none;
}
.SBSE_container > div {
width: 100%;
padding-top: 5px;
box-sizing: border-box;
}
.SBSE_container button {
width: 120px;
position: relative;
margin-right: 10px;
line-height: 28px;
box-sizing: border-box;
outline: none;
cursor: pointer;
}
.SBSE_container label {
margin-right: 10px;
}
#SBSE_BtnSettings {
width: 20px;
height: 20px;
float: right;
margin-right: 0;
margin-left: 10px;
background-color: transparent;
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz48c3ZnIGhlaWdodD0iMzJweCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMzIgMzI7IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAzMiAzMiIgd2lkdGg9IjMycHgiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxnIGlkPSJMYXllcl8xIi8+PGcgaWQ9ImNvZyI+PHBhdGggZD0iTTMyLDE3Ljk2OXYtNGwtNC43ODEtMS45OTJjLTAuMTMzLTAuMzc1LTAuMjczLTAuNzM4LTAuNDQ1LTEuMDk0bDEuOTMtNC44MDVMMjUuODc1LDMuMjUgICBsLTQuNzYyLDEuOTYxYy0wLjM2My0wLjE3Ni0wLjczNC0wLjMyNC0xLjExNy0wLjQ2MUwxNy45NjksMGgtNGwtMS45NzcsNC43MzRjLTAuMzk4LDAuMTQxLTAuNzgxLDAuMjg5LTEuMTYsMC40NjlsLTQuNzU0LTEuOTEgICBMMy4yNSw2LjEyMWwxLjkzOCw0LjcxMUM1LDExLjIxOSw0Ljg0OCwxMS42MTMsNC43MDMsMTIuMDJMMCwxNC4wMzF2NGw0LjcwNywxLjk2MWMwLjE0NSwwLjQwNiwwLjMwMSwwLjgwMSwwLjQ4OCwxLjE4OCAgIGwtMS45MDIsNC43NDJsMi44MjgsMi44MjhsNC43MjMtMS45NDVjMC4zNzksMC4xOCwwLjc2NiwwLjMyNCwxLjE2NCwwLjQ2MUwxNC4wMzEsMzJoNGwxLjk4LTQuNzU4ICAgYzAuMzc5LTAuMTQxLDAuNzU0LTAuMjg5LDEuMTEzLTAuNDYxbDQuNzk3LDEuOTIybDIuODI4LTIuODI4bC0xLjk2OS00Ljc3M2MwLjE2OC0wLjM1OSwwLjMwNS0wLjcyMywwLjQzOC0xLjA5NEwzMiwxNy45Njl6ICAgIE0xNS45NjksMjJjLTMuMzEyLDAtNi0yLjY4OC02LTZzMi42ODgtNiw2LTZzNiwyLjY4OCw2LDZTMTkuMjgxLDIyLDE1Ljk2OSwyMnoiIHN0eWxlPSJmaWxsOiM0RTRFNTA7Ii8+PC9nPjwvc3ZnPg==);
background-size: contain;
background-repeat: no-repeat;
background-origin: border-box;
border: none;
vertical-align: top;
}
`);
// spinner button affect
GM_addStyle(`
.SBSE_container button:before {
content: '';
position: absolute;
right: 10px;
margin-top: 5px;
width: 20px;
height: 20px;
border: 3px solid;
border-left-color: transparent;
border-radius: 50%;
box-sizing: border-box;
opacity: 0;
transition: opacity 0.5s;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-name: rotate;
animation-timing-function: linear;
}
.SBSE_container button.working {
padding-right: 20px;
width: 120px;
transition: padding-right 0.5s;
transition: width 0.5s;
}
.SBSE_container button.working:before {
transition-delay: 0.5s;
transition-duration: 1s;
opacity: 1;
}
@keyframes rotate {
0% { transform: rotate(0deg);}
100% { transform: rotate(360deg);}
}
`);
const $container = $(`
<div class="SBSE_container">
<textarea></textarea>
<div>
<button class="SBSE_BtnReveal">${text.buttonReveal}</button>
<button class="SBSE_BtnRetrieve">${text.buttonRetrieve}</button>
<button class="SBSE_BtnActivate">${text.buttonActivate}</button>
<button class="SBSE_BtnCopy">${text.buttonCopy}</button>
<button class="SBSE_BtnReset">${text.buttonReset}</button>
<label><input type="checkbox" class="SBSE_ChkTitle">${text.checkboxIncludeGameTitle}</label>
<label><input type="checkbox" class="SBSE_ChkJoin">${text.checkboxJoinKeys}</label>
<button id="SBSE_BtnSettings"> </button>
</div>
</div>
`);
$container.find('.SBSE_BtnCopy').click(() => {
$('.SBSE_container > textarea').select();
document.execCommand('copy');
});
$container.find('.SBSE_BtnReset').click(() => {
$('.SBSE_container > textarea').val('');
});
$container.find('.SBSE_BtnActivate').click((e) => {
const $self = $(e.delegateTarget);
const $textarea = $('.SBSE_container > textarea');
let input = $textarea.val().trim();
if (input.length === 0) {
$('.SBSE_container input').prop('checked', false);
$('.SBSE_BtnRetrieve').click();
input = $textarea.val();
}
$self.prop('disabled', true).addClass('working');
$textarea.attr('disabled', '');
activateHandler.activateKeys(input, () => {
$self.prop('disabled', false).removeClass('working');
$textarea.removeAttr('disabled');
});
});
$container.find('#SBSE_BtnSettings').click(() => {
settings.display();
});
return $container;
};
const siteCache = {
bundlestars: {
doms: [document],
},
};
const siteHandlers = {
indiegala() {
// insert textarea
$('#library-contain').eq(0).before(bundleSitesBox());
// inject css
GM_addStyle(`
.SBSE_container {
margin-top: 10px;
}
.SBSE_container > textarea {
border: 1px solid #CC001D;
}
.SBSE_container button {
background-color: #CC001D;
color: white;
}
`);
// button click
$('.SBSE_BtnReveal').click((e) => {
const $self = $(e.delegateTarget);
const $games = $('img[src*="steam-icon-tm-g.png"]').closest('a');
const handler = async () => {
const game = $games.shift();
if (game) {
const $game = $(game);
const code = $game.attr('id').split('_').pop();
const appID = $game.attr('onclick').match(/steampowered\.com\/app\/(\d+)/)[1];
$(`#permbutton_${code}, #fetchlink_${code}, #info_key_${code}`).hide();
$(`#fetching_${code}`).fadeIn();
$(`#ajax_loader_${code}`).show();
$(`#container_activate_${code}`).html('');
const url = `https://www.indiegala.com/myserials/syncget?code=${code}&cache=false&productId=${appID}`;
const res = await fetch(url, {
method: 'GET',
headers: {
Accept: 'application/json, text/javascript, */*; q=0.01',
},
mode: 'same-origin',
credentials: 'same-origin',
cache: 'no-store',
referer: location.href,
});
if (res.ok) {
const data = await res.json();
$(`#ajax_loader_${code}, #fetching_${code}, #info_key_${code}`).hide();
$(`#serial_${code}`).fadeIn();
$(`#serial_n_${code}`).val(data.serial_number);
$game.parent().prev().find('.btn-convert-to-trade').remove();
handler();
}
} else {
$self.removeClass('working');
$('.SBSE_BtnRetrieve').click();
}
};
$self.addClass('working');
handler();
});
$('.SBSE_BtnRetrieve').click(() => {
const includeTitle = $('.SBSE_ChkTitle:checked').length;
const separator = $('.SBSE_ChkJoin:checked').length > 0 ? ',' : "\n";
const keys = [];
$('.game-key-string').each((index, element) => {
const $ele = $(element);
const key = $ele.find('.keys').val();
if (key) {
const title = includeTitle ? `${$ele.find('.title_game > a').text().trim()}, ` : '';
keys.push(title + key);
}
});
$('.SBSE_container > textarea').val(keys.join(separator));
});
},
bundlestars(firstCalled) {
const cache = siteCache.bundlestars;
const $anchor = $('h2:contains(Order Keys)');
const BSselect = (selector) => {
let $results = $();
let from = parseInt($('.SBSE_container .selectFrom').val(), 10);
let to = parseInt($('.SBSE_container .selectTo').val(), 10);
if ($.isNumeric(from) && $.isNumeric(to)) {
if (from === 0 && to > 0) from = 1;
if (from > 0 && to === 0) to = cache.doms.length - 1;
for (let i = Math.min(from, to); i <= Math.max(from, to); i += 1) {
$results = $results.add(
$(cache.doms[i]).find(selector),
);
}
}
return $results;
};
if ($('.SBSE_container').length === 0 && $anchor.length > 0) {
// insert textarea
$anchor.eq(0).before(bundleSitesBox());
// insert bundlestars select
$('.SBSE_container > div').append(`
<select class="selectTo"></select>
<span>${text.BSselectConnector}</span>
<select class="selectFrom"></select>
`);
// inject css
GM_addStyle(`
.SBSE_container {
border: 1px solid #424242;
color: #999999;
}
.SBSE_container > textarea {
background-color: #303030;
color: #DDD;
}
.SBSE_container button {
width: 80px;
}
.SBSE_container button, .SBSE_container select {
border: 1px solid transparent;
background-color: #262626;
color: #DEDEDE;
}
.SBSE_container button:hover, .SBSE_container select:hover {
color: #A8A8A8;
}
.SBSE_container label {
color: #DEDEDE;
}
.SBSE_container select {
max-width:120px;
height: 30px;
}
.SBSE_container select, .SBSE_container span {
margin-right: 0;
margin-left: 10px;
float: right;
}
.SBSE_container span {
margin-top: 5px;
}
`);
// button click
$('.SBSE_BtnReveal').click((e) => {
const $self = $(e.delegateTarget);
const $games = BSselect('.key-container a[ng-click^="redeemSerial"]');
const handler = () => {
const game = $games.shift();
if (game) {
if (!game.closest('.ng-hide')) {
game.click();
setTimeout(handler, 300);
} else handler();
} else {
$self.removeClass('working');
$('.SBSE_BtnRetrieve').click();
}
};
$self.addClass('working');
handler();
});
$('.SBSE_BtnRetrieve').click(() => {
const includeTitle = $('.SBSE_ChkTitle:checked').length;
const separator = $('.SBSE_ChkJoin:checked').length > 0 ? ',' : "\n";
const keys = [];
BSselect('.key-container input').each((index, input) => {
const $input = $(input);
const title = includeTitle ? `${$input.closest('.key-container').prev().text().trim()}, ` : '';
const key = $input.val();
keys.push(title + key);
});
$('.SBSE_container > textarea').val(keys.join(separator));
});
}
// setup select
const $selects = $('.SBSE_container select');
$selects.empty();
$selects.append(new Option('All', 0));
cache.doms = [document];
$('hr ~ div > div:not(.ng-hide)').each((index, block) => {
const $block = $(block);
const $bundle = $block.find('h3');
const $tiers = $block.find('h4');
if ($tiers.length > 1) { // bundles with multiple tiers
$tiers.each((i, tier) => {
const $tier = $(tier);
$selects.append(
new Option(`${$bundle.text()} ${$tier.text()}`, cache.doms.push($tier.parent()) - 1),
);
});
} else if ($bundle.length > 0) { // bundles with single tier
$selects.append(
new Option($bundle.text(), cache.doms.push($bundle.next()) - 1),
);
} else { // individual games
$selects.append(
new Option($block.find('.title').text(), cache.doms.push($block) - 1),
);
}
});
if (firstCalled) {
new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.removedNodes.forEach((removedNode) => {
if (removedNode.id === 'loading-bar-spinner') {
siteHandlers.bundlestars();
}
});
});
}).observe(document.body, {
childList: true,
});
}
},
humblebundle() {
// insert textarea
$('#steam-tab').closest('.whitebox').eq(0).before(bundleSitesBox());
// inject css
GM_addStyle(`
.SBSE_container > textarea {
border: 1px solid #AAAAAA;
color: #4a4c45;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
border-radius: 5px;
}
.SBSE_container button {
width: 80px;
border: 1px solid #808080;
border-radius: 3px;
background-color: #c5c5c5;
background: linear-gradient(to top, #cacaca, #e7e7e7);
}
`);
// button click
$('.SBSE_BtnReveal').click((e) => {
const $self = $(e.delegateTarget);
const $games = $('.sr-unredeemed-steam-button');
const handler = () => {
const game = $games.shift();
if (game) {
game.click();
setTimeout(handler, 300);
} else {
$self.removeClass('working');
$('.SBSE_BtnRetrieve').click();
}
};
$self.addClass('working');
handler();
});
$('.SBSE_BtnRetrieve').click(() => {
const includeTitle = $('.SBSE_ChkTitle:checked').length;
const separator = $('.SBSE_ChkJoin:checked').length > 0 ? ',' : "\n";
const keys = [];
$('.sr-redeemed-bubble').each((index, element) => {
const $game = $(element);
const key = $game.text().trim();
let title = '';
if (includeTitle) {
const $heading = $game.closest('[class^=sr-key]').prev().children().eq(0);
title = `${$heading.text().trim()}, `;
}
keys.push(title + key);
});
$('.SBSE_container > textarea').val(keys.join(separator));
});
},
dailyindiegame() {
const pathname = location.pathname;
if (pathname.includes('/account_page')) {
// insert textarea
$('#TableKeys').eq(0).before(bundleSitesBox());
// inject css
GM_addStyle(`
.SBSE_container {
padding: 5px;
border: 1px solid #424242;
}
.SBSE_container > textarea {
border: 1px solid #000;
}
.SBSE_container button {
border: none;
background-color: #FD5E0F;
color: rgb(49, 49, 49);
font-family: Ropa Sans;
font-size: 15px;
font-weight: 600;
}
`);
// reveal button not neeeded
$('.SBSE_BtnReveal').hide();
// button click
$('.SBSE_BtnRetrieve').click(() => {
const includeTitle = $('.SBSE_ChkTitle:checked').length;
const separator = $('.SBSE_ChkJoin:checked').length > 0 ? ',' : "\n";
const keys = [];
$('#TableKeys tr').each((i, tr) => {
const $tds = $(tr).children();
const title = includeTitle ? `${$tds.eq(2).text().trim()}, ` : '';
const key = $tds.eq(4).text().trim();
if (key.includes('-')) keys.push(title + key);
});
$('.SBSE_container > textarea').val(keys.join(separator));
});
} else if (pathname === '/account_digstore.html' || pathname === '/account_trades.html') {
// DIG EasyBuy
GM_addStyle(`
.DIGEasyBuy button {
padding: 4px 8px;
outline: none;
}
.DIGEasyBuy_checked {
background-color: #222;
}
`);
const $target = $('#form3').closest('tr').children().eq(0);
const $DIGEasyBuy = $(`
<div class="DIGEasyBuy">
<button class="DIGButtonPurchase DIG3_Orange_15_Form">${text.DIGEasyBuyPurchase}</button>
<button class="DIGButtonSelectAll DIG3_Orange_15_Form">${text.DIGEasyBuySelectAll}</button>
</div>
`);
$target
.empty()
.append($DIGEasyBuy);
// bind button event
$('.DIGButtonPurchase').click((e) => {
let bought = 0;
let balance = parseInt($('a[href^="account_transac"]').closest('div').text().slice(12), 10) || 0;
const $self = $(e.delegateTarget);
const $checked = $('.DIGEasyBuy_checked');
const handler = async (callback) => {
const item = $checked.shift();
if (item) {
const $item = $(item);
const id = $item.data('id');
const price = parseInt($item.data('price'), 10);
if (id && price > 0 && (balance - price) > 0) {
let url = `${location.origin}/account_buy.html`;
const requestInit = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `quantity=1&xgameid=${id}&xgameprice1=${price}&send=Purchase`,
mode: 'same-origin',
credentials: 'same-origin',
cache: 'no-store',
referrer: `${location.origin}/account_buy_${id}.html`,
};
if (pathname === '/account_trades.html') {
url = `${location.origin}/account_buytrade_${id}.html`;
requestInit.body = `gameid=${id}&send=Purchase`;
requestInit.referrer = url;
}
const res = await fetch(url, requestInit);
if (res.ok) {
$item.click();
bought += 1;
balance -= price;
}
setTimeout(handler.bind(null, callback), 300);
}
} else callback();
};
$self.prop('disabled', true).text(text.DIGButtonPurchasing);
handler(() => {
if (bought) window.location = `${location.origin}/account_page.html`;
else $self.prop('disabled', false).text(text.DIGButtonPurchase);
});
});
$('.DIGButtonSelectAll').click((e) => {
const $self = $(e.delegateTarget);
const state = !$self.data('state');
$('.DIGEasyBuy_row').toggleClass('DIGEasyBuy_checked', state);
$self.data('state', state);
$self.text(state ? text.DIGEasyBuySelectCancel : text.DIGEasyBuySelectAll);
});
// setup row data & event
$('a[href^="account_buy"]').each((index, element) => {
const $game = $(element);
const $row = $game.closest('tr');
$row.data({
id: $game.attr('href').replace(/\D/g, ''),
price: parseInt($game.closest('td').prev().text(), 10) || 0,
});
$row.click(() => {
$row.toggleClass('DIGEasyBuy_checked');
});
$row.addClass('DIGEasyBuy_row');
});
}
},
ccyycn() {
// insert textarea
$('.featurette-divider').eq(0).after(bundleSitesBox());
// inject css
GM_addStyle(`
.SBSE_container {
width: 80%;
margin: 0 auto;
color: #000;
font-size: 16px;
}
.SBSE_container > textarea {
background-color: #EEE;
box-shadow: 0 0 1px 1px rgba(204,204,204,0.5);
border-radius: 5px;
}
.SBSE_container > div {
text-align: left;
}
.SBSE_container button {
width: 80px;
border: 1px solid transparent;
border-radius: 5px;
background-color: #EEE;
box-shadow: 0 0 1px 1px rgba(204,204,204,0.5);
}
.SBSE_container label {
color: #EEE;
}
`);
// button click
$('.SBSE_BtnReveal').click((e) => {
const $self = $(e.delegateTarget);
const $games = $('.deliver-btn');
const handler = () => {
const game = $games.shift();
if (game) {
game.click();
setTimeout(handler, 300);
} else {
$self.removeClass('working');
$('.SBSE_BtnRetrieve').click();
}
};
$self.addClass('working');
handler();
});
$('.SBSE_BtnRetrieve').click(() => {
const includeTitle = $('.SBSE_ChkTitle:checked').length;
const separator = $('.SBSE_ChkJoin:checked').length > 0 ? ',' : "\n";
const keys = [];
$('.deliver-gkey').each((index, element) => {
const $game = $(element);
const title = includeTitle ? `${$game.parent().prev().text().trim()}, ` : '';
const key = $game.text().trim();
keys.push(title + key);
});
$('.SBSE_container > textarea').val(keys.join(separator));
});
},
agiso() {
const keys = unique($('body').text().match(regKey));
if (keys.length > 0) {
// insert textarea
$('#tabs').eq(0).prepend(bundleSitesBox());
// inject css
GM_addStyle(`
.SBSE_container > textarea {
border: 1px solid #AAAAAA;
}
.SBSE_container button {
border: 1px solid #d3d3d3;
background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x;
color: #555555;
}
.SBSE_container button:hover {
border-color: #999999;
background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x;
color: #212121;
}
#SBSE_BtnSettings {
width: 32px !important;
height: 32px !important;
}
`);
// remove event from agiso
$('.SBSE_container button').click((e) => {
e.preventDefault();
});
// hide reveal
$('.SBSE_BtnReveal').hide();
// button click
$('.SBSE_BtnRetrieve').click(() => {
const separator = $('.SBSE_ChkJoin:checked').length > 0 ? ',' : "\n";
$('.SBSE_container > textarea').val(keys.join(separator));
});
}
},
};
const init = () => {
if (location.hostname === 'store.steampowered.com') {
// save sessionID
if (g_AccountID > 0) {
if (!config.sessionID || config.autoUpdateSessionID) config.sessionID = g_sessionID;
if (!config.language) config.language = g_oSuggestParams.l;
GM_setValue('SBSE_config', JSON.stringify(config));
} else {
swal(text.notLoggedInTitle, text.notLoggedInMsg, 'error');
}
} else {
const site = location.hostname.replace(/(www|alds|bundle)\./, '').split('.').shift();
// check sessionID
if (!config.sessionID) {
swal({
title: text.missingTitle,
text: text.missingMsg,
type: 'question',
timer: null,
showCancelButton: true,
}).then(() => {
window.open('https://store.steampowered.com/');
});
}
if (has.call(siteHandlers, site)) siteHandlers[site](true);
}
};
$(init);