您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
When your bazaar is open, a banner warns when your bazaar items are undercut using data from weav3r.dev
- // ==UserScript==
- // @name Bazaar Undercut Alert
- // @namespace https://torn.com/
- // @version 1.0
- // @author swervelord [3637232]
- // @description When your bazaar is open, a banner warns when your bazaar items are undercut using data from weav3r.dev
- //
- // @match https://www.torn.com/*
- //
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM_xmlhttpRequest
- // @connect api.torn.com
- // @connect weav3r.dev
- // ==/UserScript==
- (() => {
- const KEY_STORE = 'torn_api_key';
- const CHECK_EVERY_MS = 60_000;
- const MAX_TORN_CALLS_PER_MIN = 50;
- const PLACEHOLDER_PRICE = 1;
- let queue = [];
- let undercutNow = new Map();
- let tornCallsThisMinute = 0;
- let bannerDismissed = false;
- let bazaarOpen = false;
- const banner = (() => {
- const wrap = document.createElement('div');
- wrap.id = 'undercutBanner';
- wrap.style.cssText = `
- position:fixed;top:0;left:0;right:0;
- display:none;
- align-items:center;
- justify-content:center;
- padding:3px 8px;
- height:20px;
- background:#2c2c2c;
- color:#ffffff;
- font:600 11px/14px "Segoe UI", sans-serif;
- z-index:2147483647;
- box-shadow:0 1px 4px rgba(0,0,0,0.2);
- cursor:pointer;
- `;
- const textSpan = document.createElement('span');
- textSpan.style.cssText = `
- text-align:center;
- width:100%;
- overflow:hidden;
- white-space:nowrap;
- text-overflow:ellipsis;
- `;
- wrap.appendChild(textSpan);
- const close = document.createElement('span');
- close.textContent = '✕';
- close.style.cssText = `
- position:absolute;
- top:3px;
- right:8px;
- font-weight:bold;
- font-size:10px;
- background:#1a1a1a;
- color:white;
- border-radius:3px;
- padding:0 4px;
- cursor:pointer;
- line-height:14px;
- `;
- close.addEventListener('click', e => {
- e.stopPropagation();
- wrap.style.display = 'none';
- bannerDismissed = true;
- });
- wrap.addEventListener('click', () => {
- if (!bannerDismissed) {
- window.open('https://www.torn.com/bazaar.php#/manage', '_blank');
- }
- });
- wrap.appendChild(close);
- document.body.prepend(wrap);
- return { wrap, textSpan };
- })();
- const updateBanner = () => {
- if (bannerDismissed || !bazaarOpen || !undercutNow.size) {
- banner.wrap.style.display = 'none';
- return;
- }
- banner.wrap.style.display = 'flex';
- const items = [...undercutNow.values()]
- .map(o => `<span style="color:#00c8d6">${o.name}</span>`).join(', ');
- banner.textSpan.innerHTML = `Your items have been undercut: ${items}`;
- };
- const apiKey = () => {
- let k = GM_getValue(KEY_STORE, '');
- if (!k) {
- k = prompt('Enter your Torn API key (MINIMAL access, stored only locally):', '');
- if (k) GM_setValue(KEY_STORE, k.trim());
- }
- return k;
- };
- const httpJSON = url => new Promise((resolve, reject) => {
- GM_xmlhttpRequest({
- method: 'GET',
- url,
- headers: { accept: 'application/json' },
- onload: r => {
- try { resolve(JSON.parse(r.responseText)); } catch (e) { reject(e); }
- },
- onerror: reject,
- timeout: 15000
- });
- });
- const resetTornThrottle = () => { tornCallsThisMinute = 0; };
- const refreshBazaarData = async () => {
- if (queue.length || tornCallsThisMinute >= MAX_TORN_CALLS_PER_MIN) return;
- const key = apiKey();
- if (!key) return;
- tornCallsThisMinute++;
- try {
- const data = await httpJSON(`https://api.torn.com/user/?selections=bazaar&key=${key}`);
- bazaarOpen = !!data.bazaar_is_open;
- if (!bazaarOpen) { updateBanner(); return; }
- const fresh = Object.values(data.bazaar || {})
- .filter(i => i.price > PLACEHOLDER_PRICE)
- .map(i => ({ id: i.ID, name: i.name, price: i.price }));
- queue.push(...fresh);
- } catch (err) {
- console.error('Torn API error:', err);
- }
- };
- const processQueueBatch = async () => {
- while (queue.length) {
- const { id, name, price } = queue.shift();
- try {
- const res = await httpJSON(`https://weav3r.dev/api/marketplace/${id}`);
- const lowest = (res.listings || []).reduce((m, l) => Math.min(m, l.price), Infinity);
- if (Number.isFinite(lowest) && price > lowest) {
- undercutNow.set(id, { name, our: price, lowest });
- } else {
- undercutNow.delete(id);
- }
- } catch (e) {
- console.error('weav3r error:', e);
- }
- }
- updateBanner();
- };
- setInterval(resetTornThrottle, CHECK_EVERY_MS);
- setInterval(refreshBazaarData, CHECK_EVERY_MS);
- setInterval(processQueueBatch, 2000);
- refreshBazaarData().then(processQueueBatch);
- })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址