// ==UserScript==
// @name Add SteamDB Sale Item Into Steam Chart
// @namespace http://tampermonkey.net/
// @version 1.5.5
// @description SteamDB一键添加购物车
// @icon https://steamdb.info/static/logos/32px.png
// @author jklujklu
// @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/jquery-jgrowl/1.4.8/jquery.jgrowl.min.js
// @match https://steamdb.info/sales/*
// @match http://steamdb.info/sales/*
// @grant GM_xmlhttpRequest
// @grant GM_getResourceText
// @grant GM_addStyle
// @run-at document-end
// @resource layerCss https://cdnjs.cloudflare.com/ajax/libs/jquery-jgrowl/1.4.8/jquery.jgrowl.min.css
// @license MIT
// ==/UserScript==
(function () {
'use strict';
const steamStore = 'https://store.steampowered.com';
const steamCart = 'https://store.steampowered.com/cart/addtocart';
const steamInfo = 'https://store.steampowered.com/app/'
let sessionId = '';
function getSessionId() {
return new Promise(resolve => {
GM_xmlhttpRequest({
method: "GET",
url: steamStore,
onload: response => {
console.log("SessionId请求成功");
// console.log(response.responseText);
const str = response.responseText;
const pattern = /g_sessionID = "(.+)";/;
if (pattern.test(str)) {
// console.log(pattern.exec(str)[1])
sessionId = pattern.exec(str)[1];
popUp(`SessionId 獲取成功!${sessionId}`);
} else {
popUp(`SessionId 獲取失敗!`);
}
resolve(sessionId);
},
onerror: response => {
popUp("SessionId请求失败,请检查网络状况!");
}
});
});
}
function addChart(subId, subType, appId, parentElement) {
if (subType !== 'game'){
popUp('暂不支持添加Bundle类型的游戏!');
return;
}
const formData = new FormData()
formData.append('subid', subId);
formData.append('sessionid', sessionId);
formData.append('action', 'add_to_cart');
GM_xmlhttpRequest({
url: steamCart,
headers: {
'Content-Type': 'multipart/form-data',
Origin: 'https://store.steampowered.com',
Referer: 'https://store.steampowered.com/'
},
data: formData,
method: 'POST',
onload: response => {
console.log("Add Chart请求成功");
const rs = JSON.parse(response.responseText);
console.log(rs);
if (rs.success) {
popUp(`appId: ${appId} 添加购物车成功!`);
parentElement.style.background = 'rgba(0,156,0,0.5)';
document.querySelector('#app-2').style.opacity = 0;
document.querySelector('#app-2').style.display = 'none';
} else {
popUp(`添加购物车失败!`)
}
},
onerror: response => {
popUp("添加购物车请求失败,请检查网络状况!");
}
});
}
function popUp(msg) {
$.jGrowl(msg)
}
function getGameSubs(appId){
return new Promise(resolve =>{
GM_xmlhttpRequest({
url: steamInfo + appId,
headers: {
Origin: 'https://store.steampowered.com',
Referer: 'https://store.steampowered.com/'
},
method: 'GET',
onload: response => {
console.log("获取游戏界面成功!");
if(response.responseText.indexOf('agegate_birthday_selector') !== -1){
resolve('birthday')
}
const doc = new DOMParser().parseFromString(response.responseText, 'text/html');
let games = [];
const wrappers = doc.querySelectorAll('.game_area_purchase_game_wrapper');
for (let index = 0; index < wrappers.length; index++) {
const game = wrappers[index];
let input_sub = game.querySelector('form input[name="subid"]');
const div_discount = game.querySelector('.discount_pct');
let div_price = game.querySelector('.discount_final_price');
if(!div_discount){
div_price = game.querySelector('.game_purchase_price');
}
let subType = 'game';
if(!input_sub){
subType = 'bundle';
input_sub = game.querySelector('form input[name="bundleid"]');
}
const title = game.querySelector('.game_area_purchase_game h1').firstChild.nodeValue.replace(/(^\s*)|(\s*$)/g, "").replace('购买', '');
const discount = div_discount ? div_discount.firstChild.nodeValue.replace(/(^\s*)|(\s*$)/g, "") : '-0%'
const sub = input_sub.getAttribute('value');
const price = div_price.firstChild.nodeValue.replace(/(^\s*)|(\s*$)/g, "");
console.log(title, discount, price, sub, subType);
games.push({title, discount, price, sub, subType})
}
resolve(games);
},
onerror: response => {
popUp("获取游戏Sub失败!");
}
});
})
}
function bindElement(){
console.log('start bind steam icon')
const appimgs = document.querySelectorAll('.app');
for (let index = 0; index < appimgs.length; index++) {
const element = appimgs[index];
if (element.querySelector('td:nth-child(1) a').getAttribute('href') !== 'javascript:void(0)') {
element.querySelector('td:nth-child(1) a').setAttribute('href', 'javascript:void(0)');
element.querySelector('td:nth-child(1) a').removeAttribute('target');
element.querySelector('td:nth-child(1)').onclick = async() => {
document.querySelector('#app-2 tbody').innerHTML = '';
const dataId = element.getAttribute('data-appid');
const subs = await getGameSubs(dataId);
if(subs === 'birthday'){
popUp('需要进行生日验证,请手动前往该游戏页面验证!');
window.open(steamInfo + dataId,"_blank", '');
return;
}
const game_subs = subs.filter(e => e.subType === 'game');
if(game_subs.length === 1){
addChart(game_subs[0].sub, game_subs[0].subType, dataId, element);
return;
}else if(game_subs.length === 0){
popUp('未找到该游戏的Sub,请前往商店查看是否存在购买选项!');
window.open(steamInfo + dataId,"_blank", '');
return;
}
document.querySelector('#app-2').style.opacity = 1;
document.querySelector('#app-2').style.display = 'block';
for (let index = 0; index < subs.length; index++) {
const game = subs[index];
const _tr = document.createElement('tr');
_tr.innerHTML =
`<th>${game.title}</th>
<th>${game.discount}</th>
<th>${game.price}</th>
<th>${game.subType}</th>
<th>${game.sub}</th>
<th><button class="btn">Add</div></th>`
_tr.querySelector('.btn').addEventListener('click', ()=>{
addChart(game.sub, game.subType, dataId, element);
})
document.querySelector('#app-2 tbody').append(_tr);
}
}
}
}
}
function initPane(){
const div = document.createElement('div');
div.innerHTML =
`<div id="app-2" class="header-sales-filters" style="display:none;opacity: 0;transition: 0.5s;width: 60%;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);background: #eee;z-index: 9999;color: black;padding: 10px;">
<table style="width: 100%;height: 100%;">
<thead>
<tr>
<th>游戏</th>
<th>折扣</th>
<th>价格</th>
<th>Sub类型</th>
<th>SubId</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>`
document.body.append(div);
}
// Your code here...
const layerCss = GM_getResourceText('layerCss');
GM_addStyle(layerCss);
async function start(){
initPane();
bindElement();
const rs = await getSessionId();
console.log(`Receive Session: ${rs}`);
$("#DataTables_Table_0 > tbody").bind('DOMNodeInserted', bindElement);
}
const timer = setInterval(()=>{
if(typeof $.jGrowl === 'function'){
document.styleSheets[0].addRule('#jGrowl', 'top: 48px');
clearInterval(timer);
start();
}else{
console.log('wait for jquery.jgrowl')
}
}, 200)
})();