// ==UserScript==
// @name Steam Bundle Sites Extension
// @namespace http://tampermonkey.net/
// @version 1.7.2
// @description A steam bundle sites' tool kits.
// @icon http://store.steampowered.com/favicon.ico
// @author Bisumaruko, Cloud
// @include http*://store.steampowered.com/*
// @include https://www.indiegala.com/gift*
// @include https://www.indiegala.com/profile*
// @include https://www.indiegala.com/game*
// @include http*://*bundlestars.com/*
// @include https://www.humblebundle.com/downloads*
// @include http*://*dailyindiegame.com/*
// @include http*://bundle.ccyycn.com/order/*
// @include https://groupees.com/purchases
// @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
// @downloadURL none
// ==/UserScript==
/* global GM_xmlhttpRequest, GM_setValue, GM_getValue, GM_addStyle, GM_getResourceText,
swal, g_AccountID, g_sessionID, g_oSuggestParams,
window, document, location, fetch, localStorage, MutationObserver, Option */
// setup jQuery
const $ = jQuery.noConflict(true);
$.fn.pop = [].pop;
$.fn.shift = [].shift;
// inject swal css
GM_addStyle(GM_getResourceText('SweetAlert2CSS'));
// inject script css
GM_addStyle(`
pre.SBSE_errorMsg {
height: 200px;
text-align: left;
white-space: pre-wrap;
}
`);
// load up
const regKey = /((?:([a-zA-Z0-9])(?!\2{4})){5}-){2,5}[a-zA-Z0-9]{5}/g;
const eol = "\r\n";
const has = Object.prototype.hasOwnProperty;
const unique = a => [...new Set(a)];
const owned = JSON.parse(localStorage.getItem('SBSE_owned') || '{}');
const activated = {
data: JSON.parse(GM_getValue('SBSE_activated') || '[]'),
push(key) {
this.data.push(key);
GM_setValue('SBSE_activated', JSON.stringify(this.data));
},
check(key) {
return this.data.includes(key);
}
};
const config = {
data: JSON.parse(GM_getValue('SBSE_config') || '{}'),
set(key, value, callback = null) {
this.data[key] = value;
GM_setValue('SBSE_config', JSON.stringify(this.data));
if (typeof callback === 'function') callback();
},
get(key) {
return has.call(this.data, key) ? this.data[key] : null;
},
init() {
if (!has.call(this.data, 'autoUpdateSessionID')) this.data.autoUpdateSessionID = true;
if (!has.call(this.data, 'preselectIncludeTitle')) this.data.preselectIncludeTitle = false;
if (!has.call(this.data, 'titleComesLast')) this.data.titleComesLast = false;
if (!has.call(this.data, 'preselectJoinKeys')) this.data.preselectJoinKeys = false;
if (!has.call(this.data, 'joinKeysASFStyle')) this.data.joinKeysASFStyle = true;
}
};
const keyDetails = {
data: {},
set(key = '', obj) {
if (key.length > 0) {
obj.title = has.call(obj, 'title') ? obj.title.trim() : '';
if (has.call(obj, 'app')) obj.app = parseInt(obj.app, 10);
if (has.call(obj, 'sub')) obj.sub = parseInt(obj.sub, 10);
if (has.call(obj, 'url')) {
const matched = obj.url.match(/steam.+\/(app|sub)\/(\d+)/);
if (matched) obj[matched[1]] = parseInt(matched[2], 10);
}
this.data[key] = obj;
}
},
get(key) {
return has.call(this.data, key) ? this.data[key] : null;
},
isOwned(key) {
const detail = this.data[key];
if (detail && owned.app.includes(detail.app)) return true;
if (detail && owned.sub.includes(detail.sub)) return true;
return false;
}
};
config.init();
// text
const i18n = {
tchinese: {
name: '繁體中文',
updateSuccessTitle: '更新成功!',
updateSuccess: '成功更新Steam sessionID',
successStatus: '成功',
successDetail: '無資料',
skippedStatus: '跳過',
activatedDetail: '已啟動',
failStatus: '失敗',
failTitle: '糟糕!',
failDetailUnexpected: '發生未知錯誤,請稍後再試',
failDetailInvalidKey: '序號錯誤',
failDetailUsedKey: '序號已被使用',
failDetailRateLimited: '啟動受限',
failDetailCountryRestricted: '地區限制',
failDetailAlreadyOwned: '產品已擁有',
failDetailMissingBaseGame: '未擁有主程式',
failDetailPS3Required: '需要PS3 啟動',
failDetailGiftWallet: '偵測到禮物卡/錢包序號',
failDetailParsingFailed: '處理資料發生錯誤,請稍後再試',
failDetailRequestFailedNeedUpdate: '請求發生錯誤,請稍後再試
或者嘗試更新SessionID',
noItemDetails: '無產品詳細資料',
notLoggedInTitle: '未登入',
notLoggedInMsg: '請登入Steam 以讓腳本紀錄SessionID',
missingTitle: '未發現SessionID',
missingMsg: '請問要更新SessionID 嗎?',
emptyInput: '未發現Steam 序號',
settingsTitle: '設定',
settingsAutoUpdateSessionID: '自動更新SessionID',
settingsSessionID: '我的SessionID',
settingsLanguage: '語言',
settingsPreselectIncludeTitle: '預選包括遊戲名',
settingsTitleComesLast: '遊戲名置後',
settingsPreselectJoinKeys: '預選合併序號',
settingsJoinKeysASFStyle: '合併ASF 格式序號',
DIGEasyBuyPurchase: '購買',
DIGEasyBuySelectAll: '全選',
DIGEasyBuySelectCancel: '取消',
DIGButtonPurchasing: '購買中',
DIGInsufficientFund: '餘額不足,準備回到帳號頁',
buttonReveal: '刮開',
buttonRetrieve: '提取',
buttonActivate: '啟動',
buttonCopy: '複製',
buttonReset: '清空',
buttonExport: '匯出',
checkboxIncludeGameTitle: '遊戲名',
checkboxJoinKeys: '合併',
checkboxSkipUsed: '跳過已使用',
checkboxSkipOwned: '跳過已擁有',
BSselectConnector: '至',
markAllAsUsed: '標記全部已使用'
},
schinese: {
name: '简体中文',
updateSuccessTitle: '更新成功',
updateSuccess: '成功更新Steam sessionID',
successStatus: '成功',
successDetail: '无信息',
activatedDetail: '已激活',
skippedStatus: '跳过',
failStatus: '失败',
failTitle: '糟糕!',
failDetailUnexpected: '发生未知错误,请稍后再试',
failDetailInvalidKey: '激活码错误',
failDetailUsedKey: '激活码已被使用',
failDetailRateLimited: '激活受限',
failDetailCountryRestricted: '地区限制',
failDetailAlreadyOwned: '产品已拥有',
failDetailMissingBaseGame: '未拥有基础游戏',
failDetailPS3Required: '需要PS3 激活',
failDetailGiftWallet: '侦测到礼物卡/钱包激活码',
failDetailParsingFailed: '处理资料发生错误,请稍后再试',
failDetailRequestFailedNeedUpdate: '请求发生错误,请稍后再试
或者尝试更新SessionID',
noItemDetails: '无产品详细信息',
notLoggedInTitle: '未登入',
notLoggedInMsg: '请登入Steam 以让脚本记录SessionID',
missingTitle: '未发现SessionID',
missingMsg: '请问要更新SessionID 吗?',
emptyInput: '未批配到Steam 激活码',
settingsTitle: '设置',
settingsAutoUpdateSessionID: '自动更新SessionID',
settingsSessionID: '我的SessionID',
settingsLanguage: '语言',
settingsPreselectIncludeTitle: '预选包括游戏名',
settingsTitleComesLast: '游戏名置后',
settingsPreselectJoinKeys: '预选合并激活码',
settingsJoinKeysASFStyle: '合并ASF 格式激活码',
DIGEasyBuyPurchase: '购买',
DIGEasyBuySelectAll: '全选',
DIGEasyBuySelectCancel: '取消',
DIGButtonPurchasing: '购买中',
DIGInsufficientFund: '余额不足,准备回到账号页',
buttonReveal: '刮开',
buttonRetrieve: '提取',
buttonActivate: '激活',
buttonCopy: '复制',
buttonReset: '清空',
buttonExport: '导出',
checkboxIncludeGameTitle: '游戏名',
checkboxJoinKeys: '合并',
checkboxSkipUsed: '跳过已使用',
checkboxSkipOwned: '跳过已拥有',
BSselectConnector: '至',
markAllAsUsed: '标记全部已使用'
},
english: {
name: 'English',
updateSuccessTitle: 'Update Successful!',
updateSuccess: 'Steam sessionID is successfully updated',
successStatus: 'Success',
successDetail: 'No Detail',
activatedDetail: 'Activated',
skippedStatus: 'Skipped',
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
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',
settingsPreselectIncludeTitle: 'Pre-select Include Title',
settingsTitleComesLast: 'Title Comes Last',
settingsPreselectJoinKeys: 'Pre-select Join Keys',
settingsJoinKeysASFStyle: 'Join Keys w/ ASF Style',
DIGEasyBuyPurchase: 'Purchase',
DIGEasyBuySelectAll: 'Select All',
DIGEasyBuySelectCancel: 'Cancel',
DIGButtonPurchasing: 'Purchassing',
DIGInsufficientFund: 'Insufficient fund, returning to account page',
buttonReveal: 'Reveal',
buttonRetrieve: 'Retrieve',
buttonActivate: 'Activate',
buttonCopy: 'Copy',
buttonReset: 'Reset',
buttonExport: 'Export',
checkboxIncludeGameTitle: 'Game Title',
checkboxJoinKeys: 'Join',
checkboxSkipUsed: 'Skip Used',
checkboxSkipOwned: 'Skip Owned',
BSselectConnector: 'to',
markAllAsUsed: 'Mark All as Used'
}
};
let text = has.call(i18n, config.get('language')) ? i18n[config.get('language')] : i18n.english;
// inject settings panel css
GM_addStyle(`
.SBSE_settings .name {
text-align: right;
vertical-align: top;
}
.SBSE_settings .value {
text-align: left;
}
.SBSE_settings .value > * {
height: 30px;
margin: 0 20px 10px;
}
.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 getSessionID = () => {
GM_xmlhttpRequest({
method: 'GET',
url: 'http://store.steampowered.com/',
onload: res => {
if (res.status === 200) {
const accountID = res.response.match(/g_AccountID = (\d+)/).pop();
const sessionID = res.response.match(/g_sessionID = "(\w+)"/).pop();
if (accountID > 0) config.set('sessionID', sessionID);else {
swal({
title: text.notLoggedInTitle,
text: text.notLoggedInMsg,
type: 'error',
showCancelButton: true
}).then(() => {
window.open('http://store.steampowered.com/');
});
}
}
}
});
};
const settings = {
construct() {
const panelHTML = `
${text.settingsAutoUpdateSessionID} | |
${text.settingsSessionID} | |
${text.settingsLanguage} | |
${text.settingsPreselectIncludeTitle} | |
${text.settingsTitleComesLast} | |
${text.settingsPreselectJoinKeys} | |
${text.settingsJoinKeysASFStyle} |
'); errorMsg.push(`sessionID: ${config.get('sessionID') + eol}`); errorMsg.push(`autoUpdate: ${config.get('autoUpdateSessionID') + eol}`); errorMsg.push(`status: ${res.status + eol}`); errorMsg.push(`response: ${res.response + eol}`); errorMsg.push(''); swal({ title: text.failTitle, html: text.failDetailRequestFailedNeedUpdate + eol + errorMsg.join(''), type: 'error' }); getSessionID(); 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 bundleSitesBoxHandler = { reveal(handler, $games) { const $reveal = $('.SBSE_BtnReveal'); $reveal.addClass('working'); handler($games, () => { $reveal.removeClass('working'); $('.SBSE_BtnRetrieve').click(); }); }, retrieve(data) { if (data.length > 0) { const includeTitle = !!$('.SBSE_ChkTitle:checked').length; const joinKeys = !!$('.SBSE_ChkJoin:checked').length; const separator = joinKeys ? ',' : eol; const prefix = joinKeys && config.get('joinKeysASFStyle') ? '!redeem ' : ''; const keys = []; data.forEach(d => { if (typeof d === 'string') { keys.push(d); } else { const temp = [d.key]; if (includeTitle) temp.unshift(d.title); if (config.get('titleComesLast')) temp.reverse(); keys.push(temp.join(', ')); } }); $('.SBSE_container > textarea').val(prefix + keys.join(separator)); } }, activate(e) { const $self = $(e.delegateTarget); const $textarea = $('.SBSE_container > textarea'); let input = $textarea.val().trim(); if (input.length === 0) { $('.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'); }); }, copy() { $('.SBSE_container > textarea').select(); document.execCommand('copy'); }, reset() { $('.SBSE_container > textarea').val(''); }, export(data, title) { // data: [{key: ..., title: ...}, ...] const $export = $('.SBSE_BtnExport'); $export.removeAttr('href').removeAttr('download'); if (Array.isArray(data) && data.length > 0) { const filename = title.replace(/[\\/:*?"<>|!]/g, ''); const formattedData = data.map(line => `${line.title.replace(/,/g, ' ')},${line.key}`).join(eol); $export.attr('href', `data:text/csv;charset=utf-8,\ufeff${encodeURIComponent(formattedData)}`).attr('download', `${filename}.csv`); } }, settings() { settings.display(); } }; 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, .SBSE_container a { width: 120px; position: relative; margin-right: 10px; line-height: 28px; box-sizing: border-box; outline: none; cursor: pointer; transition: all 0.5s; } .SBSE_container a { display: inline-block; text-align: center; } .SBSE_container label { margin-right: 10px; } #SBSE_BtnSettings { width: 20px; height: 20px; float: right; margin-top: 3px; 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; margin-top: 5px; right: 10px; 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.narrow.working { width: 100px; padding-right: 40px; transition: all 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 = $(` `); // bind event $container.find('.SBSE_BtnCopy').click(bundleSitesBoxHandler.copy); $container.find('.SBSE_BtnReset').click(bundleSitesBoxHandler.reset); $container.find('.SBSE_BtnActivate').click(bundleSitesBoxHandler.activate); $container.find('#SBSE_BtnSettings').click(bundleSitesBoxHandler.settings); // apply settings if (config.get('preselectIncludeTitle')) $container.find('.SBSE_ChkTitle').prop('checked', true); if (config.get('preselectJoinKeys')) $container.find('.SBSE_ChkJoin').prop('checked', true); return $container; }; const siteCache = { bundlestars: { doms: [document] } }; const siteHandlers = { indiegala() { const box = bundleSitesBox(); // insert textarea $('#library-contain').eq(0).before(box); // inject css GM_addStyle(` .SBSE_container { margin-top: 10px; } .SBSE_container > textarea { border: 1px solid #CC001D; } .SBSE_container button, .SBSE_BtnExport { width: 100px; background-color: #CC001D; color: white; border-radius: 3px; } .SBSE_BtnExport:hover { color: white; } `); // dom source const source = location.pathname === '/profile' ? 'div[id*="_sale_"].collapse.in' : document; const extractKeys = () => { const keys = []; $(source).find('.game-key-string').each((index, element) => { const $ele = $(element); const key = $ele.find('.keys').val(); if (key) { const $a = $ele.find('.title_game > a'); const title = $a.text().trim(); // append key details keyDetails.set(key, { url: $a.attr('href'), title: $a.text() }); keys.push({ key, title }); } }); return keys; }; // button click $('.SBSE_BtnReveal').click(() => { const handler = ($games, callback) => { 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]; $.ajax({ method: 'GET', url: '/myserials/syncget', dataType: 'json', data: { code, cache: false, productId: appID }, beforeSend() { $(`#permbutton_${code}, #fetchlink_${code}, #info_key_${code}`).hide(); $(`#fetching_${code}`).fadeIn(); $(`#ajax_loader_${code}`).show(); $(`#container_activate_${code}`).html(''); }, success(data) { $(`#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($games, callback); }, error() { swal(text.failTitle, text.failDetailUnexpected, 'error'); } }); } else callback(); }; bundleSitesBoxHandler.reveal(handler, $(source).find('a[id^=fetchlink_]')); }); $('.SBSE_BtnRetrieve').click(() => { bundleSitesBoxHandler.retrieve(extractKeys()); }); $('.SBSE_BtnExport').click(() => { const $bundleTitle = location.pathname === '/profile' ? $('[aria-expanded="true"] > div#bundle-title') : $('#bundle-title, #indie_gala_2 > div > span'); const title = `IndieGala ${$bundleTitle.length > 0 ? $bundleTitle.text() : 'Keys'}`; bundleSitesBoxHandler.export(extractKeys(), title); }); // support for new password protected gift page const $node = $('#gift-contents'); if ($node.length > 0) { const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { mutation.addedNodes.forEach(addedNode => { if (addedNode.id === 'library-contain') { $('#library-contain').eq(0).before(box); observer.disconnect(); } }); }); }); observer.observe($node[0], { childList: true }); } }, 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; }; const extractKeys = () => { const keys = []; BSselect('.key-container input').each((index, input) => { const $input = $(input); keys.push({ key: $input.val(), title: $input.closest('.key-container').prev().text().trim() }); }); return keys; }; if ($('.SBSE_container').length === 0 && $anchor.length > 0) { // insert textarea $anchor.eq(0).before(bundleSitesBox()); // inject css GM_addStyle(` .SBSE_container { border: 1px solid #424242; color: #999999; } .SBSE_container > textarea { background-color: #303030; color: #DDD; } .SBSE_container button, .SBSE_container a { width: 80px; } .SBSE_container button, .SBSE_container select, .SBSE_container a { border: 1px solid transparent; background-color: #262626; color: #DEDEDE; } .SBSE_container button:hover, .SBSE_container select:hover, .SBSE_container a:hover { color: #A8A8A8; } .SBSE_container a { text-decoration: none; } .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; } `); // narrow buttons $('.SBSE_container button').addClass('narrow'); // insert bundlestars select $('.SBSE_container > div').append(` ${text.BSselectConnector} `); // button click $('.SBSE_BtnReveal').click(() => { const handler = ($games, callback) => { const game = $games.shift(); if (game) { if (!game.closest('.ng-hide')) { game.click(); setTimeout(handler.bind(null, $games, callback), 300); } else handler($games, callback); } else setTimeout(callback, 500); }; bundleSitesBoxHandler.reveal(handler, BSselect('.key-container a[ng-click^="redeemSerial"]')); }); $('.SBSE_BtnRetrieve').click(() => { bundleSitesBoxHandler.retrieve(extractKeys()); }); $('.SBSE_BtnExport').click(() => { const $bundleTitle = $('h3.bundle'); const title = `BundleStars - ${$bundleTitle.length > 0 ? $bundleTitle.text() : 'Keys'}`; bundleSitesBoxHandler.export(extractKeys(), title); }); } // 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 > div { position: relative; } .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, .SBSE_container a { width: 70px; border: 1px solid #808080; border-radius: 3px; background-color: #c5c5c5; background: linear-gradient(to top, #cacaca, #e7e7e7); } #SBSE_BtnSettings { position: absolute; } `); // narrow buttons $('.SBSE_container button').addClass('narrow'); // append checkbox for owned game $('#SBSE_BtnSettings').before($(``)); // overwrite inherited color and underline $('.SBSE_BtnExport').css({ color: '#4a4c45', 'text-decoration': 'none' }); const extractKeys = () => { const keys = []; $('.sr-redeemed-bubble .keyfield-text').each((index, element) => { const $game = $(element); const $heading = $game.closest('[class^=sr-key]').prev().children().eq(0); keys.push({ key: $game.text().trim(), title: $heading.text().trim() }); }); return keys; }; // button click $('.SBSE_BtnReveal').click(() => { const handler = ($games, callback) => { const game = $games.shift(); if (game) { game.click(); setTimeout(() => { const $popup = $('.sr-warning-modal-buttons'); const skipOwned = !!$('.SBSE_ChkSkipOwned:checked').length; const selector = skipOwned ? '.sr-warning-modal-cancel-button' : '.sr-warning-modal-confirm-button'; if ($popup.length > 0) $popup.find(selector).click(); setTimeout(handler.bind(null, $games, callback), 300); }, 300); } else callback(); }; bundleSitesBoxHandler.reveal(handler, $('.sr-unredeemed-steam-button')); }); $('.SBSE_BtnRetrieve').click(() => { bundleSitesBoxHandler.retrieve(extractKeys()); }); $('.SBSE_BtnExport').click(() => { const $bundleTitle = $('meta[name=title]'); const title = `Humble Bundle - ${$bundleTitle.length > 0 ? $bundleTitle.attr('content') : 'Keys'}`; bundleSitesBoxHandler.export(extractKeys(), title); }); // setup key details let data = $('.steam-keyredeemer-container').next().text().split(eol)[3].trim().slice(11, -1); try { data = JSON.parse(data); data.keys.forEach(key => { keyDetails.set(key.redeemedKeyVal, { app: key.steamAppId, title: key.humanName }); }); } catch (e) { // no key details } }, 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; } `); const extractKeys = () => { const keys = []; $('#TableKeys tr').each((index, tr) => { const $tds = $(tr).children(); if (tr.textContent.includes('-')) { keys.push({ key: $tds.eq(4).text().trim(), title: $tds.eq(2).text().trim() }); } }); return keys; }; // button click $('.SBSE_BtnReveal').click(() => { const handler = () => { const $form = $('#form3'); $('.quickaction').val(1); $.ajax({ method: 'POST', url: $form.attr('action'), data: $form.serializeArray(), success() { location.reload(); } }); }; bundleSitesBoxHandler.reveal(handler); }); $('.SBSE_BtnRetrieve').click(() => { bundleSitesBoxHandler.retrieve(extractKeys()); }); $('.SBSE_BtnExport').remove(); } 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 = $(`