diff --git a/README.md b/README.md
index 62b3d61..57028c6 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,3 @@
# BackpackDecalSpotter
-Finds decaled items on Backpack.tf
\ No newline at end of file
+Finds decaled items on Backpack.tf. Relies on legacy soon-to-be-deprecated endpoints. Should be hosted to avoid "Access to Image from origin 'null' has been blocked by CORS policy" errors when fetching accounts with decaled item listings.
\ No newline at end of file
diff --git a/favicon.ico b/favicon.ico
new file mode 100644
index 0000000..8acd187
Binary files /dev/null and b/favicon.ico differ
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..dff5e64
--- /dev/null
+++ b/index.html
@@ -0,0 +1,20 @@
+
+
+
+ Backpack Decal Spotter
+
+
+
+
+
+
+
+
+
+
+
+ No decaled items from
+
+
+
\ No newline at end of file
diff --git a/script.js b/script.js
new file mode 100644
index 0000000..f19ac14
--- /dev/null
+++ b/script.js
@@ -0,0 +1,117 @@
+var checkable_accounts = { '76561198311319887': 'Weapon Crusher' };
+decaled_objects = { 'Conscientious Objector': '3.66', 'Clan Pride': '2.11', 'Flair!': '4.22', 'Photo Badge': '2.44' }
+backpack_page_limit = 3;
+
+function fetchAccounts() {
+ var deferred = new $.Deferred();
+ for (const [item, price] of Object.entries(decaled_objects)) {
+ handleItem(item, price);
+ }
+ deferred.resolve(checkable_accounts);
+ return deferred.promise()
+}
+
+function handleItem(item, price) {
+ for (let i = 1; i <= backpack_page_limit; i++) {
+ $.ajax({
+ dataType: 'html',
+ url: 'https://backpack.tf/classifieds',
+ data: 'page=' + i + '&item=' + encodeURIComponent(item) + '&quality=6&tradable=1&craftable=1&australium=-1&killstreak_tier=0&numeric=price&comparison=lt&value=' + price + '&low=' + price,
+ async: false,
+ tryCount: 0,
+ retryLimit: 3,
+ success: function (msg) {
+ if ($('.col-md-6:first .alert', msg).length > 0) {
+ return false;
+ }
+ $('.col-md-6:first .user-link', msg).each(function () {
+ checkable_accounts[$(this).attr('data-id')] = $(this).attr('data-name');
+ });
+ },
+ error: function (response, status, error) {
+ if (response.status == 429) {
+ this.tryCount++;
+ if (this.tryCount <= this.retryLimit) {
+ setTimeout(() => {
+ $.ajax(this);
+ }, 3000);
+ return;
+ }
+ }
+ }
+ });
+ }
+}
+
+function handleAccounts() {
+ for (const [steamid64, name] of Object.entries(checkable_accounts)) {
+ handleAccount(steamid64, name);
+ }
+}
+
+function handleAccount(steamid64, name) {
+ var url = "https://backpack.tf/_inventory/" + steamid64;
+ $.ajax({
+ dataType: 'json',
+ url: url,
+ async: false,
+ tryCount: 0,
+ retryLimit: 3,
+ success: function (msg) { handleHTML(steamid64, name, msg['html']); },
+ error: function (response, status, error) {
+ if (response.status == 429) {
+ this.tryCount++;
+ if (this.tryCount <= this.retryLimit) {
+ setTimeout(() => {
+ $.ajax(this);
+ }, 3000);
+ return;
+ }
+ }
+ }
+ });
+}
+
+function handleHTML(steamid64, name, html_string) {
+ html = $.parseHTML(html_string);
+ var decaled_items = $('div.decal', html);
+ if (decaled_items.length == 0) {
+ var empty_accounts = $('#empty-accounts');
+ empty_accounts.append('' + name + ' ; ');
+ empty_accounts.fadeIn();
+ return false;
+ }
+ var inventory = $('
');
+ inventory.append('' + name + ' ');
+ decaled_items.each(function () {
+ var url = "https://next.backpack.tf/item/" + $(this).parent().attr('data-id');
+ var a = $(' ');
+ a.append($(this).parent());
+ inventory.append(a);
+ });
+ var inventories = $('.inventory');
+ if (inventories.length > 0) {
+ var child_count = inventory.children().length;
+ inventory.attr('data-items', child_count);
+ var last_div = null;
+ inventories.each(function () {
+ if (child_count > $(this).children().length) {
+ return false;
+ }
+ last_div = $(this);
+ });
+ if (last_div) {
+ last_div.after(inventory);
+ } else {
+ $('body').prepend(inventory);
+ }
+ } else {
+ $('#empty-accounts').before(inventory);
+ }
+}
+
+$(document).ready(function () {
+ $.when(fetchAccounts()).done(function () {
+ handleAccounts();
+ });
+});
\ No newline at end of file
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..f3c8bee
--- /dev/null
+++ b/style.css
@@ -0,0 +1,119 @@
+body {
+ background-color: #111;
+ color: #eee;
+ font-family: Verdana, Geneva, sans-serif;
+ font-size: 0.85em;
+ margin: 0px;
+ text-align: justify;
+ text-justify: inter-word;
+ word-wrap: break-word;
+ word-break: break-all;
+ white-space: normal;
+ text-align: center;
+}
+
+div {
+ display: inline-block;
+}
+
+h3 {
+ text-align: center;
+ padding: 0.5em;
+}
+
+h4 {
+ color: #555;
+ text-align: center;
+ padding: 5em;
+}
+
+li {
+ display: inline-block;
+ width: 140px;
+ height: 140px;
+ position: relative;
+ border-radius: 3px;
+ margin: 10px;
+ border: 3px solid;
+ margin-bottom: 38px;
+}
+
+.decal {
+ width: 128px;
+ height: 128px;
+ margin: auto;
+ z-index: 2;
+ position: absolute;
+ top: 6px;
+ left: 6px;
+}
+
+.item-icon {
+ width: 24px;
+ height: 24px;
+ bottom: -38px;
+ left: -3px;
+ background-size: 24px;
+ z-index: 1;
+ position: absolute;
+ border-radius: 3px;
+ border: 3px solid;
+}
+
+.q-440-6,
+.q-440-6 .item-icon,
+.q-440-6 .bottom-right {
+ background-color: rgb(119, 101, 3);
+ border-color: rgb(181, 154, 5);
+}
+
+.q-440-11,
+.q-440-11 .item-icon ,
+.q-440-11 .bottom-right {
+ background-color: rgb(110, 56, 26);
+ border-color: rgb(144, 73, 34);
+}
+
+.nocraft {
+ border-style: dashed;
+}
+
+.top-left {
+ display: none;
+}
+
+.bottom-right {
+ position: absolute;
+ width: 105px;
+ height: 24px;
+ bottom: -38px;
+ left: 32px;
+ border-radius: 3px;
+ border: 3px solid;
+ margin: auto;
+}
+
+.bottom-right span {
+ text-align: center;
+ display: block;
+ margin-top: 3px;
+}
+
+a,
+a:link,
+a:visited,
+a:hover,
+a:active {
+ text-decoration: none;
+ color: #eee;
+}
+
+h4 a,
+h4 a:link,
+h4 a:visited,
+h4 a:hover,
+h4 a:active {
+ text-decoration: none;
+ color: #555;
+ font-style: italic;
+}
\ No newline at end of file