您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Add buy/sell thresholds to Torn stocks in their own column, highlight when matched, values persist after refresh
// ==UserScript== // @name Torn Stock Buy/Sell Highlighter (Persistent, Fixed Selector) // @namespace http://tampermonkey.net/ // @version 1.3 // @description Add buy/sell thresholds to Torn stocks in their own column, highlight when matched, values persist after refresh // @author You // @match https://www.torn.com/page.php?sid=stocks* // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; function extractPrice(priceDiv) { const spans = priceDiv.querySelectorAll('span.number___hhGqA'); return parseFloat(Array.from(spans).map(span => span.textContent).join('')); } // safer way to get a unique stock key function getStockKey(stockEl) { // Torn usually sets a data-stock or data-id on the UL const dataId = stockEl.dataset?.stock || stockEl.dataset?.id; if (dataId) return `stock_${dataId}`; // fallback: try first heading inside the UL (name, ticker, etc.) const nameEl = stockEl.querySelector('li h4, li strong, li .name'); if (nameEl) return `stock_${nameEl.textContent.trim()}`; // as last resort, unique index in DOM (won't persist well if order changes) return `stock_index_${[...stockEl.parentNode.children].indexOf(stockEl)}`; } function waitForStocksAndInit() { const container = document.querySelector('div.stockMarket___iB18v'); if (!container) return setTimeout(waitForStocksAndInit, 500); const stockBlocks = container.querySelectorAll('ul[class*="stock__"]'); if (!stockBlocks.length) return setTimeout(waitForStocksAndInit, 500); addThresholdColumn(stockBlocks); setInterval(() => checkThresholds(stockBlocks), 2000); } function addThresholdColumn(stockBlocks) { stockBlocks.forEach(stockEl => { if (stockEl.querySelector('.threshold-col')) return; const stockKey = getStockKey(stockEl); const liElements = stockEl.querySelectorAll('li'); if (liElements.length < 3) return; const newCol = document.createElement('li'); newCol.className = 'threshold-col'; newCol.style.display = 'flex'; newCol.style.flexDirection = 'column'; newCol.style.alignItems = 'center'; newCol.style.justifyContent = 'center'; newCol.style.minWidth = '65px'; newCol.style.padding = '0 4px'; const inputStyle = ` width: 55px; font-size: 11px; margin-bottom: 2px; text-align: center; `; const buyInput = document.createElement('input'); buyInput.type = 'number'; buyInput.placeholder = 'Buy'; buyInput.className = 'buy-threshold'; buyInput.style.cssText = inputStyle; const sellInput = document.createElement('input'); sellInput.type = 'number'; sellInput.placeholder = 'Sell'; sellInput.className = 'sell-threshold'; sellInput.style.cssText = inputStyle; // Load saved thresholds const saved = JSON.parse(localStorage.getItem('stockThresholds') || '{}'); if (saved[stockKey]) { if (saved[stockKey].buy) buyInput.value = saved[stockKey].buy; if (saved[stockKey].sell) sellInput.value = saved[stockKey].sell; } function saveThresholds() { const data = JSON.parse(localStorage.getItem('stockThresholds') || '{}'); data[stockKey] = { buy: buyInput.value || null, sell: sellInput.value || null }; localStorage.setItem('stockThresholds', JSON.stringify(data)); } buyInput.addEventListener('input', saveThresholds); sellInput.addEventListener('input', saveThresholds); // --- Clear Button --- const clearBtn = document.createElement('button'); clearBtn.textContent = 'Clear'; clearBtn.style.fontSize = '10px'; clearBtn.style.padding = '2px 4px'; clearBtn.style.marginTop = '2px'; clearBtn.style.cursor = 'pointer'; clearBtn.addEventListener('click', () => { buyInput.value = ''; sellInput.value = ''; const data = JSON.parse(localStorage.getItem('stockThresholds') || '{}'); delete data[stockKey]; localStorage.setItem('stockThresholds', JSON.stringify(data)); stockEl.style.backgroundColor = ''; // remove highlight }); newCol.appendChild(buyInput); newCol.appendChild(sellInput); newCol.appendChild(clearBtn); liElements[2].insertAdjacentElement('afterend', newCol); }); } function checkThresholds(stockBlocks) { stockBlocks.forEach(stockEl => { const priceDiv = stockEl.querySelector('div.price___CTjJE'); if (!priceDiv) return; const price = extractPrice(priceDiv); const buyVal = parseFloat(stockEl.querySelector('.buy-threshold')?.value); const sellVal = parseFloat(stockEl.querySelector('.sell-threshold')?.value); stockEl.style.backgroundColor = ''; // reset if (!isNaN(buyVal) && price <= buyVal) { stockEl.style.backgroundColor = 'rgba(0,255,0,0.15)'; } if (!isNaN(sellVal) && price >= sellVal) { stockEl.style.backgroundColor = 'rgba(255,0,0,0.15)'; } }); } waitForStocksAndInit(); })();