Skip to content

Instantly share code, notes, and snippets.

@thor
Last active December 20, 2015 06:49
Show Gist options
  • Save thor/6089044 to your computer and use it in GitHub Desktop.
Save thor/6089044 to your computer and use it in GitHub Desktop.
Steamy Helper - slightly more OOP, works in Firefox and Chrome w/Tampermonkey Gathered from http://userscripts.org/scripts/review/174037, modified to be more OOP and cleaner and meaner.

Steamy Helper

First README revision!

// ==UserScript==
// @name Steamy Helper
// @author Thor K.H.
// @version 2.4.1.3
// @description Automatically purchase items when they're below your budget, or just let the script agree to the SSA for you, so you can purchase in one click!
// @copyright Original v2.3 from SMH, further tweaks and OOP by Thor K. H. (2013)
// @include http://steamcommunity.com/market/listings/*
// @include https://steamcommunity.com/market/listings/*
// @grant none
// @run-at document-end
// @downloadURL https://gist.github.com/thor/6089044/raw/smh-oop.user.js
// ==/UserScript==
// ==UserScript==
// @name Steamy Helper
// @author Thor K.H.
// @version 2.4.1.3
// @description Automatically purchase items when they're below your budget, or just let the script agree to the SSA for you, so you can purchase in one click!
// @copyright Original v2.3 from SMH, further tweaks and OOP by Thor K. H. (2013)
// @include http://steamcommunity.com/market/listings/*
// @include https://steamcommunity.com/market/listings/*
// @grant none
// @run-at document-end
// @updateURL https://gist.github.com/thor/6089044/raw/smh-oop.meta.js
// @downloadURL https://gist.github.com/thor/6089044/raw/smh-oop.user.js
// ==/UserScript==
function SMHClass() {
this.initialize = function() {
console.info("-- Steamy Diagnostic information --");
console.log("Steamy version:", GM_info.script.version);
console.log("Web Browser:", navigator.userAgent);
console.log("Price:", Listing.getPrice());
console.log("Currency:", Listing.getCurrency());
console.log("Budget:", this.getBudget());
console.log("Within Budget:", this.getBudget() - Listing.getPrice() >= 0, "by", this.getBudget() - Listing.getPrice());
console.log("Auto-Buy:", this.getAutoBuy());
console.log("Auto-Reload:", this.getAutoReload());
console.log("Repeat Purchases:", this.isRepeating());
console.log("Maximum Purchases:", this.getMaxPurchases());
console.log("Current Purchase ID:", this.getCurrentPurchaseID());
console.log("Use Slow Mode:", this.getSlowMode());
console.log("Minimum Wait:", this.getMinWait());
console.log("Maximum Wait:", this.getMaxWait());
console.log("Confirmed:", this.isAutoBuyConfirmed());
console.log("Active Session:", this.isSessionActive());
this.addSettings();
this.checkSession();
Listing.agreeToSSA(true);
// Check to see if there's no budget, budget at 0 or no price.
if (this.getBudget() == null || this.getBudget() == undefined || Listing.getPrice() == 0) {
// Change the total cost visible to be bigger, with text underneath. See SMH.setTotal() for types available.
this.setTotal("noBudget");
}
// Check if the difference between the set session budget and price is higher than or equal to 0.
else if (Number(this.getBudget()) - Listing.getPrice() >= 0) {
this.setTotal("withinBudget");
this.setTitle(["withinBudget"]);
if (this.getAutoBuy() == "true") {
if (this.isAutoBuyConfirmed() == "true") {
Listing.finishPurchase();
} else {
this.setTitle(["noConfirm"]);
}
} else {
// Don't autobuy.
}
}
else {
var tempCost = Math.round((Listing.getPrice()-Number(this.getBudget()))*100)/100;
this.setTotal("overBudget");
this.setTitle(["overBudget", tempCost]);
if (this.getAutoReload() == "true") {
this.setTitle(["overBudgetAuto",tempCost]);
if (this.getSlowMode() == "true") {
if (Number(sessionStorage.maxwait) > Number(sessionStorage.minwait)) {
var delay = Math.floor(Math.random() * (Number(sessionStorage.maxwait) - Number(sessionStorage.minwait) + 1)) + Number(sessionStorage.minwait);
console.log("Delay by:", delay);
console.log("");
} else {
var delay = 5;
console.log("Invalid options were chosen for the delay. Using 5 second default.");
console.log("");
}
this.setTitle(["overBudgetAutoSlow", tempCost, delay]);
setTimeout(function(){ SMH.setSessionActive(true); window.location.reload(false) },(delay*1000));
} else {
this.setSessionActive(true);
window.location.reload(false);
}
} else {
// Don't auto-reload.
}
Listing.agreeToSSA(false);
}
};
this.addSettings = function() {
var smhParameters = " \
<div id=\"smh\"> \
</br>Your budget (do not enter currency symbol!):</br> \
<input type=\"text\" name=\"budget\" id=\"budget\" value=\"0\" maxlength=\"16\"> </br></br> \
<input type=\"checkbox\" name=\"autobuy\" id=\"autobuy\" value=\"true\"> Auto-Buy </br> \
<input type=\"checkbox\" name=\"autoreload\" id=\"autoreload\" value=\"true\"> Auto-Reload </br> \
<input type=\"checkbox\" name=\"repeatpurchase\" id=\"repeatpurchase\" value=\"true\"> Enable repeat purchases </br> \
Max Purchases: <input type=\"text\" name=\"maxpurchases\" id=\"maxpurchases\" value=\"1\" maxlength=\"3\"> </br></br> \
<input type=\"checkbox\" name=\"slowmode\" id=\"slowmode\" value=\"true\"> Use slow mode (limits refresh speed) </br> \
&nbsp;&nbsp;&nbsp;&nbsp; Minimum wait: <input type=\"text\" name=\"minwait\" id=\"minwait\" value=\"4\" maxlength=\"2\"> </br> \
&nbsp;&nbsp;&nbsp;&nbsp; Maximum wait: <input type=\"text\" name=\"maxwait\" id=\"maxwait\" value=\"8\" maxlength=\"2\"> </br></br> \
<input type=\"checkbox\" name=\"confirm\" id=\"confirm\" value=\"true\"> I confirm I want to purchase this item </br> \
<button id=\"submit\">Submit</button> <button id=\"clear\">Clear</button></br></br> \
<span style=\"font-size:10px;\">" + GM_info.script.name + " v" + GM_info.script.version + "</span> \
</div>";
document.getElementById('largeiteminfo_item_descriptors').innerHTML += smhParameters;
// Get the inserted settings node and its children.
var inputNode = document.getElementById("smh").childNodes;
// Loop through them to set current settings.
for (i=0; i<inputNode.length; i++) {
if (this._getSetting(inputNode[i].id) || this._getSetting(inputNode[i].id) == "true") {
switch (inputNode[i].type) {
case "text":
inputNode[i].value = this._getSetting(inputNode[i].id);
break;
case "checkbox":
if (this._getSetting(inputNode[i].id) == "true") {
inputNode[i].checked = true;
} else {
inputNode[i].checked = false;
}
break;
}
}
}
document.getElementById('submit').onclick = function() { SMH.setSessionSettings(); };
document.getElementById('clear').onclick = function() {
SMH.clearSettings();
for (i=0; i<inputNode.length; i++) {
inputNode[i].value = "";
inputNode[i].checked = false;
}
};
console.log("Settings added.");
};
this.checkSession = function() {
if (this.isSessionActive() == "true") {
console.log("");
console.log("This page was retrieved using Steam Market Helper.");
this.setSessionActive(false);
} else {
console.log("");
console.log("This page was retrieved manually.");
this.clearSettings();
this.setSessionActive(false);
}
if (!this.getCurrentPurchaseID()) {
this.setCurrentPurchaseID(1);
}
};
this.setSessionActive = function(value) {
this._setSetting("activeSession", value);
};
this.isSessionActive = function() {
return this._getSetting("activeSession");
};
this.setTitle = function(content) {
try {
var title = {
noBudget: "",
noConfirm: "<span style=\"font-size:20px;font-weight:bold;color:red;\"> You didn't confirm autobuy. Please manual purchase instead! </span>",
withinBudget: "<span style=\"font-size:20px;font-weight:bold;color:#66CC00;\">This item is within your budget!</span>",
overBudget: "<span style=\"font-size:20px;font-weight:bold;color:red;\">This item is outside your budget.</span>",
overBudgetAuto: "<span style=\"font-size:20px;font-weight:bold;color:red;\"> " + this.getCurrentPurchaseID() + " of " + Number(this.getMaxPurchases()) + " | This item is " + Listing.getCurrency(true) + content[1] + " too expensive. Reloading... </span>",
overBudgetAutoSlow: "<span style=\"font-size:20px;font-weight:bold;color:red;\"> " + this.getCurrentPurchaseID() + " of " + Number(this.getMaxPurchases()) + " | This item is " + Listing.getCurrency(true) + content[1] + " too expensive. Reloading in " + content[2] + " seconds... </span>",
attemptingPurchase: "<span style=\"font-size:20px;font-weight:bold;color:yellow;\">Attempting purchase " + this.getCurrentPurchaseID() + " of " + Number(this.getMaxPurchases()) + ". Please wait...</span>",
purchaseComplete: "<span style=\"font-size:20px;font-weight:bold;color:#66CC00;\">Script Complete. " + Number(this.getMaxPurchases()) + " item/s purchased! </span>",
purchaseContinue: "<span style=\"font-size:20px;font-weight:bold;color:#66CC00;\">Item purchased (" + (Number(this.getCurrentPurchaseID()) - 1) + " of " + Number(this.getMaxPurchases()) + "). Continuing in 3 seconds... </span>",
purchaseContinueSlow: "<span style=\"font-size:20px;font-weight:bold;color:#66CC00;\">Item purchased (" + (Number(this.getCurrentPurchaseID()) - 1) + " of " + Number(this.getMaxPurchases()) + "). Continuing in " + content[1] + " seconds... </span>",
purchaseFailed: "<span style=\"font-size:20px;font-weight:bold;color:red;\">Purchase failed. Retrying...</span>"
};
document.getElementById('market_buynow_dialog_title').innerHTML = title[content[0]];
} catch (e) {
console.error("Exception caught in setTitle: " + e);
}
};
this.setTotal = function(type) {
var title = {
noBudget: "<span style=\"font-size:48px;font-weight:bold;color:white;\">" + Listing.getCurrency(true) + Listing.getPrice() + "</span> </br>Not cheap enough?</br>Hit F5 to refresh.",
withinBudget: "<span style=\"font-size:48px;font-weight:bold;color:#66CC00;\">" + Listing.getCurrency(true) + Listing.getPrice() + "</span>",
overBudget: "<span style=\"font-size:48px;font-weight:bold;color:red;\">" + Listing.getCurrency(true) + Listing.getPrice() + "</span>"
};
try {
document.getElementById('market_buynow_dialog_totals_total').innerHTML = title[type];
} catch (e) {
console.error("Exception at setTitle: " + e);
}
};
this.setSessionSettings = function() {
this._setSetting("budget", document.getElementById('budget').value);
this._setSetting("autobuy", document.getElementById('autobuy').checked);
this._setSetting("autoreload", document.getElementById('autoreload').checked);
this._setSetting("repeatpurchase", document.getElementById('repeatpurchase').checked);
this._setSetting("maxpurchases", document.getElementById('maxpurchases').value);
this._setSetting("slowmode", document.getElementById('slowmode').checked);
this._setSetting("minwait", document.getElementById('minwait').value);
this._setSetting("maxwait", document.getElementById('maxwait').value);
this._setSetting("confirm", document.getElementById('confirm').checked);
this.setSessionActive(true);
window.location.reload(false);
};
this.checkForErrors = function() {
var errorContainer = document.getElementById('market_buynow_dialog_error_text'),
i = o,
errorMessage = [
"You cannot purchase this item because somebody else has already purchased it.",
"There was a problem purchasing your item. The listing may have been removed. Refresh the page and try again.",
"There was an error getting listings for this item. Please try again later.",
"No puedes comprar este artículo porque ya lo ha comprado otro usuario.",
"Se ha producido un problema al comprar tu artículo. Puede que se haya eliminado la publicación. Actualiza la página e inténtalo de nuevo.",
"Se ha producido un error al obtener las publicaciones de este artículo. Por favor, inténtalo de nuevo más tarde.",
"Sie können diesen Artikel nicht kaufen, da er bereits von jemand anderem gekauft wurde.",
"Beim Kauf Ihres Artikels ist ein Problem aufgetreten. Das Angebot wurde möglicherweise entfernt. Aktualisieren Sie die Seite und versuchen Sie es erneut.",
"Você não pode comprar este item porque outra pessoa já o comprou.",
"Ocorreu um problema com a compra do seu item. É possível que a lista tenha sido removida. Atualize a página e tente novamente.",
"Não podes comprar este item porque outra pessoa já o comprou.",
"Ocorreu um problema com a compra do teu item. É possível que o anúncio do item tenha sido removido. Atualiza a página e tenta novamente.",
"Vous ne pouvez pas acheter cet objet car celui-ci a déjà été acheté par un autre utilisateur.",
"Un problème est survenu lors de l'achat de l'objet. Il se peut que l'offre ait été supprimée. Actualisez la page puis réessayez.",
"Не удалось купить данный предмет, так как его уже приобрел кто-то другой.",
"Ошибка при покупке предмета. Возможно, лот был удален. Обновите страницу и повторите попытку."
];
for (i; i < errorMessage.length; i++) {
if (errorContainer.innerHTML == errorMessage[i]) {
return true;
}
}
};
this.checkPurchaseSuccess = function() {
if (this.checkForErrors()) {
this.setTitle(["purchaseFailed"]);
this.setSessionActive(true);
window.location.reload(false);
} else {
if (this.isRepeating() == "true" && this.getMaxPurchases() !== 1 && Number(this.getCurrentPurchaseID()) < Number(this.getMaxPurchases())) {
if (this.getCurrentPurchaseID()) {
this.setCurrentPurchaseID(Number(this.getCurrentPurchaseID()) + 1);
if (this.getSlowMode() == "true") {
if (Number(this.getMaxWait()) > Number(this.getMinWait())) {
var delay = Math.floor(Math.random() * (Number(this.getMaxWait()) - Number(this.getMinWait()) + 1)) + Number(this.getMinWait());
console.log("Delay by:", delay);
console.log("");
} else {
var delay = 3;
console.log("Invalid options were chosen for the delay. Using 3 second default.");
console.log("");
}
this.setTitle(["purchaseContinueSlow", delay]);
setTimeout(function(){ this.setSessionActive(true); window.location.reload(false); },(delay*1000));
} else {
this.setTitle(["purchaseContinue"]);
setTimeout(function(){ this.setSessionActive(true); window.location.reload(false); },3000);
}
} else {
this.setCurrentPurchaseID(1);
}
} else {
this.setTitle(["complete"]);
this.clearSettings();
this.setCurrentPurchaseID(1);
alert("Purchase complete!\nThanks for using Steam Market Helper!");
}
}
};
this.getSupport = function() {
if (browser_raw.indexOf("Chrome") !== -1) {
var browser = "chrome";
} else if (browser_raw.indexOf("Firefox") !== -1) {
var browser = "firefox";
} else {
var browser = browser_raw;
}
};
this.setBudget = function(budget) {
this._setSetting("budget", budget);
};
this.getBudget = function() {
return this._getSetting("budget");
};
this.getAutoBuy = function() {
return this._getSetting("autobuy");
};
this.isAutoBuyConfirmed = function() {
return this._getSetting("confirm");
};
this.getAutoReload = function() {
return this._getSetting("autoreload");
};
this.isRepeating = function() {
return this._getSetting("repeatpurchase");
};
this.getSlowMode = function() {
return this._getSetting("slowmode");
};
this.getMinWait = function() {
return this._getSetting("minwait");
};
this.getMaxWait = function() {
return this._getSetting("maxwait");
};
this.getMaxPurchases = function() {
return this._getSetting("maxpurchases");
};
this.getCurrentPurchaseID = function() {
return this._getSetting("CurrentPurchaseID");
};
this.setCurrentPurchaseID = function(id) {
this._setSetting("CurrentPurchaseID", id);
};
this._getSetting = function(key) {
return sessionStorage[key];
};
this._setSetting = function(key, value) {
try {
sessionStorage[key] = value;
} catch (e) {
console.error("Exception caught during _setSetting: " + e);
}
};
this.clearSettings = function() {
sessionStorage.clear();
console.info("Stored settings have been cleared.");
};
}
function ListingClass() {
var _Currency,
_Price;
this.showPurchaseWindow = function() {
document.getElementsByClassName('item_market_action_button_green')[0].click();
};
this.finishPurchase = function() {
console.info("Attempting purchase at price " + this.getCurrency(true) + this.getPrice() + ", with budget " + SMH.getBudget());
var purchaseButton = document.getElementById('market_buynow_dialog_purchase');
SMH.setTitle(["attemptingPurchase"]);
purchaseButton.click();
setTimeout(SMH.checkPurchaseSuccess,8000);
};
this.agreeToSSA = function(bool) {
document.getElementById('market_buynow_dialog_accept_ssa').checked = bool;
};
this.getPrice = function() {
if (!_Price) {
try {
var rawPrice = document.getElementById('market_buynow_dialog_totals_total').innerHTML,
currency = this.getCurrency();
if (currency == "pounds") {
_Price = rawPrice.split('£')[1];
} else if (currency == "real") {
_Price = rawPrice.split('R$ ')[1].replace(',' , '.');
} else if (currency == "dollars") {
_Price = rawPrice.split('$')[1];
} else if (currency == "euros") {
_Price = rawPrice.split('€')[0].replace(',' , '.');
} else if (currency == "rubles") {
_Price = rawPrice.split(' ')[0].replace(',' , '.');
}
console.info("Price has been detected and saved to be: " + _Price);
return _Price;
} catch (e) {
console.error("Exception caught during getPrice: " + e);
}
} else if (_Price) {
return _Price;
} else {
console.error("Failed to deliver getPrice()");
}
};
this.getCurrency = function(raw) {
if (!_Currency) {
try {
var rawPrice = document.getElementById('market_buynow_dialog_totals_total').innerHTML;
if (rawPrice.indexOf('£') !== -1) {
_Currency = "pounds";
} if (rawPrice.indexOf('R$') !== -1) {
_Currency = "real";
} if (rawPrice.indexOf('$') !== -1) {
_Currency = "dollars";
} if (rawPrice.indexOf('€') !== -1) {
_Currency = "euros";
} if (rawPrice.indexOf('\u0443') !== -1) {
_Currency = "rubles";
}
console.info("Currency has been detected and saved to be: " + _Currency);
return _Currency;
} catch (e) {
console.error("Exception caught during getCurrency: " + e);
return false;
}
} else {
if (raw) {
switch (_Currency) {
case "pounds":
return "£";
break;
case "real":
return "R$";
break;
case "dollars":
return "$";
break;
case "euros":
return "€";
break;
case "rubles":
return "\u0443";
break;
default:
console.error("Failed to return raw currency symbol.");
}
} else {
return _Currency;
}
}
};
}
// globally define SMH; though, no instance yet
var SMH;
// we need this for init, so it's up and running right away
var Listing = new ListingClass();
// create a mutation observer to catch the changes to elements matched by the querySelector
// callback checks to see if "SMH" isn't the object yet, and if so, initializes it
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
var list = document.querySelector('#market_buynow_dialog_totals_total');
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (Listing.getPrice()) {
console.log("Price isn't blank; checking for previous initialization.");
if (typeof SMH !== 'object') {
console.log("No previous initalization; initializing.");
SMH = new SMHClass();
SMH.initialize();
} else {
console.log("Previous initialization found; discarding.");
}
} else {
console.log("Price is blank or unknown; discarding.");
}
});
});
observer.observe(list, {
attributes: true,
childList: true,
characterData: true
});
// first-most initialization that causes purchase window to appear
// and mutation callback to occur, thusly initializing
Listing.showPurchaseWindow();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment