Torn Manual Price Highlighter (Item Market + Bazaar)

Manually set a price and highlight both item market and bazaar sellers accordingly in Torn.com.

目前为 2025-03-25 提交的版本。查看 最新版本

// ==UserScript==
// @name         Torn Manual Price Highlighter (Item Market + Bazaar)
// @namespace    http://tampermonkey.net/
// @version      0.5
// @description  Manually set a price and highlight both item market and bazaar sellers accordingly in Torn.com.
// @license MIT 
// @author       JeffBezas[3408347]
// @match        https://www.torn.com/page.php?sid=ItemMarket*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addStyle
// ==/UserScript==

(function () {
    'use strict';

    GM_addStyle(`
        .manual-highlight-good { background-color: #004d00 !important; color: white; }
        .manual-highlight-warning { background-color: #ffa500 !important; color: black; }
        .manual-highlight-bad { background-color: #8b0000 !important; color: white; }

        #manual-price-modal {
            position: fixed;
            top: 30%;
            left: 50%;
            transform: translate(-50%, -30%);
            background: #1e1e1e;
            color: white;
            padding: 20px;
            border: 2px solid #888;
            border-radius: 10px;
            z-index: 9999;
            display: none;
        }

        #manual-price-modal input {
            width: 100px;
            padding: 5px;
            font-size: 14px;
        }

        #manual-price-modal button {
            margin-left: 10px;
            padding: 5px 10px;
            background: #444;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }
    `);

    // ========== Modal Setup ==========
    const modal = document.createElement("div");
    modal.id = "manual-price-modal";
    modal.innerHTML = `
        <label>Manual price: $<input type="number" id="manual-price-input" /></label>
        <button id="manual-price-save">Save</button>
        <button id="manual-price-cancel">Cancel</button>
    `;
    document.body.appendChild(modal);

    const priceInput = document.getElementById("manual-price-input");
    const saveBtn = document.getElementById("manual-price-save");
    const cancelBtn = document.getElementById("manual-price-cancel");

    let currentItemId = null;

    // ========== Save Price ==========
    saveBtn.onclick = () => {
        const value = parseInt(priceInput.value);
        if (value > 0 && currentItemId) {
            GM_setValue(`manual_price_${currentItemId}`, value);
            modal.style.display = "none";

            // Highlight Item Market rows
            const observer = new MutationObserver(() => {
                const sellerRows = document.querySelectorAll('li[class*="rowWrapper___"]');
                if (sellerRows.length > 0) {
                    observer.disconnect();
                    highlightSellerRows(currentItemId, value);
                }
            });

            observer.observe(document.body, {
                childList: true,
                subtree: true
            });

            // Highlight Bazaar prices
            waitForBazaarPrices(currentItemId, value);
        }
    };

    cancelBtn.onclick = () => {
        modal.style.display = "none";
    };

    // ========== Item Market Highlight ==========
    function highlightSellerRows(itemId, manualPrice) {
        const rows = document.querySelectorAll('li[class*="rowWrapper___"]');
        rows.forEach(row => {
            const priceEl = row.querySelector('div[class*="price___"]');
            if (!priceEl) return;

            const match = priceEl.textContent.match(/\$([\d,]+)/);
            if (!match) return;

            const listed = parseInt(match[1].replace(/,/g, ''));
            const diffPercent = ((listed - manualPrice) / manualPrice) * 100;
            console.log(`[ItemMarket] $${listed} vs $${manualPrice} (${diffPercent.toFixed(2)}%)`);

            row.classList.remove('manual-highlight-good', 'manual-highlight-warning', 'manual-highlight-bad');

            if (listed <= manualPrice) {
                row.classList.add('manual-highlight-good');
            } else if (diffPercent <= 5) {
                row.classList.add('manual-highlight-warning');
            } else {
                row.classList.add('manual-highlight-bad');
            }
        });
    }

    // ========== Bazaar Enhancer Highlight ==========
    function highlightBazaarPrices(priceLinks, manualPrice) {
        console.log(`[Bazaar Debug] Highlighting ${priceLinks.length} links for item`, manualPrice);

        priceLinks.forEach(link => {
            if (link.dataset.manualChecked === "true") return;

            const match = link.textContent.match(/\$([\d,]+)/);
            if (!match) return;

            const listed = parseInt(match[1].replace(/,/g, ''));
            const diff = ((listed - manualPrice) / manualPrice) * 100;

            link.dataset.manualChecked = "true";
            link.style.padding = "2px 4px";
            link.style.borderRadius = "4px";
            link.style.fontWeight = "bold";

            if (listed <= manualPrice) {
                link.style.backgroundColor = "#004d00"; // Green
                link.style.color = "#fff";
            } else if (diff <= 5) {
                link.style.backgroundColor = "#ffa500"; // Yellow
                link.style.color = "#000";
            } else {
                link.style.backgroundColor = "#8b0000"; // Red
                link.style.color = "#fff";
            }

            console.log(`[Bazaar] $${listed} vs $${manualPrice} (${diff.toFixed(2)}%)`);
        });
    }

    // ========== Bazaar Wait Loop ==========
    function waitForBazaarPrices(itemId, manualPrice) {
    const listingsView = document.querySelector('#fullListingsView');
    if (!listingsView) return;

    const observer = new MutationObserver(() => {
        const noItem = listingsView.textContent.includes("No item selected");
        const priceLinks = listingsView.querySelectorAll('a[href*="bazaar.php?userID="]:not([data-checked])');

        // Only trigger once it's no longer saying "No item selected"
        if (!noItem && priceLinks.length > 0) {
            observer.disconnect();
            console.log(`[Bazaar Trigger] Detected new item listings... highlighting.`);
            highlightBazaarPrices(priceLinks, manualPrice);

        }
    });

    observer.observe(listingsView, {
        childList: true,
        subtree: true,
        characterData: true
    });
}



    // ========== Buy Item Listener ==========
    function extractItemIdFromButton(button) {
        const container = button.closest('.itemTile___cbw7w');
        const img = container?.querySelector('img.torn-item');
        const match = img?.src?.match(/\/items\/(\d+)\//);
        return match ? match[1] : null;
    }

    function setupBuyButtonListeners() {
        document.querySelectorAll('.actionButton___pb_Da').forEach(btn => {
            if (btn.dataset.boundManual === "true") return;
            btn.dataset.boundManual = "true";

            btn.addEventListener('click', () => {
                const itemId = extractItemIdFromButton(btn);
                if (!itemId) return;

                currentItemId = itemId;
                const saved = GM_getValue(`manual_price_${itemId}`, "");
                priceInput.value = saved || "";
                modal.style.display = "block";

                if (saved) {
                    const observer = new MutationObserver(() => {
                        const sellerRows = document.querySelectorAll('li[class*="rowWrapper___"]');
                        if (sellerRows.length > 0) {
                            observer.disconnect();
                            highlightSellerRows(itemId, parseInt(saved));
                        }
                    });

                    observer.observe(document.body, {
                        childList: true,
                        subtree: true
                    });

                    waitForBazaarPrices(itemId, parseInt(saved));
                }
            });
        });
    }

    // ========== Init Loop ==========
    setInterval(setupBuyButtonListeners, 1000);

    window.addEventListener('keydown', (e) => {
        if (e.key === "Escape") {
            modal.style.display = "none";
        }
    });
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址