Display case market value

Display the total market value of items in a display case

// ==UserScript==
// @name        Display case market value
// @namespace   Violentmonkey Scripts
// @match       https://www.torn.com/displaycase.php*
// @grant       GM_xmlhttpRequest
// @version     1.0
// @license     MIT
// @author      BillyBourbon/Bilbosaggings[2323763]
// @description Display the total market value of items in a display case
// ==/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;
	}

	// Wait for the display case container to load
	while (document.querySelector(".display-cabinet") === null) {
		await new Promise(resolve => setTimeout(resolve, 500)); // Delay before retrying
	}

	// Select the display case container
	const displayCaseContainer = document.querySelector(".display-cabinet");

	// Load the Torn items
	const { items: tornItems } = await loadTornItems();

	// Iterate through each item in the display case
	displayCaseContainer.querySelectorAll("li").forEach(li => {
		const temp = li.querySelector(".item-hover");

		if (temp === null) 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);

		// Find the item from the loaded Torn items
		const item = findTornItem(itemId, tornItems);

		// Check if item was found
		if (item && item.value && item.value.market_price) {
			const marketPrice = item.value.market_price;

			// Calculate total market value
			ammountField.innerHTML += `(${formatToCurrency(ammount * marketPrice)})`;
		} else {
			console.error(`Item with ID ${itemId} not found or missing market price.`);
		}
	});
})();