您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Combined script for Inventory and Display Case market value
// ==UserScript== // @name Torn Inventory & Display Case Market Value // @namespace Violentmonkey Scripts // @match https://www.torn.com/* // @grant GM_xmlhttpRequest // @version 1.0 // @license MIT // @author BillyBourbon/Bilbosaggings[2323763] // @description Combined script for Inventory and Display Case market value // ==/UserScript== // ================================ // Input your apikey in between the quote marks "" const apikey = ""; // ================================ (async () => { // Function to format numbers to currency format (USD) function formatToCurrency(n) { n = Number(n); return new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", minimumFractionDigits: 0, maximumFractionDigits: 0 }).format(n); } // Function to load Torn items with caching async function loadTornItems() { const cacheKey = "tornItemsCache"; const cacheExpiryKey = "tornItemsCacheExpiry"; const cacheDuration = 60 * 60 * 1000; // 1 hour in milliseconds // Check for cached data const cachedData = localStorage.getItem(cacheKey); const cachedExpiry = localStorage.getItem(cacheExpiryKey); if (cachedData && cachedExpiry && Date.now() < cachedExpiry) { console.log("Using cached data"); return JSON.parse(cachedData); } let attempt = 0; let jsonResponse = null; // Retry logic for API request while (attempt < 3) { try { jsonResponse = await new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "GET", url: `https://api.torn.com/v2/torn/items`, headers: { "Authorization": `ApiKey ${apikey}`, }, onload: function (response) { if (response.status >= 200 && response.status < 300) { try { const responseData = JSON.parse(response.responseText); resolve(responseData); } catch (error) { reject(new Error("Failed to parse JSON")); } } else { reject(new Error(`API request failed with status: ${response.status}`)); } }, onerror: function (error) { reject(new Error(`API request failed with error: ${error}`)); } }); }); console.log(jsonResponse); // Cache the API response localStorage.setItem(cacheKey, JSON.stringify(jsonResponse)); localStorage.setItem(cacheExpiryKey, Date.now() + cacheDuration); return jsonResponse; } catch (error) { attempt++; console.error(`Attempt ${attempt} failed: ${error.message}`); if (attempt < 3) { await new Promise(resolve => setTimeout(resolve, 2000)); // Delay before retrying } } } } // Function to find a Torn item by its ID function findTornItem(itemId, tornItems) { const item = tornItems.find(o => o.id.toString() === itemId.toString()); // Return null if item is not found return item || null; } // ======================== // Inventory Market Value // ======================== async function insertMarketValues(itemList) { let counter = 0; const { items: tornItems } = await loadTornItems(); for (let child of itemList.querySelectorAll("li")) { const itemId = child.getAttribute("data-item"); if (itemId !== null && itemId > 0 && child.querySelector(".name-wrap .name") !== null) { const itemNameSpan = child.querySelector(".name-wrap .name"); const itemQuantitySpan = child.querySelector(".name-wrap .qty"); const itemQuantity = itemQuantitySpan.innerHTML.length === 0 ? 1 : Number(itemQuantitySpan.innerHTML.substring(1)); const { value: { market_price } } = findTornItem(itemId, tornItems); itemNameSpan.innerHTML += ` (${formatToCurrency(market_price * itemQuantity)})`; counter++; } } return counter; } const callback = async (mutationList, observer) => { console.log("mutation observed"); for (const mutation of mutationList) { if (mutation.type === "childList") { if (mutation.addedNodes.length === 0) return; const editedElementCount = await insertMarketValues(mutation.target); if (editedElementCount > 0) observer.disconnect(); } } } // ======================== // Display Case Market Value // ======================== async function updateDisplayCaseMarketValue() { // Wait for display case page to load while (document.querySelector(".display-cabinet") === null) { await new Promise(resolve => setTimeout(resolve, 500)); // Delay before retrying } const displayCaseContainer = document.querySelector(".display-cabinet"); const { items: tornItems } = await loadTornItems(); displayCaseContainer.querySelectorAll("li").forEach(li => { const temp = li.querySelector(".item-hover"); if (temp === null || temp.getAttribute("data-userscript") === "true") return; // Skip if there's no item const itemId = temp.getAttribute("itemId"); const ammountField = li.querySelector(".b-item-amount"); const ammount = ammountField.innerHTML.trim().substring(1); const item = findTornItem(itemId, tornItems); // Check if item was found if (item && item.value && item.value.market_price) { const marketPrice = item.value.market_price; const totalValue = ammount * marketPrice if(totalValue > 0) ammountField.innerHTML += `(${formatToCurrency(totalValue)})`; } else { console.error(`Item with ID ${itemId} not found or missing market price.`); } temp.setAttribute("data-userscript", "true") }); } // ======================== // Main Logic // ======================== const currentUrl = window.location.href; if (currentUrl.includes("item.php")) { console.log("Updating Inventory Market Value..."); // Observe changes in the inventory page document.querySelectorAll(".items-cont").forEach(container => { const observer = new MutationObserver(callback); observer.observe(container, { attributes: true, childList: true, subtree: true }); }) } else if (currentUrl.includes("displaycase.php")) { console.log("Updating Display Case Market Value..."); await updateDisplayCaseMarketValue(); } })();