// ==UserScript==
// @name IsThereCouponForThis
// @name:en IsThereCouponForThis
// @namespace https://greasyfork.org/users/2205
// @description Отображает доступные купоны с помощью значка на странице магазина, на виджетах встроенных на форуме и в вишлисте.
// @description:en Show coupons available on game steam store page, on wishlist and on widgets embedded in steamcommunity discussions.
// @license Apache-2.0
// @author Rudokhvist
// @include http://store.steampowered.com/*
// @include https://store.steampowered.com/*
// @connect pastebin.com
// @run-at document-end
// @version 2.8
// @grant GM.xmlhttpRequest
// @grant GM_xmlhttpRequest
// @language English
// ==/UserScript==
var debug = false;
var getJSON = function(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'json';
xhr.onload = function() {
var status = xhr.status;
if (status === 200) {
callback(null, xhr.response);
} else {
callback(status, xhr.response);
}
};
xhr.send();
};
//rate limiting
var getJSONRL = function(url, callback) {
var Rate=1500; //ms between requests;
var lastCall=localStorage.getItem ('ITCFTRateLimiter');
if (lastCall!==null) {
if ((parseInt(lastCall) + Rate) > Date.now()) {
window.setTimeout(function(){
getJSONRL(url,callback);
},parseInt(lastCall)+Rate-Date.now());
} else { //already time
getJSON(url,callback);
localStorage.setItem('ITCFTRateLimiter',Date.now());
}
} else { //first call ever
getJSON(url,callback);
localStorage.setItem('ITCFTRateLimiter',Date.now());
}
};
var elemVisible =function( elem ) {
if (elem===null) {
return false;
} else {
return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
}
};
var processWishlist = function (subids,couponMap,container){
var NewElement=document.createElement("span");
NewElement.setAttribute("style","font-size:18px;text-align: center;cursor:default;border-radius: 2px 2px 2px; border: 1px solid; user-select: none !important; pointer-events:auto !important; line-height: 1; margin-left: 5px; margin-right: 5px;");
NewElement.setAttribute("class","platform_img");
NewElement.setAttribute("tag","coupondata");
var foundcoupons=0;
var foundlist="";
if (subids.length == 0){
if (debug) {console.log(' placeholder used');}
NewElement.setAttribute("title","Getting data");
var img = document.createElement("img");
img.witdh = 16;
img.height = 16;
img.src = "https://steamcommunity-a.akamaihd.net/public/images/login/throbber.gif";
NewElement.appendChild(img);
} else {
for (var m=0;m<subids.length;m++) {
if (couponMap.has(subids[m])) {
if (foundcoupons>0) {
foundlist=foundlist+", ";
}
foundlist=foundlist+couponMap.get(subids[m]);
foundcoupons++;
}
}
if (foundcoupons>0) {
NewElement.setAttribute("title","Coupons: "+foundlist);
NewElement.appendChild(document.createTextNode("$"));
} else {
NewElement.setAttribute("title","No Coupons Found");
NewElement.appendChild(document.createTextNode("X"));
}
}
var showplace=container.getElementsByClassName('platform_icons')[0];
if (showplace.querySelector('[tag="coupondata"]')!==null){
showplace.removeChild(showplace.querySelector('[tag="coupondata"]'));
}
var newchild=showplace.appendChild(NewElement);
newchild.addEventListener('touchstart', function() {
this.classList.add('touched');
}.bind(newchild));
};
var processWishlistRow = function(container,couponMap){
if (container.querySelector('[tag="coupondata"]')!==null){
return;
}
var subidContainer=container.querySelector('[name="subid"]');
var subids=[];
if (subidContainer===null) {
if (debug) {console.log(new Date(Date.now()).toTimeString()+' We dont have subid for '+ container.getElementsByClassName('title')[0].innerText);}
var appid=container.getAttribute('data-app-id');
(function(appid,subids,couponMap,container){
var cachedPackages=sessionStorage.getItem("ITCFTappid"+appid);
if (cachedPackages===null) {
if (debug) {console.log(new Date(Date.now()).toTimeString()+' Getting subids for '+ container.getElementsByClassName('title')[0].innerText);}
processWishlist([],couponMap,container);
getJSONRL('https://store.steampowered.com/api/appdetails?appids='+appid, function(err, data) {
if (err !== null) {
console.log(new Date(Date.now()).toTimeString()+' Something went wrong: ' + err);
} else {
subids.lenght=0;
if (typeof(data[appid].data.packages)!=='undefined') {
sessionStorage.setItem("ITCFTappid"+appid,data[appid].data.packages.toString());
for (var w=0;w<data[appid].data.packages.length;w++){
subids.push(data[appid].data.packages[w].toString());
}
if (debug) {console.log(new Date(Date.now()).toTimeString()+' Aquired subids for '+ container.getElementsByClassName('title')[0].innerText+" are: "+subids.toString());}
processWishlist(subids,couponMap,container);
} else {
if (debug) {console.log(new Date(Date.now()).toTimeString()+' No subids aquired for '+ container.getElementsByClassName('title')[0].innerText);}
//if no subid found - store empty line, to prevent further requests.
//it will be cached only untill browser restart, so it's fine.
sessionStorage.setItem("ITCFTappid"+appid,"");
processWishlist([0],couponMap,container); //show "no coupons"
}
}
});
} else { //Cached subids
subids.lenght=0;
var packages=cachedPackages.split(",");
for (var x=0;x<packages.length;x++){
subids.push(packages[x]);
}
if (debug) {console.log(new Date(Date.now()).toTimeString()+' Cached subids for '+ container.getElementsByClassName('title')[0].innerText+" are: "+subids.toString());}
processWishlist(subids,couponMap,container);
}
})(appid,subids,couponMap,container);
} else {
subids.push(subidContainer.value);
processWishlist(subids,couponMap,container);
}
}
var renewWishlist = function(couponMap){
var containers=document.getElementsByClassName('wishlist_row');
for (var k=0;k<containers.length;k++) {
processWishlistRow(containers[k],couponMap);
var container=containers[k];
}
};
+function(){
var style = document.createElement("style");
style.appendChild(document.createTextNode(""));
document.head.appendChild(style);
var sheet=style.sheet;
sheet.insertRule("[title] { border-bottom: 1px dashed rgba(0, 0, 0, 0.2); border-radius:2px; position: relative; }",0);
sheet.insertRule(".touched[title]:hover:after { position: absolute; bottom: 100%; left: -10%; content: attr(title); border: 1px solid rgba(0, 0, 0, 0.2); background-color: white; color: black !important; box-shadow: 1px 1px 3px; padding: 0.3em; z-index: 1; font-size: 11px !important;}",0);
var couponMap = new Map();
GM_xmlhttpRequest({
method: "GET",
url: "https://pastebin.com/raw/i8ri7Ne7",
onload: function(response) {
var couponlist = response.responseText;
var couponlistlines = couponlist.split('\n');
for (var i=1 ; i<couponlistlines.length ; i++) { //start from 1 line to exclude header
if (couponlistlines[i].startsWith('=====')) break; //stop at first separator, to avoid double records
var coupondata=couponlistlines[i].split('\t');
if (coupondata.length>3) {
var subids=coupondata[3].split(',');
for (var j=0; j<subids.length; j++) {
if (couponMap.has(subids[j])) {
couponMap.set(subids[j],couponMap.get(subids[j])+", "+coupondata[0]);
} else {
couponMap.set(subids[j],coupondata[0]);
}
}
}
}
var timerId = window.setInterval(function WLReady() {
if (!elemVisible(document.getElementById('throbber'))) {
clearInterval(timerId);
//store page
var containers=document.getElementsByClassName('game_area_purchase_game');
for (var k=0;k<containers.length;k++) {
var container=containers[k];
var subidcontainer=container.querySelector('[name="subid"]');
if (subidcontainer!==null) {
var subid=subidcontainer.value;
var NewElement=document.createElement("span");
NewElement.setAttribute("style","font-size:18px;text-align: center;cursor:default;border-radius: 2px 2px 2px; border: 1px solid; user-select: none !important; pointer-events:auto !important; line-height: 1; margin-left: 5px; margin-right: 5px;");
NewElement.setAttribute("class","platform_img");
if (couponMap.has(subid)){
NewElement.setAttribute("title","Coupons: "+couponMap.get(subid));
NewElement.appendChild(document.createTextNode("$"));
} else {
NewElement.setAttribute("title","No Coupons Found");
NewElement.appendChild(document.createTextNode("X"));
}
var showplace=container.getElementsByClassName('game_area_purchase_platform')[0];
var newchild=showplace.insertBefore(NewElement,showplace.firstChild);
newchild.addEventListener('touchstart', function() {
this.classList.add('touched');
}.bind(newchild));
}
}
//forum widgets
var wcontainer=document.getElementById ('widget');
if (wcontainer!==null) {
subid=wcontainer.querySelector('[name="subid"]').value;
NewElement=document.createElement("span");
NewElement.setAttribute("style","font-size:18px;text-align: center;cursor:default;border-radius: 2px 2px 2px; border: 1px solid; user-select: none !important; pointer-events:auto !important;");
NewElement.setAttribute("class","platform_img");
if (couponMap.has(subid)){
NewElement.setAttribute("title","Coupons: "+couponMap.get(subid));
NewElement.appendChild(document.createTextNode("$"));
} else {
NewElement.setAttribute("title","No Coupons Found");
NewElement.appendChild(document.createTextNode("X"));
}
showplace=wcontainer.getElementsByClassName('game_area_purchase_platform')[0];
var newwchild=showplace.appendChild(NewElement);
newwchild.addEventListener('touchstart', function() {
this.classList.add('touched');
}.bind(newwchild));
}
//wishlist
if (document.getElementsByClassName('wishlist_row').length>0) {
renewWishlist(couponMap);
var mutationObserver = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
mutation.addedNodes.forEach( function(currentValue, currentIndex, listObj) {
if (currentValue.nodeType == Node.ELEMENT_NODE) {
if (currentValue.className == 'wishlist_row'){
processWishlistRow(currentValue,couponMap);
}
}
});
});
});
mutationObserver.observe(document.documentElement, {
childList: true,
subtree: true
});
}
} //main work
},100); //SetInterval
},
onerror: function() {
console.log('Error.');
}
});
}();