您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Bazaar listings on Item Page
// ==UserScript== // @name Bazaar Listings on Market *NO PDA* (TE Market Value, No API Key) // @namespace https://weav3r.dev/ // @version 2.3.4 // @description Bazaar listings on Item Page // @author WTV [3281931] // @match https://www.torn.com/* // @grant GM_xmlhttpRequest // @license MIT // ==/UserScript== (function() { 'use strict'; let currentSortKey = 'price'; let currentSortOrder = 'asc'; let allListings = []; let filteredListings = []; window._visitedBazaars = new Set(); function sortListings(listings) { const key = currentSortKey, order = currentSortOrder; return [...listings].sort((a,b)=>{ let valA = a[key] || 0, valB = b[key] || 0; if(key==='player_name'){ valA=valA.toLowerCase(); valB=valB.toLowerCase(); } return (valA>valB?1:valA<valB?-1:0)*(order==='asc'?1:-1); }); } function applyFilters(listings, filters) { return listings.filter(l=>{ if(filters.minPrice && l.price < parseFloat(filters.minPrice)) return false; if(filters.maxPrice && l.price > parseFloat(filters.maxPrice)) return false; if(filters.minQty && l.quantity < parseInt(filters.minQty)) return false; if(filters.maxQty && l.quantity > parseInt(filters.maxQty)) return false; return true; }); } function renderMessage(container,isError){ const cardContainer = container.querySelector('.bazaar-card-container'); if(!cardContainer) return; cardContainer.innerHTML = ''; const msg = document.createElement('div'); msg.style.cssText='color:#fff;text-align:center;padding:20px;width:100%;'; msg.innerHTML = isError ? "API Error<br><span style='font-size:12px;color:#ccc;'>Please try again later</span>" : "No bazaar listings available for this item."; cardContainer.appendChild(msg); } function createInfoContainer(itemName,itemId,marketValue){ const container=document.createElement('div'); container.className='bazaar-info-container'; container.dataset.itemid=itemId; if(marketValue) container.dataset.marketValue = marketValue; container.style.cssText='border:1px solid #888;margin:10px 0;padding:5px;background:#222;color:#fff;'; const marketText = marketValue ? ` <span style="color:#FFD700;">(Market Value: ${marketValue})</span>` : ''; container.innerHTML=` <div class="bazaar-info-header" style="font-weight:bold;margin-bottom:5px;"> Bazaar Listings for ${itemName}${marketText} </div> <div class="bazaar-controls" style="margin-bottom:5px; display:flex; gap:5px; flex-wrap:wrap;"></div> <div class="bazaar-card-container" style="display:flex;overflow-x:auto;padding:5px;gap:5px;"></div> `; const cardContainer = container.querySelector('.bazaar-card-container'); if(cardContainer){ cardContainer.addEventListener("wheel", e=>{ if(e.deltaY!==0){ e.preventDefault(); cardContainer.scrollLeft += e.deltaY; } }); } return container; } function createFilters(container){ const controls=container.querySelector('.bazaar-controls'); controls.innerHTML=''; const sortSelect=document.createElement('select'); ['price','quantity','player_name'].forEach(opt=>{ const o=document.createElement('option'); o.value=opt; o.textContent=opt.charAt(0).toUpperCase()+opt.slice(1); if(opt===currentSortKey) o.selected=true; sortSelect.appendChild(o); }); sortSelect.addEventListener('change', ()=>{ currentSortKey=sortSelect.value; renderCards(container); }); const orderBtn=document.createElement('button'); orderBtn.textContent=currentSortOrder==='asc'?'Asc':'Desc'; orderBtn.addEventListener('click', ()=>{ currentSortOrder=currentSortOrder==='asc'?'desc':'asc'; orderBtn.textContent=currentSortOrder==='asc'?'Asc':'Desc'; renderCards(container); }); const minPrice=document.createElement('input'); minPrice.type='number'; minPrice.placeholder='Min Price'; minPrice.style.width='80px'; const maxPrice=document.createElement('input'); maxPrice.type='number'; maxPrice.placeholder='Max Price'; maxPrice.style.width='80px'; const minQty=document.createElement('input'); minQty.type='number'; minQty.placeholder='Min Qty'; minQty.style.width='80px'; const maxQty=document.createElement('input'); maxQty.type='number'; maxQty.placeholder='Max Qty'; maxQty.style.width='80px'; const applyBtn=document.createElement('button'); applyBtn.textContent="Apply"; applyBtn.addEventListener('click', ()=>renderCards(container)); [minPrice,maxPrice,minQty,maxQty].forEach(inp=>{ inp.addEventListener('keydown', e=>{ if(e.key==='Enter'){ renderCards(container); } }); }); controls.appendChild(sortSelect); controls.appendChild(orderBtn); [minPrice,maxPrice,minQty,maxQty].forEach(inp=>controls.appendChild(inp)); controls.appendChild(applyBtn); } function renderCards(container){ const cardContainer=container.querySelector('.bazaar-card-container'); if(!cardContainer || !allListings) return; const controls=container.querySelector('.bazaar-controls'); const filters={ minPrice: controls.querySelector('input[placeholder="Min Price"]').value, maxPrice: controls.querySelector('input[placeholder="Max Price"]').value, minQty: controls.querySelector('input[placeholder="Min Qty"]').value, maxQty: controls.querySelector('input[placeholder="Max Qty"]').value }; filteredListings=applyFilters(allListings,filters); filteredListings=sortListings(filteredListings); cardContainer.innerHTML=''; if(filteredListings.length===0){ renderMessage(container,false); return; } const marketValueStr = container.dataset.marketValue; const marketNum = marketValueStr ? parseInt(marketValueStr.replace(/\D/g,'')) : null; filteredListings.forEach(listing=>{ const card=document.createElement('div'); const isVisited=window._visitedBazaars.has(listing.player_id); card.style.cssText=` border:1px solid #444; background:#222; color:#eee; padding:10px; margin:2px; min-width:160px; cursor:pointer; display:flex; flex-direction:column; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size:15px; transition:transform 0.2s; position: relative; `; if(!isVisited){ card.addEventListener('mouseenter', ()=>card.style.transform='scale(1.03)'); card.addEventListener('mouseleave', ()=>card.style.transform='scale(1)'); } const formattedPrice = `$${Math.round(listing.price).toLocaleString()}`; let diffText = ''; if(marketNum){ const percent = ((listing.price - marketNum)/marketNum*100).toFixed(1); const color = percent < 0 ? 'limegreen' : 'red'; const sign = percent > 0 ? '+' : ''; diffText = `<span style="position:absolute; right:10px; top:50%; transform:translateY(-50%); font-weight:bold; color:${color};">${sign}${percent}%</span>`; } card.innerHTML=` <div style="font-weight:bold; color:${isVisited?'#800080':'#1E90FF'}">${listing.player_name || 'Unknown'}</div> <div>Qty: ${listing.quantity}</div> <div>Price: ${formattedPrice}</div> ${diffText} `; card.addEventListener('click', ()=>{ if(listing.player_id){ window._visitedBazaars.add(listing.player_id); const nameDiv = card.querySelector('div:first-child'); if(nameDiv) nameDiv.style.color='#800080'; window.open(`https://www.torn.com/bazaar.php?userId=${listing.player_id}&highlightItem=${listing.item_id}#/`,'_blank'); } }); cardContainer.appendChild(card); }); } function updateInfoContainer(wrapper,itemId,itemName){ let infoContainer=document.querySelector(`.bazaar-info-container[data-itemid="${itemId}"]`); if(!infoContainer){ // Fetch market value from TornExchange public API GM_xmlhttpRequest({ method: "GET", url: `https://tornexchange.com/api/te_price?item_id=${itemId}`, onload: function(response){ let marketValue = ''; try{ const data = JSON.parse(response.responseText); if(data && data.status === 'success' && data.data && data.data.te_price){ const rounded = Math.round(data.data.te_price); marketValue = `$${rounded.toLocaleString()}`; } } catch(e){} // create the info container with marketValue infoContainer = createInfoContainer(itemName, itemId, marketValue); wrapper.insertBefore(infoContainer, wrapper.firstChild); createFilters(infoContainer); fetchBazaarListings(itemId, infoContainer); }, onerror:function(){ infoContainer = createInfoContainer(itemName, itemId,''); wrapper.insertBefore(infoContainer, wrapper.firstChild); createFilters(infoContainer); fetchBazaarListings(itemId, infoContainer); } }); } else { renderCards(infoContainer); } } function fetchBazaarListings(itemId, infoContainer){ GM_xmlhttpRequest({ method:"GET", url:`https://weav3r.dev/api/marketplace/${itemId}`, onload:function(response){ try{ const data = JSON.parse(response.responseText); if(!data || !data.listings){ renderMessage(infoContainer,true); return; } allListings = data.listings.map(l=>({ player_name:l.player_name, player_id:l.player_id, quantity:l.quantity, price:l.price, item_id:l.item_id })); renderCards(infoContainer); } catch(e){ renderMessage(infoContainer,true); } }, onerror:function(){ renderMessage(infoContainer,true); } }); } function processSellerWrapper(wrapper){ if(!wrapper || wrapper.dataset.bazaarProcessed) return; const itemTile = wrapper.closest('[class*="itemTile"]') || wrapper.previousElementSibling; if(!itemTile) return; let nameEl = itemTile.querySelector('div[class*="name"]') || itemTile.querySelector('div'); const btn = itemTile.querySelector('button[aria-controls*="itemInfo"]'); if(!nameEl || !btn) return; const itemName = nameEl.textContent.trim(); const idParts = btn.getAttribute('aria-controls').split('-'); const itemId = idParts[idParts.length-1]; wrapper.dataset.bazaarProcessed='true'; updateInfoContainer(wrapper,itemId,itemName); } function processAllSellerWrappers(root=document.body){ const sellerWrappers=root.querySelectorAll('[class*="sellerListWrapper"]'); sellerWrappers.forEach(wrapper=>processSellerWrapper(wrapper)); } const observer=new MutationObserver(()=>{ processAllSellerWrappers(); }); observer.observe(document.body,{childList:true,subtree:true}); processAllSellerWrappers(); })(); // --- Bazaar Page Green Highlight --- (function(){ const params=new URLSearchParams(window.location.search); const itemIdToHighlight=params.get('highlightItem'); if(!itemIdToHighlight) return; const observer=new MutationObserver(()=>{ const imgs=document.querySelectorAll('img'); imgs.forEach(img=>{ if(img.src.includes(`/images/items/${itemIdToHighlight}/`)){ img.closest('div')?.style.setProperty('outline','3px solid green','important'); img.scrollIntoView({behavior:'smooth', block:'center'}); } }); }); observer.observe(document.body,{childList:true,subtree:true}); })();