Inventory Market Value

A userscript

目前为 2025-04-05 提交的版本。查看 最新版本

// ==UserScript==
// @name        Inventory Market Value
// @license     MIT
// @namespace   Violentmonkey Scripts
// @match       https://www.torn.com/item*
// @grant       none
// @version     1.00
// @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 {
      const call = await fetch(`https://api.torn.com/v2/torn/items`, {
        method: 'GET',
        contentType: 'application/json',
        muteHttpExceptions: true,
        headers: {
          Authorization: `ApiKey ${apikey}`,
        },
      });

      if (!call.ok) {
        throw new Error(`API request failed with status: ${call.status}`);
      }

      jsonResponse = await call.json();
      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));
      }
    }
  }

  console.error('Failed to fetch data after 3 attempts.');

  return null;
}

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)} | ${formatToCurrency(market_price * itemQuantity)})`

      counter++
    }
  }

  return counter
}

const callback = async (mutationList, observer) => {
  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()
    }
  }
}

window.addEventListener('load', async ()=>{
  document.querySelectorAll('.items-cont').forEach(container=>{
    const observer = new MutationObserver(callback)

    observer.observe(container, { attributes: true, childList: true, subtree: true })
  })
})