// ==UserScript==
// @name Steam Wholesale Sites Extension
// @namespace http://tampermonkey.net/
// @version 1.7.0
// @description try to take over the world!
// @icon https://store.steampowered.com/favicon.ico
// @author Bisumaruko
// @contributor Renoz fghhdfh@greasyfork for Russian translation
// @include https://wallet.web.money/finances*
// @include https://mini.wmtransfer.com/*
// @include https://qiwi.com/payment/form/99*
// @include http*://www.cheapkeys.ovh/*
// @include http*://cheapkeys.ovh/*
// @include http://steamfarmkey.ru/*
// @include http://steam1.lequeshop.ru/*
// @include http://steam1.ru/*
// @include http://lastkey.ru/*
// @include http://steamkeyswhosales.com/*
// @include http://alfakeys.ru/*
// @include http://cheap-steam-games.ru/*
// @include http://dmshop.lequeshop.ru/*
// @include http://kartonanet.lequeshop.ru/*
// @include http://keyssell.ru/*
// @include http://keys.farm/*
// @include http://rig4all.lequeshop.ru/*
// @include http://steam-tab.ru/*
// @include http://steamd.lequeshop.ru/*
// @include http://steamkeys-shop.ru/*
// @include http://steamkey.lequeshop.ru/*
// @include http://steamkeystore.ru/*
// @include http://farmacc.ru/*
// @include http://steamrandomkeys.ru/*
// @include http://animekeys.ru/*
// @include http://drunkpatrick.store/*
// @include http://steamfarm.lequestore.ru/*
// @include http://maxfarmshop.ru/*
// @include http://bestkeystore.ru/*
// @include http://bestfarmkey.lequestore.ru/*
// @include http://tkfg.ru/*
// @include http://indiegamekeys.lequestore.ru/*
// @include http://m-b-shop.leque.shop/*
// @include http://200plus.lequeshop.ru/*
// @include http://randomkey.ru/*
// @include http://farmkeys.ru/*
// @include http://baty131shop.lequestore.ru/*
// @include http://baty131shop.lequeshop.ru/*
// @include http://200plus.lequestore.ru/*
// @include http://azimut-steam.leque.shop/*
// @include http://imperiumkey.com/*
// @include http://alonekey.net/*
// @include http://keys.lequestore.ru/*
// @include http://wlutmarket.lequeshop.ru/*
// @include http://cheapkeys.akens.ru/*
// @include http://steam-discount.ru/*
// @include http://jplay.lequeshop.ru/*
// @include http://sovkey-farm.ru/*
// @include http://gamesforfarm.lequeshop.com/*
// @include http://bestgames.lequeshop.com/*
// @include http://bobkeys.lequeshop.ru/*
// @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/7.0.6/sweetalert2.min.js
// @resource SweetAlert2CSS https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/7.0.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
// ==/UserScript==
/* global swal */
// inject swal css
GM_addStyle(GM_getResourceText('SweetAlert2CSS'));
// inject styles
GM_addStyle(`
body.hideOwned .SWSE_owned { display: none; }
body.hideDLC .SWSE_DLC { display: none; }
th.discount { width: 150px; }
.SWSE_hide { display: none !important; }
.SWSE_settings, .SWSE_settings input { width: -webkit-fill-available; width: -moz-available; }
.SWSE_settings .name { text-align: right; vertical-align: top; }
.SWSE_settings .value { text-align: left; }
.SWSE_settings .value > * { height: 30px; margin: 0 20px 10px; }
.SWSE_settings .switch { position: relative; display: inline-block; width: 60px; }
.SWSE_settings .switch input { display: none; }
.SWSE_settings .slider {
position: absolute;
cursor: pointer;
top: 0; left: 0; right: 0; bottom: 0;
background-color: #ccc;
transition: 0.4s;
}
.SWSE_settings .slider:before {
position: absolute;
content: "";
height: 26px; width: 26px;
left: 2px; bottom: 2px;
background-color: white;
transition: 0.4s;
}
.SWSE_settings input:checked + .slider { background-color: #2196F3; }
.SWSE_settings input:focus + .slider { box-shadow: 0 0 1px #2196F3; }
.SWSE_settings input:checked + .slider:before { transform: translateX(30px); }
.SWSE_settings > span { display: inline-block; cursor: pointer; color: white; }
.SWSE_owned, .SWSE_owned > .name {
background-image: linear-gradient(135deg, rgba(0, 0, 0, 0.3) 60%, rgba(0, 0, 0, 0.1) 90%) !important;
background-color: #9ccc65 !important;
transition: background 500ms ease 0s;
color: white !important;
}
.SWSE_owned a { color: white !important; }
`);
// load up
const regURL = /(https?:\/\/)?([.\w]*steam[-.\w]*){1}\/.*?(apps?|subs?){1}\/(\d+){1}(\/.*\/?)?/m;
const regKey = /((?:([A-Z0-9])(?!\2{4})){5}-){2,5}[A-Z0-9]{5}/g;
const has = Object.prototype.hasOwnProperty;
const forEachAsync = (array, callback, lastIterationCallback) => {
if (!Array.isArray(array)) throw Error('Not an array');
if (typeof callback !== 'function') throw Error('Not an function');
const iterators = [...array.keys()];
const processor = taskStartTime => {
let taskFinishTime;
do {
const iterator = iterators.shift();
if (iterator in array) callback(array[iterator], iterator, array);
taskFinishTime = window.performance.now();
} while (taskFinishTime - taskStartTime < 1000 / 60);
if (iterators.length > 0) requestAnimationFrame(processor);
// finished iterating array
else if (typeof lastIterationCallback === 'function') lastIterationCallback();
};
requestAnimationFrame(processor);
};
// setup jQuery
const $ = jQuery.noConflict(true);
$.fn.pop = [].pop;
$.fn.shift = [].shift;
$.fn.eachAsync = function eachAsync(callback, lastIterationCallback) {
forEachAsync(this.get(), callback, lastIterationCallback);
};
const owned = JSON.parse(GM_getValue('SWSE_owned') || '{}');
const discountCode = JSON.parse(GM_getValue('SWSE_discount_code') || '{}');
const config = {
data: JSON.parse(GM_getValue('SWSE_config') || '{}'),
set(key, value, callback = null) {
this.data[key] = value;
GM_setValue('SWSE_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, 'language')) this.data.language = 'english';
if (!has.call(this.data, 'count')) this.data.count = 1;
if (!has.call(this.data, 'email')) this.data.email = '';
}
};
const i18n = {
data: {
tchinese: {
name: '繁體中文',
settingsTitle: '設定',
settingsCount: '購買數量',
settingsEmail: '購買信箱',
settingsLanguage: '語言',
menuHideOwned: '隱藏已擁有',
menuShowOwned: '顯示已擁有',
menuHideDLC: '隱藏DLC',
menuShowDLC: '顯示DLC',
menuSyncLibrary: '同步遊戲庫',
menuFilterDiscount: '折扣篩選',
menuFilterDiscountLoading: '折扣載入中...',
menuSort: '排序',
keyField: 'Steam 序號',
payButtonText: '付款',
syncSuccessTitle: '同步成功',
syncSuccess: '成功同步Steam 遊戲庫資料'
},
schinese: {
name: '简体中文',
settingsTitle: '设置',
settingsCount: '购买数量',
settingsEmail: '购买邮箱',
settingsLanguage: '语言',
menuHideOwned: '隐藏已拥有',
menuShowOwned: '显示已擁有',
menuHideDLC: '隐藏DLC',
menuShowDLC: '显示DLC',
menuSyncLibrary: '同步游戏库',
menuFilterDiscount: '折扣筛选',
menuFilterDiscountLoading: '加载折扣中...',
menuSort: '排序',
keyField: 'Steam 激活码',
payButtonText: '付款',
syncSuccessTitle: '同步成功',
syncSuccess: '成功同步Steam 游戏库资料'
},
english: {
name: 'English',
settingsTitle: 'Settings',
settingsCount: 'Purchase Quantity',
settingsEmail: 'Purchase Email',
settingsLanguage: 'Language',
menuHideOwned: 'Hide Owned',
menuShowOwned: 'Show Owned',
menuHideDLC: 'Hide DLC',
menuShowDLC: 'Show DLC',
menuSyncLibrary: 'Sync Library',
menuFilterDiscount: 'Discount Filter',
menuFilterDiscountLoading: 'Loading discounts...',
menuSort: 'Sort',
keyField: 'Steam Keys',
payButtonText: 'Pay',
syncSuccessTitle: 'Sync Successful',
syncSuccess: 'Successfully sync Steam library data'
},
russian: {
name: 'Русский',
settingsTitle: 'Настройки',
settingsCount: 'Приобретаемое количество',
settingsEmail: 'Email для покупок',
settingsLanguage: 'Язык',
menuHideOwned: 'Скрыть имеющиеся',
menuShowOwned: 'Показать имеющиеся',
menuHideDLC: 'Скрыть DLC',
menuShowDLC: 'Показать DLC',
menuSyncLibrary: 'Синхронизировать список игр',
menuFilterDiscount: 'Фильтр скидок',
menuFilterDiscountLoading: 'Скидки загружаются...',
menuSort: 'Сортировка',
keyField: 'Steam ключи',
payButtonText: 'Оплатить',
syncSuccessTitle: 'Синхронизация успешна',
syncSuccess: 'Успешно синхронизированы данные Steam библиотеки'
}
},
language: null,
set() {
const selectedLanguage = has.call(this.data, config.get('language')) ? config.get('language') : 'english';
this.language = this.data[selectedLanguage];
},
get(key) {
return has.call(this.language, key) ? this.language[key] : this.data.english[key];
},
init() {
this.set();
}
};
const settingsHandler = arg => {
swal.showLoading();
arg();
setTimeout(swal.hideLoading, 500);
};
const settings = () => {
const panelHTML = `
<table class="SWSE_settings">
<tr>
<td class="name">${i18n.get('settingsLanguage')}</td>
<td class="value"><select class="language"></select></td>
</tr>
<tr>
<td class="name">${i18n.get('settingsCount')}</td>
<td class="value"><input type="number" class="count" value="1" min="1"></select></td>
</tr>
<tr>
<td class="name">${i18n.get('settingsEmail')}</td>
<td class="value"><input type="text" class="email"></td>
</tr>
</table>
`;
const panelHandler = panel => {
// apply settings
const $panel = $(panel).find('.SWSE_settings');
// language
const $language = $panel.find('.language');
Object.keys(i18n.data).forEach(language => {
$language.append(new Option(i18n.data[language].name, language));
});
$panel.find(`option[value=${config.get('language')}]`).prop('selected', true);
$language.change(settingsHandler.bind(null, () => {
const newLanguage = $language.val();
config.set('language', newLanguage);
i18n.set();
}));
// count, email
['count', 'email'].forEach(field => {
const $field = $panel.find(`.${field}`);
const val = config.get(field);
if (val) $field.val(val);
$field.change(settingsHandler.bind(null, () => {
config.set(field, $field.val().trim());
}));
});
};
swal({
title: i18n.get('settingsTitle'),
html: panelHTML,
onBeforeOpen: panelHandler
});
};
const matchSteamUrl = (str = '') => {
const input = str.trim();
let output = null;
if (input.length > 0) {
const found = input.match(regURL);
if (found) {
output = {
type: found[3].slice(0, 3),
id: parseInt(found[4], 10),
index: found.index,
matched: found[0]
};
}
}
return output;
};
const check = (d, s, c) => {
let source = d;
let selector = s;
let callback = c;
if (typeof d === 'string') {
// dom source omitted
source = document;
selector = d;
callback = s;
}
$(source).find(selector.split(',').map(x => `${x}:not(.SWSE_checked)`).join()).eachAsync(element => {
const $ele = $(element);
const classes = [];
let attr = null;
for (let i = 0; i < element.attributes.length; i += 1) {
if (!attr) attr = matchSteamUrl(element.attributes[i].value);
}
if (attr && owned[attr.type].includes(attr.id)) classes.push('SWSE_owned');
if ($ele.text().toLowerCase().includes(' dlc')) classes.push('SWSE_DLC');
if (classes.length > 0) callback($ele, classes.join(' '));
$ele.addClass('SWSE_checked');
});
};
const syncLibrary = (notify = false) => {
GM_xmlhttpRequest({
method: 'GET',
url: `https://store.steampowered.com/dynamicstore/userdata/t=${Math.random()}`,
onload: res => {
if (res.status === 200) {
const data = JSON.parse(res.response);
if (data.rgOwnedApps.length > 0) owned.app = data.rgOwnedApps;
if (data.rgOwnedPackages.length > 0) owned.sub = data.rgOwnedPackages;
owned.lastSync = Date.now();
GM_setValue('SWSE_owned', JSON.stringify(owned));
if (notify) {
swal({
title: i18n.get('syncSuccessTitle'),
text: i18n.get('syncSuccess'),
type: 'success',
timer: 3000
});
}
}
}
});
};
const headerMenu = () => {
// insert header menu
GM_addStyle(`
header.SWSE_header {
display: flex !important;
position: sticky;
top: 0;
padding: 0 7%;
background: #2d3f51;
box-shadow: 0 2px 5px rgba(68, 68, 68, 0.3);
transition: all 0.2s ease;
z-index: 9999;
}
.SWSE_nav ul { margin: 0; padding: 0; list-style: none; }
.SWSE_nav li { float: left; }
.SWSE_nav a {
color: #f5f5f5;
text-decoration: none;
display: block;
padding: 1.5em;
font-size: initial;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 1px;
transition: all 0.2s ease;
overflow: hidden;
}
.SWSE_nav a:hover { color: #16A085; }
body.hideDiscountRange_-1 tr[data-discount-range="-1"],
body.hideDiscountRange_1 tr[data-discount-range="1"],
body.hideDiscountRange_2 tr[data-discount-range="2"],
body.hideDiscountRange_3 tr[data-discount-range="3"],
body.hideDiscountRange_4 tr[data-discount-range="4"],
body.hideDiscountRange_5 tr[data-discount-range="5"],
body.hideDiscountRange_6 tr[data-discount-range="6"],
body.hideDiscountRange_7 tr[data-discount-range="7"],
body.hideDiscountRange_8 tr[data-discount-range="8"],
body.hideDiscountRange_9 tr[data-discount-range="9"] { display: none; }
.menuFilterDiscount { position: relative; }
.menuFilterDiscount ul {
width: 165px; max-height: 0;
position: absolute; top: 80px;
background-color: #2d3f51;
color: #FFF;
transition: max-height 0.5s ease;
overflow: hidden;
}
.menuFilterDiscount:hover ul { max-height: 500px; }
.menuFilterDiscount li { width: 100%; }
.menuFilterDiscount input { display: none; }
.menuFilterDiscount input:checked + span { color: #16A085; }
.menuFilterDiscount label {
width: 100%;
display: inline-block;
padding: 10px 20px;
text-align: right;
font-weight: 100;
text-transform: none;
box-sizing: border-box;
cursor: pointer;
}
.menuFilterDiscount label:hover input + span { color: #16A085; }
.menuFilterDiscount label:hover input:checked + span { color: #FFF; }
`);
const $nav = $('<nav class="SWSE_nav"><ul></ul></nav>');
$nav.prependTo('body').wrap('<header class="SWSE_header"></header>');
$nav.find('ul').append(
// hide owned button
$(`<li class="menuHideOwned"><a>${i18n.get('menuHideOwned')}</a></li>`).click(() => {
$('.menuHideOwned > a').text(document.body.classList.toggle('hideOwned') ? i18n.get('menuShowOwned') : i18n.get('menuHideOwned'));
}),
// hide DLC button
$(`<li class="menuHideDLC"><a>${i18n.get('menuHideDLC')}</a></li>`).click(() => {
$('.menuHideDLC > a').text(document.body.classList.toggle('hideDLC') ? i18n.get('menuShowDLC') : i18n.get('menuHideDLC'));
}),
// sync library button
$(`<li class="menuSyncLibrary"><a>${i18n.get('menuSyncLibrary')}</a></li>`).click(syncLibrary.bind(null, true)),
// settings button
$(`<li class="settings"><a>${i18n.get('settingsTitle')}</a></li>`).click(settings));
};
const handler = () => {
// order page, auto download keys
if (location.pathname.startsWith('/order/get/') || location.pathname === '/views/') {
const url = $('table a, .down a').eq(0).attr('href');
if (url.length > 0) {
fetch(url, {
method: 'GET',
credentials: 'include'
}).then(res => {
if (res.ok) return res.text();
throw Error('Request was not ok');
}).then(t => {
const keys = t.match(regKey).map(k => `<span>${k}</span><a class="activateOnSteam" href="https://store.steampowered.com/account/registerkey?key=${k}" target="_blank"></a>`);
$('table tr:last-child').before(`<tr><td>${i18n.get('keyField')}</td><td>${keys.join('<br>')}</td></tr>`);
$('.down > .btn-primary').before(`<p>${i18n.get('keyField')}<br>${keys.join('<br>')}</p>`);
GM_addStyle(`
.activateOnSteam {
width: 16px; height: 16px;
display: inline-block;
margin-left: 5px;
background-image: url("https://store.steampowered.com/favicon.ico");
}
`);
});
}
// product page
} else {
// pre-fill inputs
$('input[name=count]').val(config.get('count'));
$('input[name=email]').val(config.get('email'));
$('#agreeLicense').click();
if (has.call(discountCode, location.hostname)) {
$('input[name=copupon]').val(discountCode[location.hostname]);
}
// insert pay button
const $payButton = $(`<span class="SWSE_payButton">${i18n.get('payButtonText')}</span>`).click(() => {
const data = {
swse: true,
purse: $('#purse > span, #copyfund > b, #purse > span').text().trim() || $('.payment > input').val(),
amount: $('#price > span, .payprice, form#pay #price, table tr:nth-child(4) .wow').text().toLowerCase().trim(),
desc: $('#message > span, #copybill > b, #message > span').text().trim() || $('table tr:nth-child(6) input').val()
};
const paymentGateways = {
qiwi: 'https://qiwi.com/payment/form/99',
webmoney: 'https://wallet.web.money/finances'
};
const gateway = data.amount.includes('qiwi') ? 'qiwi' : 'webmoney';
data.currency = data.amount.includes('wm') ? data.amount.match(/[a-z]+/)[0] : 'wmz';
data.amount = parseFloat(data.amount);
window.open(`${paymentGateways[gateway]}?${JSON.stringify(data)}`, '', 'height=800,width=1000');
});
switch (location.hostname) {
case 'steamkeyswhosales.com':
case 'alfakeys.ru':
case 'cheapkeys.akens.ru':
$payButton.addClass('btn').css({
'margin-right': '10px',
cursor: 'pointer',
color: '#FFF',
'background-color': '#337ab7',
'border-color': '#2e6da4'
}).insertBefore('#check_pay');
break;
case 'cheap-steam-games.ru':
case 'lastkey.ru':
case 'keys.farm':
case 'steamkeys-shop.ru':
case 'maxfarmshop.ru':
case 'bestkeystore.ru':
case 'bestfarmkey.lequestore.ru':
case 'steamfarmkey.ru':
case 'indiegamekeys.lequestore.ru':
case 'randomkey.ru':
case 'farmkeys.ru':
case 'azimut-steam.leque.shop':
case 'alonekey.net':
case 'keys.lequestore.ru':
case 'wlutmarket.lequeshop.ru':
$payButton.addClass('btn-leque btn-leque-primary btn-leque-xs').css({ float: 'right', 'margin-top': '5px' }).insertAfter('.btn-leque-xs');
break;
case 'steam1.lequeshop.ru':
case 'steam1.ru':
case 'steam-tab.ru':
case 'steamd.lequeshop.ru':
case 'steamkeystore.ru':
case 'steamrandomkeys.ru':
case 'keyssell.ru':
$payButton.addClass('btn btn-primary').css('margin-top', '10px').insertBefore('.checkpayButton, .checkpaybtn');
break;
case 'dmshop.lequeshop.ru':
case 'kartonanet.lequeshop.ru':
case 'rig4all.lequeshop.ru':
case 'steamkey.lequeshop.ru':
case 'farmacc.ru':
case 'drunkpatrick.store':
case 'steamfarm.lequestore.ru':
case 'tkfg.ru':
case '200plus.lequeshop.ru':
case 'baty131shop.lequestore.ru':
case 'baty131shop.lequeshop.ru':
case '200plus.lequestore.ru':
case 'jplay.lequeshop.ru':
case 'animekeys.ru':
case 'gamesforfarm.lequeshop.com':
case 'bestgames.lequeshop.com':
case 'bobkeys.lequeshop.ru':
$payButton.addClass('btn btn-primary').insertBefore('.checkpayButton, .checkpaybtn');
break;
case 'steam-discount.ru':
$payButton.addClass('btn ipaid-btn btn-primary').css({
width: '200px',
'margin-right': '20px',
'font-size': 'x-large',
'line-height': '80px'
}).insertBefore('.ipaid-btn');
break;
default:
}
// check owned
switch (location.hostname) {
case 'www.cheapkeys.ovh':
case 'cheapkeys.ovh':
{
check('a[href*="steampowered"], img[src*="steam/apps/"]', ($ele, classes) => {
$ele.closest('tr.row, div.demo').addClass(classes);
});
// save discount code
const $as = $('a[data-clipboard-text]:has(img.cp)');
const codes = {};
$as.eachAsync(ele => {
const site = ele.hostname;
const code = ele.dataset.clipboardText.trim();
if (site && code.length > 0 && !has.call(codes, site)) codes[site] = code;
}, () => {
GM_setValue('SWSE_discount_code', JSON.stringify(codes));
});
// insert percentage off
GM_addStyle(`
td[data-discount-text] {
position: relative;
padding-right: 65px !important;
}
td[data-discount-text]::after {
content: attr(data-discount-text);
position: absolute;
top: 8px;
right: 10px;
}
`);
$('.menuSyncLibrary').before(`<li class="menuFilterDiscount"><a>${i18n.get('menuFilterDiscount')}<ul><li><label>${i18n.get('menuFilterDiscountLoading')}</label></li></ul></a></li>`);
$('.dataTable').css('width', '1280px');
forEachAsync($('#tables tbody tr').get(), tr => {
const price = parseFloat(tr.children[2].textContent);
const retail = parseFloat(tr.children[7].textContent);
let range = -1;
if (price > 0 && retail > 0) {
const discount = Math.min(100 - Math.round(price / retail * 100), 99);
tr.children[1].setAttribute('data-discount-text', `${discount}% off`);
if (discount >= 0) range = `00${discount}`.slice(-2).slice(0, 1);
}
tr.setAttribute('data-discount-range', range);
}, () => {
// finished inserting disocunts then append filter panel
const $ul = $('.menuFilterDiscount ul');
$ul.empty();
for (let i = -1; i < 10; i += 1) {
const text = i === -1 ? '~ - 0% off' : `${i * 10}% - ${(i + 1) * 10}% off`;
const $option = $(`<li><label><input type="checkbox" checked><span> ${text}</span></label></li>`);
$option.find('input').change(e => {
$('body').toggleClass(`hideDiscountRange_${i}`, !e.currentTarget.checked);
});
$ul.append($option);
}
});
break;
}
case 'steamkeyswhosales.com':
case 'alfakeys.ru':
case 'ign.akens.ru':
case 'bestkey.akens.ru':
case 'goldkeys.akens.ru':
case 'domenkeys.akens.ru':
case 'cada.akens.ru':
check('div[title*="steam"]', ($ele, classes) => {
$ele.closest('tr').addClass(classes);
});
break;
case 'keymarket.pw':
check('div[style*="steam/apps/"]', ($ele, classes) => {
$ele.nextAll().addClass(classes);
$ele.parent().parent().addClass(classes);
});
break;
case 'steamkey.lequeshop.ru':
check('img[src*="steam/apps/"]', ($ele, classes) => {
$ele.next().addClass(classes);
$ele.parent().addClass(classes);
});
break;
case 'cheap-steam-games.ru':
check('img[src*="steam/apps/"]', ($ele, classes) => {
$ele.closest('.hero-feature').addClass(classes);
$ele.parent().next().addClass(classes);
});
break;
case 'cheapkey.lequeshop.ru':
check('div[style*="steam/apps/"]', ($ele, classes) => {
$ele.parent().addClass(classes);
});
break;
case 'steamfarmkey.ru':
case 'kartonanet.lequeshop.ru':
case 'lastkey.ru':
case 'rig4all.lequeshop.ru':
case 'steamkeys-shop.ru':
case 'farmacc.ru':
case 'steamfarm.lequestore.ru':
case 'proxzy.lequestore.ru':
case 'maxfarmshop.ru':
case 'bestkeystore.ru':
case 'keys.farm':
case 'bestfarmkey.lequestore.ru':
case 'm-b-shop.leque.shop':
case 'indiegamekeys.lequestore.ru':
case '200plus.lequeshop.ru':
case 'farmkeys.ru':
case 'baty131shop.lequestore.ru':
case 'baty131shop.lequeshop.ru':
case '200plus.lequestore.ru':
case 'azimut-steam.leque.shop':
case 'imperiumkey.com':
case 'alonekey.net':
case 'keys.lequestore.ru':
case 'jplay.lequeshop.ru':
case 'gamesforfarm.lequeshop.com':
case 'bestgames.lequeshop.com':
case 'bobkeys.lequeshop.ru':
check('img[src*="steam"]', ($ele, classes) => {
$ele.closest('tr').addClass(classes);
});
break;
case 'keyssell.ru':
case 'steam-tab.ru':
case 'steamd.lequeshop.ru':
case 'steam1.ru':
case 'steamkeystore.ru':
case 'steam1.lequeshop.ru':
case 'steamrandomkeys.ru':
case 'sovkey-farm.ru':
check('a > img[src*="steam/apps/"]', ($ele, classes) => {
$ele.closest('.item-loop').addClass(classes);
$ele.closest('div').prev().addClass(classes);
});
check('.item-poster > img[src*="steam/apps/"]', ($ele, classes) => {
$ele.parent().addClass(classes);
$ele.prev().prev().addClass(classes);
});
break;
case 'reronage.akens.ru':
check('.good-title > div', ($ele, classes) => {
$ele.closest('tr').addClass(classes);
});
break;
case 'animekeys.ru':
check('img[src*="steam"]', ($ele, classes) => {
$ele.closest('.panel').addClass(classes);
});
break;
case 'steam-discount.ru':
check('img[src*="steam"]', ($ele, classes) => {
$ele.closest('div.item-loop').addClass(classes);
});
break;
case 'tkfg.ru':
check('a > img[src*="steam"]', ($ele, classes) => {
$ele.closest('.list-item').addClass(classes);
});
break;
case 'randomkey.ru':
$('#header').css('position', 'initial');
check('a > img[src*="steam"]', ($ele, classes) => {
$ele.parent().prev('.title').find('p').addClass(classes);
$ele.closest('.b-poster').addClass(classes);
});
break;
case 'wlutmarket.lequeshop.ru':
check('img[src*="steam"]', ($ele, classes) => {
$ele.closest('div.short').addClass(classes);
});
break;
case 'cheapkeys.akens.ru':
check('a[href*=steampowered]', ($ele, classes) => {
$ele.closest('div.good').addClass(classes);
});
break;
case 'steamground.com':
GM_xmlhttpRequest({
method: 'GET',
url: 'https://www.steamgifts.com/discussion/iy081/steamground-wholesale-build-a-bundle',
onload: res => {
if (res.status !== 200) return;
const $games = $('<div/>', {
html: res.response
}).find('.comment__description:first table a[href*="steampowered"]');
const $titles = $('.wholesale-card_title');
const hrefs = {};
const process = t => {
let tx = t.trim();
if (tx === 'Ball of Light (Journey)') tx = 'Ball of Light';
if (tx === 'Shake Your Money Simulator') tx = 'Shake Your Money Simulator 2016';
return tx.toLowerCase().replace(/[\W]/g, '');
};
$games.each((index, element) => {
hrefs[process(element.textContent)] = element.href;
});
$titles.each((index, element) => {
const $ele = $(element);
const href = hrefs[process($ele.text())] || '';
if (href.length > 0) $ele.parent().attr('href', href);
});
check('.wholesale-card > a[href*="steampowered"]', (element, classes) => {
$(element).parent().addClass(classes);
$(element).children().eq(1).css('color', 'black');
});
}
});
break;
default:
}
}
};
const init = () => {
// on WebMoney payment page (new)
if (location.hostname === 'wallet.web.money') {
if (location.pathname === '/finances' && location.search.length > 0) {
try {
const search = location.href.split('?').pop();
const data = JSON.parse(decodeURIComponent(search));
if (data.swse) {
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
Array.from(mutation.addedNodes).forEach(addedNode => {
if (addedNode.nodeType === 1) {
const $addedNode = $(addedNode);
if ($addedNode.find('img[src*="to-wm-purse.png"]').length > 0) $addedNode.click();
if ($addedNode.prop('tagName') === 'FORM' && $addedNode.attr('kz-root') === 'transfer') {
const $receiver = $addedNode.find('[name="receiver"] input');
const $amount = $addedNode.find('input[name="amount"]');
const $currency = $amount.next('select');
const $description = $addedNode.find('textarea[name="description"]');
$receiver.val(data.purse);
$amount.val(data.amount);
$currency.val(data.currency);
$description.val(data.desc);
unsafeWindow.angular.element($receiver).triggerHandler('input');
unsafeWindow.angular.element($amount).triggerHandler('input');
unsafeWindow.angular.element($currency).triggerHandler('change');
unsafeWindow.angular.element($description).triggerHandler('input');
sessionStorage.setItem('paidWM', 1);
}
if (sessionStorage.getItem('paidWM') && $addedNode.prop('tagName') === 'OPERATION-BLOCK') window.close();
}
});
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
} catch (err) {
throw err;
}
}
// on WebMoney payment page (old)
} else if (location.hostname === 'mini.wmtransfer.com') {
if (location.href.includes('purses-view-history') && sessionStorage.getItem('paidWM')) window.close();
if (location.pathname === '/SendWebMoney.aspx' && location.search.length > 0) {
try {
const search = location.href.split('?').pop();
const data = JSON.parse(decodeURIComponent(search));
if (data.swse) {
$('#ctl00_cph_tbEmailOrPurseNumber').val(data.purse);
$('#ctl00_cph_tbDesc').val(data.desc);
$('#ctl00_cph_tbAmount').val(data.amount);
sessionStorage.setItem('paidWM', 1);
}
} catch (err) {
throw err;
}
}
// on Qiwi payment page
} else if (location.hostname === 'qiwi.com') {
if (location.pathname === '/payment/form/99' && location.search.length > 0) {
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
Array.from(mutation.addedNodes).forEach(addedNode => {
const className = addedNode.nodeType === 1 ? addedNode.getAttribute('class') || '' : '';
if (className.includes('center-loader-self')) {
try {
const search = location.href.split('?').pop();
const data = JSON.parse(decodeURIComponent(search));
const $divs = $('#app form > div');
if (data.swse) {
$divs.eq(1).find('input').each((i, input) => {
input.value = `+${data.purse}`;
input._valueTracker.setValue('+'); // hack React16
input.dispatchEvent(new Event('input', { bubbles: true }));
});
$divs.eq(2).find('textarea').each((i, textarea) => {
textarea.value = data.desc;
textarea._valueTracker.setValue(''); // hack React16
textarea.dispatchEvent(new Event('input', { bubbles: true }));
});
$divs.eq(3).find('input').each((i, input) => {
input.value = data.amount;
input._valueTracker.setValue(''); // hack React16
input.dispatchEvent(new Event('input', { bubbles: true }));
});
$divs.find('.text-area-form-field-title-text-160, .mask-text-input-form-field-title-text-131').css({
top: 0,
'font-size': '13px'
});
sessionStorage.setItem('paidQiwi', 1);
}
} catch (err) {
throw err;
}
}
// close window on successful payment
if ($('div[class^="block-content-icon"] > svg[fill="#55D467"]').length > 0) window.close();
});
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
// wholesale sites
} else {
config.init();
i18n.init();
// sync owned every 10 min
const syncTimer = 10 * 60 * 1000;
if (!owned.lastSync || owned.lastSync < Date.now() - syncTimer) syncLibrary();
headerMenu();
handler();
}
};
$(init);