// ==UserScript==
// @name Steam, Card sets viewer
// @name:ja Steam, Card sets viewer
// @namespace http://tampermonkey.net/
// @version 1.0.2
// @description Happy trading 1:1 card sets
// @description:ja Happy trading 1:1 card sets
// @author You
// @require http://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js
// @match https://steamcommunity.com/tradeoffer/*
// @grant GM.xmlHttpRequest
// @runat document-end
// @nowrap
// ==/UserScript==
(function() {
'use strict';
var $ = jQuery.noConflict();
var getBadgeInfoUrl = "https://www.steamcardexchange.net/api/request.php?GetBadgePrices_Member";
var CacheKey = "BadgeInformatinCache";
var MaxBadgeLevel = 5;
function escapeHtml (string) {
if(typeof string !== 'string') {
return string;
}
return string.replace(/[&'`"<>]/g, function(match) {
return {
'&': '&',
"'": ''',
'`': '`',
'"': '"',
'<': '<',
'>': '>',
}[match]
});
}
function getSteamInventory () {
var inv = g_ActiveInventory;
if (!inv) throw "Error: Not found inventory";
if (!inv.initialized) throw "Error: Inventory is unloaded";
if (inv.appid != "753") throw "Error: Inventory isn't Steam Inventory";
if (!inv.rgInventory) throw "Error: Inventory is unloaded";
console.log("Inventory loaded");
return inv;
}
function main(inventory) {
var sets = {};
var isSelfInventory = $("#inventory_select_your_inventory").hasClass("active");
var isExtraOnly = $("#DisplayExtraOnlyCheckbox")[0].checked;
var rgInventory = inventory.rgInventory;
function onLoadBadgeInformation(xhr, cache) {
var badges = cache || JSON.parse(xhr.responseText);
if (!cache) {
localStorage[CacheKey] = xhr.responseText;
}
console.log(badges);
var fee, set;
var data = badges.data;
// Add badge information to sets variable
for (var i = 0; i < data.length; i++) {
set = sets[data[i][0][0]];
if (!set) continue;
// Appid (market_fee_app) have been already added
// data[i][0][0]
set.title = data[i][0][1];
set.cardsInSet = data[i][1];
set.badgeValue = data[i][2];
set.yourLevel = parseInt(data[i][3]);
// Updated timestamp isn't necessary
// data[i][4]
set.fullSetQuantity = 0;
set.hasFullSet = false;
}
// Count complete card sets
for (fee in sets) {
set = sets[fee];
var totalCards = 0;
var cardsCount = 0;
var minQty = Number.MAX_VALUE;
for (var hash in set.items) {
var item = set.items[hash];
minQty = Math.min(minQty, item.quantity);
cardsCount++;
totalCards += item.quantity;
}
set.totalCards = totalCards;
if (set.cardsInSet > 0 && set.cardsInSet == cardsCount) {
set.hasFullSet = true;
set.fullSetQuantity = minQty;
if (isSelfInventory) {
var extraQuantity = set.fullSetQuantity - (MaxBadgeLevel - set.yourLevel);
set.extraQuantity = extraQuantity > 0 ? extraQuantity : 0;
set.necessaryQuantity = 0;
} else {
set.extraQuantity = 0;
set.necessaryQuantity = Math.min(MaxBadgeLevel - set.yourLevel, set.fullSetQuantity);
}
} else {
set.hasFullSet = false;
set.fullSetQuantity = 0;
set.extraQuantity = 0;
set.necessaryQuantity = 0;
}
}
var displayList = [];
for (fee in sets) {
set = sets[fee];
if (!set.hasFullSet) continue;
if (isSelfInventory && isExtraOnly && set.extraQuantity <= 0) continue;
if (!isSelfInventory && isExtraOnly && set.necessaryQuantity <= 0) continue;
displayList.push(set);
}
// sort by title
displayList.sort(function (a, b) {
return a.title > b.title ? 1 : -1;
});
var textBuilder = "";
var markdownBuilder = "";
var htmlBuilder = "";
for (var k = 0; k < displayList.length; k++) {
set = displayList[k];
var qty = set.fullSetQuantity;
if (isExtraOnly) {
qty = isSelfInventory ? set.extraQuantity : set.necessaryQuantity;
}
var setUrl = inventory.owner.strProfileURL + "/gamecards/" + set.appId + "/";
var perValue = Math.round(parseFloat(set.badgeValue.replace("$", "")) / set.cardsInSet * 1000) / 1000;
// Add content as text to pre tag so don't need to html-escape
textBuilder += "{qty}x {title}\n"
.replace("{qty}", qty)
.replace("{title}", set.title);
// Add content as text to pre tag so don't need to html-escape
markdownBuilder += "{qty}x [{title}]({url}) ({cards})\n"
.replace("{qty}", qty)
.replace("{title}", set.title)
.replace("{url}", setUrl)
.replace("{cards}", set.cardsInSet);
// Append content as html to body so need to html-escape variables
htmlBuilder += "<div>{qty}x <a href='{url}' target='_blank'>{title}</a> ({cards} as {value} / ${pervalue} each) <button data-fee='{fee}' class='AddSetToTradeButton'>Add to trade</button></div>"
.replace("{qty}", qty)
.replace("{title}", escapeHtml(set.title))
.replace("{url}", setUrl)
.replace("{fee}", set.appId)
.replace("{cards}", set.cardsInSet)
.replace("{value}", set.badgeValue)
.replace("{pervalue}", perValue);
}
$("<div />")
.append("<div><a class='SwitchSetList'>Text</a><a class='SwitchSetList'>Markdown</a><a class='SwitchSetList'>Html</a><a class='CloseSetList'>Close</a></div>")
.append($("<pre />").addClass("SetListText").text(textBuilder))
.append($("<pre />").addClass("SetListMarkdown").text(markdownBuilder))
.append($("<div />").addClass("SetListHtml").append(htmlBuilder))
.attr("id", "SetListContainer")
.addClass("VisibleText")
.appendTo("body");
$(".SwitchSetList").click(function (ev) {
ev.preventDefault();
ev.stopPropagation();
$("#SetListContainer")
.removeClass("VisibleText")
.removeClass("VisibleMarkdown")
.removeClass("VisibleHtml")
.addClass("Visible" + $(this).text());
});
$(".CloseSetList").click(function (ev){
ev.preventDefault();
ev.stopPropagation();
$("#SetListContainer").remove();
});
$(".AddSetToTradeButton").click(function (ev) {
ev.preventDefault();
ev.stopPropagation();
var fee = $(this).attr("data-fee");
var targetSet = sets[fee];
var targets = [];
for (var hash in targetSet.items) {
var instances = targetSet.items[hash].instances;
for (var i = 0; i < instances.length; i++) {
var $c = $((isSelfInventory ? "#your_slots" : "#their_slots") + " #item753_6_" + instances[i]);
if ($c.length == 0) {
targets.push(instances[i]);
break;
}
if (i == instances.length - 1) {
alert("Cards aren't enough to add complete set");
return;
}
}
}
for (var n = 0; n < targets.length; n++) {
MoveItemToTrade($("#item753_6_" + targets[n])[0]);
}
});
}
function onErrorBadgeInformation(xhr) {
console.log("Couldn't get badge information. You need to log in to steamcardexchange.net.");
}
for (var instanceid in rgInventory) {
var item = rgInventory[instanceid];
// Check whether item type is card
var isCard = false;
for (var i = 0; i < item.tags.length; i++) {
if (item.tags[i].category == "item_class") {
// item_class_2 is type of trading card
if (item.tags[i].internal_name == "item_class_2") {
isCard = true;
}
break;
}
}
if (!isCard) continue;
if (!sets[item.market_fee_app]) {
sets[item.market_fee_app] = {
appId: item.market_fee_app,
cardsInSet: -1,
items: {}
};
}
if (!sets[item.market_fee_app].items[item.market_hash_name]) {
sets[item.market_fee_app].items[item.market_hash_name] = {
hash: item.market_hash_name,
quantity: 1,
instances: [instanceid],
};
} else {
sets[item.market_fee_app].items[item.market_hash_name].quantity++;
sets[item.market_fee_app].items[item.market_hash_name].instances.push(instanceid);
}
}
console.log(sets);
try {
var cache = JSON.parse(localStorage[CacheKey]);
} catch (error) {
cache = null;
}
if (cache) {
onLoadBadgeInformation(null, cache);
} else {
GM.xmlHttpRequest({
url: getBadgeInfoUrl,
method: "GET",
onerror: onErrorBadgeInformation,
onload: onLoadBadgeInformation
});
}
}
var $controllerContainer = $("<div />").appendTo("#inventory_box");;
$("<button />")
.append("<span>List card sets</span>")
.addClass("btn_darkblue_white_innerfade btn_small new_trade_offer_btn")
.css({ margin: "10px 12px" })
.click(function () {
try {
var inv = getSteamInventory();
main(inv);
} catch (error) {
alert(error);
}
})
.appendTo($controllerContainer);
$("<button />")
.append("<span>Clear badge cache</span>")
.addClass("btn_darkblue_white_innerfade btn_small new_trade_offer_btn")
.css({ margin: "10px 12px" })
.click(function () {
delete localStorage[CacheKey];
})
.appendTo($controllerContainer);
$("<input />").attr({ type: "checkbox", id: "DisplayExtraOnlyCheckbox" }).appendTo($controllerContainer);
$("<label />").attr({ for: "DisplayExtraOnlyCheckbox" }).text("Extra/Necessary only").appendTo($controllerContainer);
$("<style />").text(function () {/*
#SetListContainer .SetListText,
#SetListContainer .SetListMarkdown,
#SetListContainer .SetListHtml {
display: none;
}
#SetListContainer.VisibleText .SetListText,
#SetListContainer.VisibleMarkdown .SetListMarkdown,
#SetListContainer.VisibleHtml .SetListHtml {
display: block;
}
#SetListContainer {
position: fixed;
z-index: 10000;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: #000000dd;
overflow-y: scroll;
padding: 24px 40px;
}
#SetListContainer > div {
margin-bottom: 24px;
}
.SwitchSetList {
margin-right: 8px;
}
*/}.toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1]).appendTo("head");
// Your code here...
// .toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1];
})();