您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A userscript
// ==UserScript== // @name Inventory Market Value // @license MIT // @namespace Violentmonkey Scripts // @match https://www.torn.com/item* // @grant none // @version 1.05 // @author BillyBourbon/Bilbosaggings[2323763] // @description A userscript // ==/UserScript== // ================================ // Input your apikey inbetween the quote marks "" const apikey = ""; // ================================ (() => { function formatToCurrency(n) { n = Number(n); return new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", minimumFractionDigits: 0, maximumFractionDigits: 0 }).format(n); } async function loadTornItems() { const cacheKey = "tornItemsCache"; const cacheExpiryKey = "tornItemsCacheExpiry"; const cacheDuration = 60 * 60 * 1000; // 1 hour in milliseconds 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; 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); 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 findTornItem(itemId, tornItems) { const item = tornItems.find(o => o.id.toString() === itemId.toString()); return item; } 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(); } } } document.querySelectorAll(".items-cont").forEach(container => { const observer = new MutationObserver(callback); observer.observe(container, { attributes: true, childList: true, subtree: true }); }) })()