// ==UserScript== // @name Bazaars in Item Market 2.0 // @namespace http://tampermonkey.net/ // @version 0.1 // @description Displays bazaar listings with sorting controls via TornPal // @author Weav3r [1853324] // @match https://www.torn.com/page.php?sid=ItemMarket* // @grant GM_xmlhttpRequest // @connect tornpal.com // @run-at document-end // @downloadURL none // ==/UserScript== (function() { 'use strict'; // Cache duration: 60 seconds const CACHE_DURATION_MS = 60000; // Global sort settings let currentSortKey = "price"; // "price", "quantity", or "updated" let currentSortOrder = "asc"; // "asc" or "desc" // Helpers: caching function getCache(itemId) { try { const key = "tornBazaarCache_" + itemId; const cached = localStorage.getItem(key); if (cached) { const payload = JSON.parse(cached); if (Date.now() - payload.timestamp < CACHE_DURATION_MS) { return payload.data; } } } catch(e) { } return null; } function setCache(itemId, data) { try { const key = "tornBazaarCache_" + itemId; const payload = { timestamp: Date.now(), data: data }; localStorage.setItem(key, JSON.stringify(payload)); } catch(e) { // intentionally left blank } } // Helper: relative time function getRelativeTime(timestampSeconds) { const now = Date.now(); const diffSec = Math.floor((now - timestampSeconds * 1000) / 1000); if (diffSec < 60) return diffSec + 's ago'; if (diffSec < 3600) return Math.floor(diffSec / 60) + 'm ago'; if (diffSec < 86400) return Math.floor(diffSec / 3600) + 'h ago'; return Math.floor(diffSec / 86400) + 'd ago'; } // Creates the info container function createInfoContainer(itemName, itemId) { const container = document.createElement('div'); container.id = 'item-info-container'; container.setAttribute('data-itemid', itemId); container.style.backgroundColor = '#2f2f2f'; container.style.color = '#ccc'; container.style.fontSize = '13px'; container.style.border = '1px solid #444'; container.style.borderRadius = '4px'; container.style.margin = '5px 0'; container.style.padding = '10px'; container.style.display = 'flex'; container.style.flexDirection = 'column'; container.style.gap = '8px'; // Header const header = document.createElement('div'); header.className = 'info-header'; header.style.fontSize = '16px'; header.style.fontWeight = 'bold'; header.style.color = '#fff'; header.textContent = `Item: ${itemName} (ID: ${itemId})`; container.appendChild(header); // Sort controls const sortControls = document.createElement('div'); sortControls.className = 'sort-controls'; sortControls.style.display = 'flex'; sortControls.style.alignItems = 'center'; sortControls.style.gap = '5px'; sortControls.style.fontSize = '12px'; sortControls.style.padding = '5px'; sortControls.style.backgroundColor = '#333'; sortControls.style.borderRadius = '4px'; const sortLabel = document.createElement('span'); sortLabel.textContent = "Sort by:"; sortControls.appendChild(sortLabel); const sortSelect = document.createElement('select'); sortSelect.style.padding = '2px'; sortSelect.style.border = '1px solid #444'; sortSelect.style.borderRadius = '2px'; sortSelect.style.backgroundColor = '#1a1a1a'; sortSelect.style.color = '#fff'; [ { value: "price", text: "Price" }, { value: "quantity", text: "Quantity" }, { value: "updated", text: "Last Updated" } ].forEach(opt => { const option = document.createElement('option'); option.value = opt.value; option.textContent = opt.text; sortSelect.appendChild(option); }); sortSelect.value = currentSortKey; sortControls.appendChild(sortSelect); const orderToggle = document.createElement('button'); orderToggle.style.padding = '2px 4px'; orderToggle.style.border = '1px solid #444'; orderToggle.style.borderRadius = '2px'; orderToggle.style.backgroundColor = '#1a1a1a'; orderToggle.style.color = '#fff'; orderToggle.style.cursor = 'pointer'; orderToggle.textContent = (currentSortOrder === "asc") ? "Asc" : "Desc"; sortControls.appendChild(orderToggle); container.appendChild(sortControls); // Scrollable listings row const scrollWrapper = document.createElement('div'); scrollWrapper.style.overflowX = 'auto'; scrollWrapper.style.overflowY = 'hidden'; scrollWrapper.style.height = '120px'; scrollWrapper.style.whiteSpace = 'nowrap'; scrollWrapper.style.paddingBottom = '3px'; const cardContainer = document.createElement('div'); cardContainer.className = 'card-container'; cardContainer.style.display = 'inline-flex'; cardContainer.style.flexWrap = 'nowrap'; cardContainer.style.gap = '10px'; scrollWrapper.appendChild(cardContainer); container.appendChild(scrollWrapper); // Sorting events sortSelect.addEventListener('change', () => { currentSortKey = sortSelect.value; if (container.filteredListings) { renderCards(container, container.filteredListings); } }); orderToggle.addEventListener('click', () => { currentSortOrder = (currentSortOrder === "asc") ? "desc" : "asc"; orderToggle.textContent = (currentSortOrder === "asc") ? "Asc" : "Desc"; if (container.filteredListings) { renderCards(container, container.filteredListings); } }); return container; } // Sort + render listing cards function renderCards(infoContainer, listings) { const sorted = listings.slice().sort((a, b) => { let diff = 0; if (currentSortKey === "price") diff = a.price - b.price; else if (currentSortKey === "quantity") diff = a.quantity - b.quantity; else if (currentSortKey === "updated") diff = a.updated - b.updated; return (currentSortOrder === "asc") ? diff : -diff; }); const cardContainer = infoContainer.querySelector('.card-container'); cardContainer.innerHTML = ''; sorted.forEach(listing => { const card = createListingCard(listing); cardContainer.appendChild(card); }); } // Create listing card function createListingCard(listing) { const card = document.createElement('div'); card.className = 'listing-card'; card.style.backgroundColor = '#1a1a1a'; card.style.color = '#fff'; card.style.border = '1px solid #444'; card.style.borderRadius = '4px'; card.style.padding = '8px'; card.style.minWidth = '200px'; card.style.fontSize = '14px'; card.style.display = 'inline-block'; card.style.boxSizing = 'border-box'; const playerLink = document.createElement('a'); playerLink.href = `https://www.torn.com/bazaar.php?userId=${listing.player_id}#/`; playerLink.target = '_blank'; playerLink.textContent = `Player: ${listing.player_id}`; playerLink.style.display = 'block'; playerLink.style.fontWeight = 'bold'; playerLink.style.color = '#00aaff'; playerLink.style.textDecoration = 'underline'; playerLink.style.marginBottom = '6px'; const details = document.createElement('div'); details.innerHTML = `