Torn Bazaar Helper

Meowy meow

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         Torn Bazaar Helper
// @namespace    http://tampermonkey.net/
// @version      1.7
// @description  Meowy meow
// @author       Meow
// @match        https://www.torn.com/bazaar.php*
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==

(function() {
    'use strict';

    if (window.location.hash !== '#/add') {
      return;
    }

    GM_addStyle(`
        :root {
            --default-color: #333;
            --default-bg-panel-color: #f2f2f2;
            --default-panel-border-color: #cccccc;
            --input-background-color: #fff;
            --input-color: #000;
            --input-border-color: #ccc;
            --btn-background: linear-gradient(180deg, #DEDEDE 0%, #F7F7F7 25%, #CFCFCF 60%, #E7E7E7 78%, #D9D9D9 100%);
            --btn-border: 1px solid #aaa;
            --btn-color: #555;
            --title-black-gradient: linear-gradient(180deg, #555555 0%, #333333 100%);
            --title-color: #FFF;
        }

        .dark-mode {
            --default-color: #ddd;
            --default-bg-panel-color: #333;
            --default-panel-border-color: #444;
            --input-background-color: #444;
            --input-color: #ddd;
            --input-border-color: #555;
            --btn-background: linear-gradient(180deg, #444 0%, #555 100%);
            --btn-border: 1px solid #222;
            --btn-color: #ccc;
            --title-black-gradient: linear-gradient(180deg, #444 0%, #222 100%);
            --title-color: #ddd;
        }

        .bazaar-helper-btn {
            cursor: pointer;
            margin-right: 10px;
            display: flex;
            align-items: center;
            font-weight: bold;
            color: var(--default-color);
        }
        .bazaar-helper-btn:hover {
            opacity: 0.8;
        }

        #bh-modal-overlay {
            position: fixed;
            top: 0; left: 0; width: 100%; height: 100%;
            background: rgba(0, 0, 0, 0.7);
            z-index: 99999;
            display: none;
            justify-content: center;
            align-items: center;
        }

        #bh-modal-box {
            background: var(--default-bg-panel-color);
            color: var(--default-color);
            border: 1px solid var(--default-panel-border-color);
            border-radius: 5px;
            width: 400px;
            box-shadow: 0 0 15px rgba(0,0,0,0.5);
            font-family: Arial, sans-serif;
            overflow: hidden;
        }

        #bh-modal-header {
            background: var(--title-black-gradient);
            color: var(--title-color);
            font-size: 14px;
            font-weight: bold;
            padding: 8px 10px;
            border-bottom: 1px solid var(--default-panel-border-color);
            display: flex;
            align-items: center;
        }

        .bh-modal-content {
            padding: 15px;
        }

        #bh-apikey {
            width: 100%;
            padding: 8px;
            box-sizing: border-box;
            background: var(--input-background-color);
            color: var(--input-color);
            border: 1px solid var(--input-border-color);
            border-radius: 3px;
            margin-bottom: 10px;
            font-family: monospace;
        }

        #bh-textarea {
            width: 100%;
            height: 200px;
            resize: vertical;
            padding: 8px;
            box-sizing: border-box;
            background: var(--input-background-color);
            color: var(--input-color);
            border: 1px solid var(--input-border-color);
            border-radius: 3px;
            margin-bottom: 15px;
            font-family: monospace;
        }

        .bh-actions {
            display: flex;
            justify-content: flex-end;
            gap: 10px;
        }

        .bh-btn {
            padding: 6px 15px;
            background: var(--btn-background);
            border: var(--btn-border);
            color: var(--btn-color);
            border-radius: 4px;
            cursor: pointer;
            font-weight: bold;
            font-size: 12px;
            text-transform: uppercase;
        }

        .bh-btn:hover {
            filter: brightness(1.1);
        }

        .bh-btn-run {
            background: linear-gradient(to bottom, #8fce00 0%, #6da203 100%);
            color: white;
            border: 1px solid #568203;
            text-shadow: 0 1px 0 #333;
        }
    `);

    function setReactInput(element, value) {
        if (!element) return;
        const lastValue = element.value;
        element.value = value;
        const event = new Event('input', { bubbles: true });
        const tracker = element._valueTracker;
        if (tracker) {
            tracker.setValue(lastValue);
        }
        element.dispatchEvent(event);
    }

    function init() {
        const manageLink = document.querySelector('a[href="#/manage"]');

        if (!manageLink) {
            setTimeout(init, 500);
            return;
        }

        const linkContainer = manageLink.parentNode;

        if (document.getElementById('bazaar-helper-btn')) return;

        const btn = document.createElement('a');
        btn.id = 'bazaar-helper-btn';
        btn.className = manageLink.className;
        btn.innerHTML = `
            <span class="iconWrapper___x3ZLe iconWrapper___COKJD svgIcon___IwbJV">
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <path d="M4 4L9 9L15 9L20 4V14L12 21L4 14V4Z" />
                    <circle cx="9" cy="13" r="1" fill="currentColor" stroke="none"/>
                    <circle cx="15" cy="13" r="1" fill="currentColor" stroke="none"/>
                </svg>
            </span>
            <span class="linkTitle____NPyM">Bazaar Helper</span>
        `;

        btn.style.cursor = 'pointer';
        btn.style.order = "-1";

        btn.addEventListener('click', toggleModal);

        linkContainer.insertBefore(btn, linkContainer.firstChild);

        createModal();
    }

    function createModal() {
        const overlay = document.createElement('div');
        overlay.id = 'bh-modal-overlay';
        overlay.innerHTML = `
            <div id="bh-modal-box">
                <div id="bh-modal-header">Bazaar Helper</div>
                <div class="bh-modal-content">
                    <div style="font-size:12px; margin-bottom:5px; opacity:0.8;">Torn API Key:</div>
                    <input type="text" id="bh-apikey" placeholder="Enter API Key" />
                    <div style="font-size:12px; margin-bottom:5px; opacity:0.8;">Enter item names (one per line):</div>
                    <textarea id="bh-textarea" placeholder="Bag of Chocolate Kisses\nHPCPU\n..."></textarea>
                    <div class="bh-actions">
                        <button id="bh-close" class="bh-btn">Close</button>
                        <button id="bh-save" class="bh-btn">Save</button>
                        <button id="bh-run" class="bh-btn bh-btn-run">Run</button>
                    </div>
                </div>
            </div>
        `;
        document.body.appendChild(overlay);

        document.getElementById('bh-close').addEventListener('click', toggleModal);
        document.getElementById('bh-modal-overlay').addEventListener('click', (e) => {
            if (e.target.id === 'bh-modal-overlay') toggleModal();
        });
        document.getElementById('bh-save').addEventListener('click', saveList);
        document.getElementById('bh-run').addEventListener('click', runScript);

        document.getElementById('bh-textarea').value = GM_getValue('bh_item_list', '');
        document.getElementById('bh-apikey').value = GM_getValue('bh_api_key', '');
    }

    function toggleModal() {
        const el = document.getElementById('bh-modal-overlay');
        el.style.display = el.style.display === 'flex' ? 'none' : 'flex';
    }

    function saveList() {
        const text = document.getElementById('bh-textarea').value;
        const key = document.getElementById('bh-apikey').value;
        GM_setValue('bh_item_list', text);
        GM_setValue('bh_api_key', key);
        const btn = document.getElementById('bh-save');
        const originalText = btn.innerText;
        btn.innerText = "Saved!";
        setTimeout(() => btn.innerText = originalText, 1000);
    }

    async function runScript() {
        saveList();

        const apiKey = GM_getValue('bh_api_key', '').trim();
        if (!apiKey) {
            alert('Bazaar Helper: Please enter your Torn API Key.');
            return;
        }

        const rawList = document.getElementById('bh-textarea').value;
        const wantedItems = rawList.split('\n')
            .map(s => s.trim().toLowerCase())
            .filter(s => s.length > 0);

        if (wantedItems.length === 0) {
            alert('Bazaar Helper: No items in list.');
            return;
        }

        const btnRun = document.getElementById('bh-run');
        const originalText = btnRun.innerText;
        btnRun.innerText = "Fetching...";
        btnRun.disabled = true;

        try {
            const response = await fetch('https://api.torn.com/v2/user?selections=bazaar', {
                method: 'GET',
                headers: {
                    'accept': 'application/json',
                    'Authorization': 'ApiKey ' + apiKey
                }
            });

            if (!response.ok) {
                throw new Error('API Request Failed');
            }

            const data = await response.json();
            const currentBazaarItems = data.bazaar || [];
            const existingItemNames = new Set(currentBazaarItems.map(item => item.name.toLowerCase()));

            const itemsToProcess = wantedItems.filter(item => !existingItemNames.has(item));

            toggleModal();

            if (itemsToProcess.length === 0) {
                console.log('Bazaar Helper: All items in list are already in the bazaar.');
            }

            const itemRows = document.querySelectorAll('ul.items-cont > li');
            let processedCount = 0;

            itemRows.forEach(row => {
                const nameEl = row.querySelector('.name-wrap .t-overflow');
                if (!nameEl) return;

                const itemName = nameEl.textContent.trim().toLowerCase();

                if (itemsToProcess.includes(itemName)) {

                    const qtyInput = row.querySelector('input[name="amount"]');

                    if (qtyInput && qtyInput.type === 'checkbox') {
                        if (!qtyInput.checked) {
                            qtyInput.click();
                            processedCount++;
                        }
                    } else if (qtyInput && qtyInput.type === 'text') {
                        const qtyDisplay = row.querySelector('.thumbnail .qty');
                        if (qtyDisplay) {
                            const maxQty = qtyDisplay.textContent.replace(/,/g, '').trim();
                            if (qtyInput.value !== maxQty) {
                                setReactInput(qtyInput, 1);
                                processedCount++;
                            }
                        }
                    }

                    const priceInputs = row.querySelectorAll('input.input-money');
                    let priceInput = null;
                    priceInputs.forEach(inp => {
                        if (inp.type === 'text' && inp.placeholder === 'Price') priceInput = inp;
                    });

                    if (priceInput) {
                        setReactInput(priceInput, "1");
                    }
                }
            });

            console.log(`Bazaar Helper: Processed ${processedCount} items.`);

        } catch (error) {
            console.error(error);
            alert('Bazaar Helper: Error fetching API data. Check Key or Console.');
        } finally {
            btnRun.innerText = originalText;
            btnRun.disabled = false;
        }
    }

    init();

})();