Inventory Market Value

A userscript

  1. // ==UserScript==
  2. // @name Inventory Market Value
  3. // @license MIT
  4. // @namespace Violentmonkey Scripts
  5. // @match https://www.torn.com/item*
  6. // @grant none
  7. // @version 1.05
  8. // @author BillyBourbon/Bilbosaggings[2323763]
  9. // @description A userscript
  10. // ==/UserScript==
  11.  
  12. // ================================
  13. // Input your apikey inbetween the quote marks ""
  14. const apikey = "";
  15. // ================================
  16. (() => {
  17. function formatToCurrency(n) {
  18. n = Number(n);
  19. return new Intl.NumberFormat("en-US", {
  20. style: "currency",
  21. currency: "USD",
  22. minimumFractionDigits: 0,
  23. maximumFractionDigits: 0
  24. }).format(n);
  25. }
  26.  
  27. async function loadTornItems() {
  28. const cacheKey = "tornItemsCache";
  29. const cacheExpiryKey = "tornItemsCacheExpiry";
  30. const cacheDuration = 60 * 60 * 1000; // 1 hour in milliseconds
  31.  
  32. const cachedData = localStorage.getItem(cacheKey);
  33. const cachedExpiry = localStorage.getItem(cacheExpiryKey);
  34.  
  35. if (cachedData && cachedExpiry && Date.now() < cachedExpiry) {
  36. console.log("Using cached data");
  37. return JSON.parse(cachedData);
  38. }
  39.  
  40. let attempt = 0;
  41. let jsonResponse = null;
  42.  
  43. while (attempt < 3) {
  44. try {
  45. jsonResponse = await new Promise((resolve, reject) => {
  46. GM_xmlhttpRequest({
  47. method: "GET",
  48. url: `https://api.torn.com/v2/torn/items`,
  49. headers: {
  50. "Authorization": `ApiKey ${apikey}`,
  51. },
  52. onload: function (response) {
  53. if (response.status >= 200 && response.status < 300) {
  54. try {
  55. const responseData = JSON.parse(response.responseText);
  56. resolve(responseData);
  57. } catch (error) {
  58. reject(new Error("Failed to parse JSON"));
  59. }
  60. } else {
  61. reject(new Error(`API request failed with status: ${response.status}`));
  62. }
  63. },
  64. onerror: function (error) {
  65. reject(new Error(`API request failed with error: ${error}`));
  66. }
  67. });
  68. });
  69.  
  70. console.log(jsonResponse);
  71.  
  72. localStorage.setItem(cacheKey, JSON.stringify(jsonResponse));
  73. localStorage.setItem(cacheExpiryKey, Date.now() + cacheDuration);
  74.  
  75. return jsonResponse;
  76. } catch (error) {
  77. attempt++;
  78. console.error(`Attempt ${attempt} failed: ${error.message}`);
  79.  
  80. if (attempt < 3) {
  81. await new Promise(resolve => setTimeout(resolve, 2000)); // Delay before retrying
  82. }
  83. }
  84. }
  85. }
  86.  
  87. function findTornItem(itemId, tornItems) {
  88. const item = tornItems.find(o => o.id.toString() === itemId.toString());
  89.  
  90. return item;
  91. }
  92.  
  93.  
  94. async function insertMarketValues(itemList) {
  95. let counter = 0;
  96.  
  97. const {
  98. items: tornItems
  99. } = await loadTornItems();
  100.  
  101. for (let child of itemList.querySelectorAll("li")) {
  102. const itemId = child.getAttribute("data-item");
  103. if (itemId !== null && itemId > 0 && child.querySelector(".name-wrap .name") !== null) {
  104. const itemNameSpan = child.querySelector(".name-wrap .name");
  105. const itemQuantitySpan = child.querySelector(".name-wrap .qty");
  106. const itemQuantity = itemQuantitySpan.innerHTML.length === 0 ? 1 : Number(itemQuantitySpan.innerHTML.substring(1));
  107. const {
  108. value: {
  109. market_price
  110. }
  111. } = findTornItem(itemId, tornItems);
  112. itemNameSpan.innerHTML += ` (${formatToCurrency(market_price * itemQuantity)})`;
  113.  
  114. counter++;
  115. }
  116. }
  117.  
  118. return counter;
  119. }
  120.  
  121. const callback = async (mutationList, observer) => {
  122. console.log("mutation observed");
  123. for (const mutation of mutationList) {
  124. if (mutation.type === "childList") {
  125. if (mutation.addedNodes.length === 0) return;
  126. const editedElementCount = await insertMarketValues(mutation.target);
  127.  
  128. if (editedElementCount > 0) observer.disconnect();
  129. }
  130. }
  131. }
  132.  
  133. document.querySelectorAll(".items-cont").forEach(container => {
  134. const observer = new MutationObserver(callback);
  135. observer.observe(container, {
  136. attributes: true,
  137. childList: true,
  138. subtree: true
  139. });
  140. })
  141. })()