// ==UserScript== // @name Bazaars in Item Market Powered by TornW3B // @namespace http://tampermonkey.net/ // @version 3.0 // @description Displays bazaar listings with sorting controls // @author Weav3r // @match https://www.torn.com/page.php?sid=ItemMarket* // @match https://www.torn.com/bazaar.php* // @grant unsafeWindow // @grant GM_xmlhttpRequest // @grant GM_addStyle // @connect weav3r.dev // @require https://code.jquery.com/jquery-3.6.0.min.js // @run-at document-end // @downloadURL none // ==/UserScript== (function($) { 'use strict'; const PDA = { isDetected: false, handlers: {}, async detect() { try { if (window.flutter_inappwebview && window.flutter_inappwebview.callHandler) { const response = await window.flutter_inappwebview.callHandler('isTornPDA'); this.isDetected = response && response.isTornPDA; if (this.isDetected) { this.setupHandlers(); } } else if (navigator.userAgent && navigator.userAgent.includes('TornPDA')) { this.isDetected = true; this.setupHandlers(); } } catch (e) { this.isDetected = false; } return this.isDetected; }, setupHandlers() { this.handlers.httpGet = async (url, headers = {}) => { try { const response = await window.flutter_inappwebview.callHandler('PDA_httpGet', url, headers); return { responseText: response.responseText, status: response.status, statusText: response.statusText, responseHeaders: response.responseHeaders }; } catch (error) { throw new Error(`PDA HTTP GET failed: ${error}`); } }; this.handlers.httpPost = async (url, headers = {}, body = '') => { try { const response = await window.flutter_inappwebview.callHandler('PDA_httpPost', url, headers, body); return { responseText: response.responseText, status: response.status, statusText: response.statusText, responseHeaders: response.responseHeaders }; } catch (error) { throw new Error(`PDA HTTP POST failed: ${error}`); } }; this.handlers.evaluate = async (code) => { try { await window.flutter_inappwebview.callHandler('PDA_evaluateJavascript', code); } catch (error) { throw new Error(`PDA JS evaluation failed: ${error}`); } }; }, async httpRequest(options) { if (this.isDetected && options.method === 'GET') { const response = await this.handlers.httpGet(options.url, options.headers || {}); return { responseText: response.responseText, status: response.status, readyState: 4, response: response.responseText }; } else if (this.isDetected && options.method === 'POST') { const response = await this.handlers.httpPost(options.url, options.headers || {}, options.data || ''); return { responseText: response.responseText, status: response.status, readyState: 4, response: response.responseText }; } else { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ ...options, onload: resolve, onerror: reject }); }); } } }; PDA.detect(); const CONFIG = { CACHE_DURATION: 30000, ITEMS_PER_PAGE: 3, DEFAULT_SORT: 'price-asc', DEFAULT_MIN_QTY: 0, SHOW_MARKET_COMPARISON: true, BAZAAR_CLICK_BEHAVIOR: 'new-tab', SELECTORS: { DESKTOP_LIST: '.sellerListWrapper___PN32N .sellerList___kgAh_', MOBILE_LIST: '.sellerList___e4C9_', MOBILE_HEADER: '.itemsHeader___ZTO9r', MOBILE_ROW: '.rowWrapper___OrFGK' }, MOBILE_BREAKPOINT: 784 }; const loadSettings = () => { const saved = localStorage.getItem('bazaarListingsSettings'); if (saved) { try { const settings = JSON.parse(saved); return { ...CONFIG, ...settings }; } catch (e) { } } return CONFIG; }; const saveSettings = (settings) => { localStorage.setItem('bazaarListingsSettings', JSON.stringify(settings)); Object.assign(CONFIG, settings); }; Object.assign(CONFIG, loadSettings()); const state = { originalFetch: null, currentDisplay: null, apiCache: new Map(), currentItemID: null }; const injectStyles = () => { const styles = ` :root { --base-font-size: clamp(12px, 1vw, 14px); --small-font-size: clamp(11px, 0.9vw, 12px); --tiny-font-size: clamp(10px, 0.8vw, 11px); --large-font-size: clamp(13px, 1.1vw, 15px); --title-font-size: clamp(14px, 1.2vw, 16px); --spacing-xs: clamp(3px, 0.3vw, 3px); --spacing-sm: clamp(5px, 0.5vw, 6px); --spacing-md: clamp(8px, 0.8vw, 10px); --spacing-lg: clamp(12px, 1.2vw, 16px); --bazaar-bg: #f5f5f5; --bazaar-card-bg: white; --bazaar-card-border: #ddd; --bazaar-card-shadow: rgba(0,0,0,0.06); --bazaar-card-shadow-hover: rgba(0,0,0,0.10); --bazaar-text-primary: #222; --bazaar-text-secondary: #666; --bazaar-text-tertiary: #888; --bazaar-price-color: #0070e0; --bazaar-nav-bg: #333; --bazaar-nav-bg-hover: #555; --bazaar-nav-disabled: #ccc; --bazaar-border-light: #eee; --bazaar-input-border: #ddd; --bazaar-error-color: #cc0000; --bazaar-qty-color: #444; --bazaar-container-border: #d0d0d0; --bazaar-container-bg: rgba(248, 249, 250, 0.6); --bazaar-container-shadow: rgba(0,0,0,0.08); } body.dark-mode { --bazaar-bg: #1a1a1a; --bazaar-card-bg: #2a2a2a; --bazaar-card-border: #444; --bazaar-card-shadow: rgba(0,0,0,0.3); --bazaar-card-shadow-hover: rgba(0,0,0,0.5); --bazaar-text-primary: #e8e8e8; --bazaar-text-secondary: #aaa; --bazaar-text-tertiary: #888; --bazaar-price-color: #4da6ff; --bazaar-nav-bg: #444; --bazaar-nav-bg-hover: #666; --bazaar-nav-disabled: #333; --bazaar-border-light: #3a3a3a; --bazaar-input-border: #555; --bazaar-error-color: #ff6666; --bazaar-qty-color: #ccc; --bazaar-container-border: #555; --bazaar-container-bg: rgba(35, 35, 35, 0.8); --bazaar-container-shadow: rgba(0,0,0,0.4); } .bazaar-container { display: block; list-style: none; margin-bottom: var(--spacing-md); padding: clamp(12px, 1.5vw, 16px); border: 2px solid var(--bazaar-container-border); border-radius: clamp(6px, 1vw, 8px); background: var(--bazaar-container-bg); box-shadow: 0 2px 4px var(--bazaar-container-shadow); } .itemsHeader___ZTO9r + .bazaar-container { margin-top: var(--spacing-md); margin-bottom: var(--spacing-md); } .bazaar-controls { display: flex; gap: var(--spacing-sm); padding: var(--spacing-sm); background: var(--bazaar-bg); border-radius: clamp(3px, 0.5vw, 4px); margin-bottom: var(--spacing-md); align-items: center; border: 1px solid var(--bazaar-border-light); } .bazaar-filter { display: flex; align-items: center; gap: var(--spacing-xs); margin-right: var(--spacing-md); } .bazaar-filter label { font-size: var(--small-font-size); color: var(--bazaar-text-secondary); } .bazaar-filter input { width: clamp(55px, 8vw, 65px); padding: var(--spacing-xs) var(--spacing-sm); border: 1px solid var(--bazaar-input-border); border-radius: clamp(2px, 0.4vw, 3px); font-size: var(--small-font-size); background: var(--bazaar-card-bg); color: var(--bazaar-text-primary); } .bazaar-sort-buttons { display: flex; gap: var(--spacing-xs); align-items: center; } .bazaar-sort-label { font-size: var(--small-font-size); color: var(--bazaar-text-secondary); margin-right: var(--spacing-xs); } .bazaar-sort-btn { padding: var(--spacing-xs) var(--spacing-md); border: 1px solid var(--bazaar-input-border); background: var(--bazaar-card-bg); color: var(--bazaar-text-primary); border-radius: clamp(2px, 0.4vw, 3px); font-size: var(--small-font-size); cursor: pointer; transition: all 0.15s; white-space: nowrap; display: flex; align-items: center; gap: var(--spacing-xs); min-width: clamp(50px, 7vw, 55px); } .bazaar-sort-btn:hover { background: var(--bazaar-bg); } .bazaar-sort-btn[data-state="asc"], .bazaar-sort-btn[data-state="desc"] { background: var(--bazaar-nav-bg); color: white; border-color: var(--bazaar-nav-bg); } .bazaar-sort-btn[data-state="asc"]:hover, .bazaar-sort-btn[data-state="desc"]:hover { background: var(--bazaar-nav-bg-hover); border-color: var(--bazaar-nav-bg-hover); } .sort-arrow { font-size: var(--tiny-font-size); opacity: 0.8; } /* Touch indicator for mobile */ @media (pointer: coarse) { .bazaar-display::after { content: ''; position: absolute; bottom: -20px; left: 50%; transform: translateX(-50%); width: 40px; height: 4px; background: var(--bazaar-nav-disabled); border-radius: 2px; opacity: 0.5; transition: opacity 0.3s; } .bazaar-container:hover .bazaar-display::after { opacity: 0.8; } } @media (max-width: 784px) { :root { --base-font-size: clamp(12px, 2vw, 13px); --small-font-size: clamp(11px, 1.7vw, 12px); --tiny-font-size: clamp(10px, 1.5vw, 11px); --large-font-size: clamp(13px, 2vw, 14px); --title-font-size: clamp(14px, 2.2vw, 15px); } .bazaar-container { margin: var(--spacing-sm) 0; padding: max(var(--spacing-md), 12px); } .bazaar-controls { flex-direction: column; gap: var(--spacing-md); padding: var(--spacing-sm); } .bazaar-filter { width: auto; max-width: fit-content; justify-content: flex-start; align-items: baseline; gap: var(--spacing-xs); margin-right: var(--spacing-md); } .bazaar-filter input { margin-right: 0; } .bazaar-sort-buttons { width: 100%; justify-content: space-between; gap: var(--spacing-xs); } .bazaar-sort-label { display: none; } .bazaar-sort-btn { flex: 1; padding: var(--spacing-sm) var(--spacing-sm); min-width: auto; } .bazaar-display { margin-top: var(--spacing-sm); } .bazaar-nav { width: clamp(24px, 4vw, 28px); min-height: clamp(40px, 8vw, 50px); font-size: clamp(14px, 3vw, 18px); border-radius: clamp(5px, 1.2vw, 8px); } .bazaar-cards-wrapper { gap: var(--spacing-xs); } .bazaar-cards-wrapper.multi-row { grid-template-columns: repeat(2, 1fr); gap: var(--spacing-xs); } .bazaar-card { padding: var(--spacing-sm) var(--spacing-sm); } .bazaar-card-info { align-items: center; margin-bottom: var(--spacing-xs); } .bazaar-card-price, .bazaar-card-qty { width: 100%; text-align: center; } .bazaar-card-name { text-align: center; margin-bottom: var(--spacing-sm); } .bazaar-card-bottom { padding-top: var(--spacing-xs); } .rowWrapper___OrFGK .bazaar-container { height: auto !important; opacity: 1 !important; transform: none !important; position: relative; } div.bazaar-container { width: 100%; box-sizing: border-box; } } .bazaar-display { display: grid; grid-template-columns: clamp(26px, 3vw, 30px) 1fr clamp(26px, 3vw, 30px); align-items: stretch; width: 100%; max-width: 100%; overflow: hidden; box-sizing: border-box; background: none; padding: var(--spacing-sm); gap: var(--spacing-sm); position: relative; touch-action: pan-y; } .bazaar-nav { grid-row: 1; z-index: 2; opacity: 0.9; background: var(--bazaar-nav-bg); color: white; border: none; border-radius: clamp(6px, 1vw, 10px); width: 100%; height: 100%; min-height: clamp(50px, 6vw, 55px); cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: clamp(14px, 2.5vw, 20px); transition: background 0.2s; padding: 0; } .bazaar-nav.prev { grid-column: 1; justify-self: stretch; } .bazaar-nav.next { grid-column: 3; justify-self: stretch; } .bazaar-nav:hover:not(:disabled) { background: var(--bazaar-nav-bg-hover); opacity: 1; } .bazaar-nav:disabled { background: var(--bazaar-nav-disabled); cursor: not-allowed; opacity: 0.6; } .bazaar-pagination-info { display: flex; align-items: center; justify-content: center; gap: var(--spacing-md); margin-top: var(--spacing-sm); margin-bottom: var(--spacing-sm); font-size: var(--small-font-size); color: var(--bazaar-text-secondary); } .bazaar-nav-first, .bazaar-nav-last { background: var(--bazaar-nav-bg); color: white; border: none; border-radius: clamp(3px, 0.5vw, 4px); padding: var(--spacing-xs) var(--spacing-md); cursor: pointer; font-size: var(--small-font-size); transition: all 0.2s; opacity: 0.9; } .bazaar-nav-first:hover:not(:disabled), .bazaar-nav-last:hover:not(:disabled) { background: var(--bazaar-nav-bg-hover); opacity: 1; } .bazaar-nav-first:disabled, .bazaar-nav-last:disabled { background: var(--bazaar-nav-disabled); cursor: not-allowed; opacity: 0.6; } .bazaar-page-info { font-weight: 500; } .current-page, .total-pages { font-weight: bold; color: var(--bazaar-text-primary); } .bazaar-cards-wrapper { grid-column: 2; display: flex; flex-wrap: wrap; width: 100%; gap: var(--spacing-xs); justify-content: center; align-items: stretch; box-sizing: border-box; margin: 0; padding: 0; transition: transform 0.2s ease-out; } .bazaar-display.swiping .bazaar-cards-wrapper { transition: none; } .bazaar-cards-wrapper.multi-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--spacing-sm); } .bazaar-cards-wrapper.multi-row .bazaar-card { max-width: none; width: 100%; } .bazaar-error, .bazaar-empty { padding: var(--spacing-lg); text-align: center; font-size: var(--base-font-size); } .bazaar-error { color: var(--bazaar-error-color); } .bazaar-empty { color: var(--bazaar-text-secondary); } .bazaar-card { flex: 1 1 0; min-width: 0; max-width: 100%; margin: 0 1px; background: var(--bazaar-card-bg); border: 1px solid var(--bazaar-card-border); border-radius: clamp(4px, 0.8vw, 5px); padding: clamp(10px, 1vw, 12px) clamp(8px, 0.8vw, 10px); box-shadow: 0 1px 2px var(--bazaar-card-shadow); transition: transform 0.2s, box-shadow 0.2s; cursor: default; box-sizing: border-box; display: flex; flex-direction: column; justify-content: space-between; word-break: break-word; overflow-wrap: anywhere; } .bazaar-card:hover { transform: translateY(-1px); box-shadow: 0 2px 6px var(--bazaar-card-shadow-hover); } .bazaar-card > div { margin-bottom: var(--spacing-xs); } .bazaar-card-name { font-weight: bold; font-size: var(--large-font-size); line-height: 1.2; font-family: sans-serif; color: var(--bazaar-text-primary); margin-bottom: var(--spacing-sm); letter-spacing: 0.1px; word-break: break-word; overflow-wrap: anywhere; min-width: 0; } .bazaar-settings-modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.8); z-index: 10000; justify-content: center; align-items: center; backdrop-filter: blur(5px); } .bazaar-settings-modal.show { display: flex; } .bazaar-settings-content { background: var(--settings-bg); border-radius: clamp(6px, 1vw, 8px); max-width: min(600px, 90vw); width: 90%; max-height: 85vh; overflow: hidden; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5); position: relative; display: flex; flex-direction: column; } :root { --settings-bg: #ffffff; --settings-header-bg: #f8f9fa; --settings-border: #dee2e6; --settings-text: #212529; --settings-text-secondary: #6c757d; --settings-tab-active: #0066cc; --settings-tab-hover: #f8f9fa; --settings-input-bg: #ffffff; --settings-input-border: #ced4da; --settings-button-primary: #28a745; --settings-button-secondary: #6c757d; --settings-credits-bg: #f8f9fa; --settings-link: #0066cc; } body.dark-mode { --settings-bg: #2b2b2b; --settings-header-bg: #1f1f1f; --settings-border: #444444; --settings-text: #e8e8e8; --settings-text-secondary: #aaaaaa; --settings-tab-active: #4da6ff; --settings-tab-hover: #3a3a3a; --settings-input-bg: #3a3a3a; --settings-input-border: #555555; --settings-button-primary: #28a745; --settings-button-secondary: #6c757d; --settings-credits-bg: #1f1f1f; --settings-link: #4da6ff; } .bazaar-settings-header { background: var(--settings-header-bg); padding: clamp(12px, 2vw, 20px) clamp(16px, 2.5vw, 24px); border-bottom: 1px solid var(--settings-border); position: relative; } .bazaar-settings-title { font-size: clamp(16px, 2vw, 20px); font-weight: 600; color: var(--settings-text); margin: 0; padding-right: 40px; } .bazaar-settings-body { flex: 1; overflow-y: auto; padding: clamp(16px, 2vw, 24px); } .bazaar-settings-body::-webkit-scrollbar { width: 8px; } .bazaar-settings-body::-webkit-scrollbar-track { background: var(--settings-bg); } .bazaar-settings-body::-webkit-scrollbar-thumb { background: var(--settings-border); border-radius: 4px; } .bazaar-settings-body::-webkit-scrollbar-thumb:hover { background: var(--settings-text-secondary); } .bazaar-settings-section { margin-bottom: clamp(16px, 2vw, 24px); } .bazaar-settings-section-title { font-size: clamp(14px, 1.5vw, 16px); font-weight: 600; color: var(--settings-text); margin-bottom: clamp(12px, 1.5vw, 16px); } .bazaar-settings-field { margin-bottom: clamp(12px, 1.5vw, 16px); } .bazaar-settings-field-label { display: block; font-size: clamp(12px, 1.2vw, 14px); font-weight: 500; color: var(--settings-text); margin-bottom: 4px; } .bazaar-settings-field-description { font-size: clamp(10px, 1vw, 12px); color: var(--settings-text-secondary); margin-bottom: 8px; line-height: 1.4; } .bazaar-settings-input, .bazaar-settings-select { padding: clamp(6px, 0.8vw, 8px) clamp(8px, 1vw, 12px); border: 1px solid var(--settings-input-border); border-radius: 4px; background: var(--settings-input-bg); color: var(--settings-text); font-size: clamp(12px, 1.2vw, 14px); transition: all 0.2s; } .bazaar-settings-input[type="number"] { width: 120px; } .bazaar-settings-select { width: auto; min-width: 200px; max-width: 300px; } .bazaar-settings-input:focus, .bazaar-settings-select:focus { outline: none; border-color: var(--settings-tab-active); box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1); } body.dark-mode .bazaar-settings-input:focus, body.dark-mode .bazaar-settings-select:focus { box-shadow: 0 0 0 3px rgba(77, 166, 255, 0.2); } .bazaar-settings-toggle-field { display: flex; align-items: center; justify-content: space-between; padding: 12px 0; } .bazaar-settings-toggle-info { flex: 1; margin-right: 16px; } .bazaar-toggle-switch { position: relative; width: 48px; height: 24px; background: var(--settings-input-border); border-radius: 12px; cursor: pointer; transition: background 0.3s; flex-shrink: 0; } .bazaar-toggle-switch.active { background: var(--settings-button-primary); } .bazaar-toggle-slider { position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; background: white; border-radius: 50%; transition: transform 0.3s; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } .bazaar-toggle-switch.active .bazaar-toggle-slider { transform: translateX(24px); } .bazaar-settings-actions { display: flex; gap: clamp(8px, 1vw, 12px); justify-content: flex-end; padding: clamp(12px, 1.5vw, 16px) clamp(16px, 2vw, 24px); border-top: 1px solid var(--settings-border); background: var(--settings-header-bg); } .bazaar-settings-btn { padding: clamp(8px, 1vw, 10px) clamp(16px, 1.5vw, 20px); border: none; border-radius: 4px; font-size: clamp(12px, 1.2vw, 14px); font-weight: 500; cursor: pointer; transition: all 0.2s; } .bazaar-settings-btn-primary { background: var(--settings-button-primary); color: white; } .bazaar-settings-btn-primary:hover { background: #218838; transform: translateY(-1px); box-shadow: 0 2px 8px rgba(40, 167, 69, 0.3); } .bazaar-settings-btn-secondary { background: var(--settings-button-secondary); color: white; } .bazaar-settings-btn-secondary:hover { background: #5a6268; transform: translateY(-1px); box-shadow: 0 2px 8px rgba(108, 117, 125, 0.3); } .bazaar-settings-credits { background: var(--settings-credits-bg); padding: clamp(12px, 1.5vw, 16px) clamp(16px, 2vw, 24px); border-top: 1px solid var(--settings-border); text-align: center; font-size: clamp(10px, 1vw, 12px); color: var(--settings-text-secondary); line-height: 1.6; } .bazaar-settings-credits a { color: var(--settings-link); text-decoration: none; font-weight: 500; transition: opacity 0.2s; } .bazaar-settings-credits a:hover { opacity: 0.8; text-decoration: underline; } .bazaar-settings-credits-divider { margin: 0 8px; color: var(--settings-text-secondary); } .bazaar-settings-close { position: absolute; top: 20px; right: 24px; background: none; border: none; font-size: 24px; color: var(--settings-text-secondary); cursor: pointer; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; border-radius: 4px; transition: all 0.2s; } .bazaar-settings-close:hover { background: var(--settings-tab-hover); color: var(--settings-text); } .bazaar-card-name a { color: #0066cc; text-decoration: none; transition: opacity 0.2s; } .bazaar-card-name a:visited { color: #800080 !important; } .bazaar-card-name a:hover { opacity: 0.8; text-decoration: underline; } body.dark-mode .bazaar-card-name a { color: #4da6ff; } body.dark-mode .bazaar-card-name a:visited { color: #b366ff !important; } .bazaar-card-info { display: flex; flex-direction: column; gap: var(--spacing-xs); margin-bottom: var(--spacing-sm); min-width: 0; word-break: break-word; overflow-wrap: anywhere; } .bazaar-card-price, .bazaar-card-qty { font-weight: 500; font-size: var(--large-font-size); line-height: 1.1; font-family: sans-serif; color: var(--bazaar-text-primary); } .bazaar-card-bottom { display: flex; justify-content: center; align-items: center; border-top: 1px solid var(--bazaar-border-light); padding-top: var(--spacing-xs); margin-top: auto; font-size: var(--small-font-size); color: var(--bazaar-text-secondary); } .bazaar-card-time { color: var(--bazaar-text-tertiary); font-size: var(--tiny-font-size); } .bazaar-price-wrapper { display: flex; align-items: center; justify-content: center; gap: var(--spacing-sm); flex-wrap: wrap; min-width: 0; word-break: break-word; overflow-wrap: anywhere; width: 100%; text-align: center; } .bazaar-market-diff { display: block; text-align: center; margin: 0 auto; word-break: break-word; overflow-wrap: anywhere; min-width: 0; } .bazaar-market-diff.positive { color: #ef4444; background: rgba(239, 68, 68, 0.1); } .bazaar-market-diff.negative { color: #22c55e; background: rgba(34, 197, 94, 0.1); } .bazaar-market-diff:hover { transform: scale(1.05); } body.dark-mode .bazaar-market-diff.positive { color: #f87171; background: rgba(248, 113, 113, 0.15); } body.dark-mode .bazaar-market-diff.negative { color: #4ade80; background: rgba(74, 222, 128, 0.15); } .bazaar-footer { margin-top: var(--spacing-sm); padding-top: var(--spacing-sm); border-top: 1px solid var(--bazaar-border-light); font-size: var(--base-font-size); color: var(--bazaar-text-secondary); line-height: 1.4; display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: var(--spacing-xs); } .bazaar-footer-stats, .bazaar-footer-stat, .bazaar-footer-link, .bazaar-footer-separator { font-size: var(--base-font-size); } .bazaar-footer-link-text-full { display: inline; } .bazaar-footer-link-text-short { display: none; } @media (max-width: 600px) { .bazaar-footer-link-text-full { display: none; } .bazaar-footer-link-text-short { display: inline; } .bazaar-footer-stat-label { display: none; } } .bazaar-footer-link { color: #0066cc !important; text-decoration: none; transition: opacity 0.2s; } .bazaar-footer-link:hover { opacity: 0.8; text-decoration: underline; } .bazaar-footer-link:visited { color: #0066cc !important; } body.dark-mode .bazaar-footer-link { color: #4da6ff !important; } body.dark-mode .bazaar-footer-link:visited { color: #4da6ff !important; } `; GM_addStyle(styles); }; const utils = { getRelativeTime(timestamp) { const now = Math.floor(Date.now() / 1000); const diff = now - timestamp; const intervals = [ { unit: 'day', seconds: 86400 }, { unit: 'hour', seconds: 3600 }, { unit: 'minute', seconds: 60 }, { unit: 'second', seconds: 1 } ]; for (const { unit, seconds } of intervals) { const value = Math.floor(diff / seconds); if (value >= 1) { return `Checked ${value} ${unit}${value !== 1 ? 's' : ''} ago`; } } return 'just now'; }, parseItemID(body) { if (!body) return null; const parseValue = (data) => { if (data instanceof FormData) return data.get('itemID'); if (data instanceof URLSearchParams) return data.get('itemID'); if (typeof data === 'string') return new URLSearchParams(data).get('itemID'); return null; }; return parseValue(body); }, isMobile() { return window.innerWidth <= CONFIG.MOBILE_BREAKPOINT; }, createBazaarUrl(listing, itemID) { return `https://www.torn.com/bazaar.php?userId=${listing.player_id}&itemID=${itemID}&price=${listing.price}&qty=${listing.quantity}#/`; } }; const dom = { createContainer() { const containerHtml = `
Number of bazaar listings to show per page
Choose how listings are sorted: Price, Quantity, Profit, or Last Updated
Default minimum quantity filter value
How bazaar links should open when clicked