您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
View anyone's bazaar from hospital, jail or travelling!
// ==UserScript== // @name View Bazaar Anytime // @namespace heartflower.torn.com // @version 1.1 // @description View anyone's bazaar from hospital, jail or travelling! // @author Heartflower [2626587] // @match https://www.torn.com/bazaar.php* // @icon https://www.google.com/s2/favicons?sz=64&domain=torn.com // ==/UserScript== (function() { 'use strict'; // Set to 'true' if you want to show a link to remove your API key let removeKeyLink = true; // Change maximum calls you want to do here. If it says 40, but those 40 items have an UID, it'll actually be 80 calls. let maximumCalls = 40; let apiCallCount = 0; let itemIDs = []; let itemUIDs = []; let userName = ''; let userID = ''; let apiKey = ''; let storedAPIKey = localStorage.getItem('hf-public-apiKey'); if (storedAPIKey) { apiKey = storedAPIKey; } function checkElement() { let contentWrapper = document.querySelector('.content-wrapper'); if (contentWrapper) { let messageContent = document.querySelector('.msg.right-round'); let originalText = messageContent.textContent; if (messageContent && messageContent.textContent.includes('This area is unavailable')) { if (userName == '') { userName = 'Unknown'; } let newText = `${userName}'s bazaar is fetched by the "View Bazaar Anytime" script" with the help of the API!`; messageContent.textContent = newText; if (apiKey !== '') { fetchBazaarData(); if (removeKeyLink === true) { let link = document.createElement('a'); link.href = '#'; // Set a placeholder href link.textContent = ' Click here to remove your (public) API key!'; // Add click event listener to the link link.addEventListener('click', function(event) { event.preventDefault(); // Prevent the default link behavior localStorage.removeItem('hf-public-apiKey'); alert('API key successfully removed!'); link.remove(); let enterLink = document.createElement('a'); enterLink.href = '#'; // Set a placeholder href enterLink.textContent = ' Click here to enter your (public) API key!'; // Add click event listener to the link enterLink.addEventListener('click', function(event) { event.preventDefault(); // Prevent the default link behavior promptAPIKey(); link.remove(); }); messageContent.appendChild(enterLink); }); messageContent.appendChild(link); } } else { let link = document.createElement('a'); link.href = '#'; // Set a placeholder href link.textContent = ' Click here to enter your (public) API key!'; // Add click event listener to the link link.addEventListener('click', function(event) { event.preventDefault(); // Prevent the default link behavior promptAPIKey(); }); messageContent.appendChild(link); } } } } function promptAPIKey() { let enterAPIKey = prompt('Enter a public API key here:'); if (enterAPIKey !== null && enterAPIKey.trim() !== '') { localStorage.setItem('hf-public-apiKey', enterAPIKey); alert('API key set succesfully'); fetchBazaarData(); } else { alert('No valid API key entered!'); } } function checkUserID() { let url = new URL(window.location.href); userID = url.searchParams.get('userId'); let apiUrl = `https://api.torn.com/user/${userID}?key=${apiKey}&selections=basic&comment=ViewBazaarAnytime`; fetch(apiUrl) .then(response => response.json()) .then(data => { userName = data.name; console.log(userName); }) .catch(error => console.error('Error fetching data: ' + error)); } function createTable (data) { let contentWrapper = document.querySelector('.content-wrapper'); let tableDiv = document.createElement('div'); tableDiv.style.paddingTop = '16px'; let table = document.createElement('table'); table.style.margin = '0 auto'; table.style.background = 'var(--default-bg-panel-color)'; table.style.width = '100%'; let thead = document.createElement('thead'); let tbody = document.createElement('tbody'); tbody.style.borderRadius = '5px'; // Create table headers let headers = ['Image', 'Name', 'Bonus', 'Stock', 'Price each', 'Price total', 'Lowest price in other bazaars']; let headerRow = document.createElement('tr'); headers.forEach(function(header) { let th = document.createElement('th'); th.style.padding = '4px'; th.textContent = header; th.style.background = 'var(--tabs-active-bg-gradient)'; th.style.color = 'var(--default-color)'; th.style.fontWeight = 'bold'; th.style.textAlign = 'center'; th.style.padding = '8px 4px'; th.style.borderBottom = '1px solid grey'; th.style.borderBottomColor = 'var(--default-panel-divider-outer-side-color)'; headerRow.appendChild(th); }); thead.appendChild(headerRow); table.appendChild(thead); // Create table body data.forEach(function(item, index) { let row = document.createElement('tr'); row.style.borderBottom = '1px solid grey'; row.style.borderBottomColor = 'var(--default-panel-divider-outer-side-color)'; let itemID = item.ID; let itemUID = item.UID; let bonusText = ''; if (itemUID) { itemUIDs.push({ uid: itemUID, index: index}); bonusText = 'Loading...'; } // Store itemID with index itemIDs.push({ id: itemID, index: index}); createCell('Image', row, itemID); createCell(item.name, row); createCell(bonusText, row); createCell(item.quantity, row); createCell(item.price.toLocaleString('en-US', {style: 'currency', currency: 'USD', maximumFractiondigits: 0, minimumFractionDigits: 0}), row); createCell((item.quantity * item.price).toLocaleString('en-US', {style: 'currency', currency: 'USD', maximumFractiondigits: 0, minimumFractionDigits: 0}), row); createCell('Loading...', row); tbody.appendChild(row); }); table.appendChild(tbody); tableDiv.appendChild(table); contentWrapper.appendChild(tableDiv); fetchMarketDataForItems(); fetchItemDetailsForUIDs(); } function createCell(text, row, itemID) { let cell = document.createElement('td'); if (text == 'Image') { let img = document.createElement('img'); img = document.createElement('img'); img.src = `/images/items/${itemID}/large.png`; img.srcset = `/images/items/${itemID}/large.png 1x, /images/items/${itemID}/[email protected] 2x, /images/items/${itemID}/[email protected] 3x, /images/items/${itemID}/[email protected] 4x`; img.alt = 'Item Image'; img.style.height = '25px'; cell.appendChild(img); } else { cell.textContent = text; } cell.style.color = 'var(--default-color)'; cell.style.textAlign = 'center'; cell.style.verticalAlign = 'middle'; cell.style.padding = '4px'; row.appendChild(cell); } function fetchBazaarData() { let apiUrl = `https://api.torn.com/user/${userID}?key=${apiKey}&selections=bazaar&comment=ViewBazaarAnytime`; fetch(apiUrl) .then(response => response.json()) .then(data => { createTable(data.bazaar); apiCallCount++; }) .catch(error => console.error('Error fetching data: ' + error)); } function fetchMarketDataForItems() { let itemsToFetch = Math.min(maximumCalls, itemIDs.length); for (let i = 0; i < itemsToFetch; i++) { let { id, index } = itemIDs[i]; fetchMarketData(id, index); } if (itemIDs.length > maximumCalls) { setTimeout(function () { fetchMarketDataForItems(); }, 60000); } } function fetchMarketData(itemID, index) { let apiUrl = `https://api.torn.com/market/${itemID}?selections=bazaar&key=${apiKey}&comment=ViewBazaarAnytime`; // Make the API call fetch(apiUrl) .then(response => response.json()) .then(data => { if (data.bazaar && data.bazaar.length > 0) { let lowestPrice = data.bazaar[0].cost; // Update table with lowest bazaar price let table = document.querySelector('table'); let cell = table.rows[index + 1].cells[6]; cell.textContent = lowestPrice.toLocaleString('en-US', {style: 'currency', currency: 'USD', maximumFractiondigits: 0, minimumFractionDigits: 0}); // Remove from itemIDs itemIDs = itemIDs.filter(item => item.id !== itemID); } else { throw new Error('No items found in the bazaar'); } }) .catch(error => console.error('Error fetching data: ' + error)); } function fetchItemDetailsForUIDs() { console.log('Fetching all item details'); let itemsToFetch = Math.min(maximumCalls, itemUIDs.length); for (let i = 0; i < itemsToFetch; i++) { let { uid, index } = itemUIDs[i]; fetchItemDetails(uid, index); } if (itemIDs.length > maximumCalls) { setTimeout(function () { fetchItemDetailsForUIDs(); }, 60000); } } function fetchItemDetails(itemUID, index) { console.log('Fetching item details'); let apiUrl = `https://api.torn.com/torn/${itemUID}?selections=itemdetails&key=${apiKey}&comment=ViewBazaarAnytime`; console.log(apiUrl); // Make the API call fetch(apiUrl) .then(response => response.json()) .then(data => { if (data.itemdetails) { let rarity = data.itemdetails.rarity; if (rarity == 'None') { rarity = ''; } let quality = data.itemdetails.quality; let bonuses = data.itemdetails.bonuses; let bonusText = ''; if (bonuses) { if (Object.keys(bonuses).length === 1) { // If there is only one bonus let bonus = bonuses[Object.keys(bonuses)[0]]; bonusText = `<p style="padding:4px">${bonus.value}% ${bonus.bonus}</p>`; } else if (Object.keys(bonuses).length === 2) { // If there are two bonuses Object.keys(bonuses).forEach(key => { let bonus = bonuses[key]; bonusText += `<p style="padding:4px">${bonus.value}% ${bonus.bonus}</p>`; }); } } // Update table with bonus text let table = document.querySelector('table'); let cell = table.rows[index + 1].cells[2]; cell.innerHTML = `<p style="padding:4px">${rarity}<p>${quality} Quality</p>${bonusText}`; // Remove from itemUIDs itemUIDs = itemUIDs.filter(item => item.uid !== itemUID); } else { throw new Error('No item details found'); } }) .catch(error => console.error('Error fetching data: ' + error)); } checkUserID(); setTimeout(checkElement, 300); })();