TLDR SCANNER

Our Little Secret

// ==UserScript==
// @name         TLDR SCANNER
// @namespace    http://tampermonkey.net/
// @version      3.1
// @description  Our Little Secret
// @author       TLDR TLDR [3348219]
// @match        https://www.torn.com/page.php?sid=ItemMarket*
// @match        https://www.torn.com/imarket.php*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';
    console.log('Scanner is Starting');

    GM_addStyle(`
        #missingItemsGUI {
            position: fixed;
            top: 10px;
            right: 10px;
            background-color: #f0f0f0;
            border: 1px solid #ccc;
            padding: 10px;
            z-index: 9999;
            max-height: 80vh;
            overflow-y: auto;
        }
        #missingItemsGUI h3 { margin-top: 0; }
        #missingItemsGUI ul { list-style-type: none; padding: 0; }
        #missingItemsGUI li { margin-bottom: 5px; }
        #missingItemsGUI a { text-decoration: none; color: #0066cc; }
    `);

    function getItemInfo(itemName) {
        return new Promise((resolve, reject) => {
            console.log(`Fetching info for item: ${itemName}`);
            GM_xmlhttpRequest({
                method: "GET",
                url: `http://153.92.5.106:8080/get_item_info/${encodeURIComponent(itemName)}`,
                onload: function(response) {
                    if (response.status === 200) {
                        const items = JSON.parse(response.responseText);
                        console.log(`Parsed data for ${itemName}:`, items);
                        resolve(items);
                    } else {
                        reject(new Error(`Failed to fetch item info: ${response.statusText}`));
                    }
                },
                onerror: reject
            });
        });
    }

    function updateUserIdInDatabase(itemName, userId, damage, accuracy, armor) {
        console.log(`Updating database for item: ${itemName}, user: ${userId}, Damage: ${damage}, Accuracy: ${accuracy}, Armor: ${armor}`);
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "POST",
                url: `http://153.92.5.106:8080/update_user_id`,
                data: JSON.stringify({ itemName, userId, damage, accuracy, armor }),
                headers: { "Content-Type": "application/json" },
                timeout: 10000,
                onload: function(response) {
                    if (response.status === 200) {
                        resolve();
                    } else {
                        reject(new Error(`Failed to update database: ${response.statusText}`));
                    }
                },
                onerror: reject,
                ontimeout: () => reject(new Error('Request timed out'))
            });
        });
    }

    function getPropertyValues(itemElement) {
        const properties = itemElement.querySelectorAll('.modifiersAndPropertiesWrapper___VPWW_ .properties___QCPEP div .value___cwqHv');
        const values = [];

        properties.forEach(prop => {
            if (prop.textContent) {
                values.push(parseFloat(prop.textContent));
            }
        });

        if (values.length === 2) {
            return {
                damage: values[0],
                accuracy: values[1],
                armor: null
            };
        } else if (values.length === 1) {
            return {
                damage: null,
                accuracy: null,
                armor: values[0]
            };
        }

        return null;
    }

    function handleBuyButtonClick(event) {
        const buyButton = event.target.closest('button.actionButton___pb_Da');
        if (!buyButton) return;

        const itemElement = buyButton.closest('li');
        if (!itemElement) {
            console.warn('Could not find item element');
            return;
        }

        const itemNameElement = itemElement.querySelector('.name___ukdHN');
        if (!itemNameElement) {
            console.warn('Could not find item name element');
            return;
        }

        const itemName = itemNameElement.textContent.trim();
        const properties = getPropertyValues(itemElement);

        if (!properties) {
            console.warn('Could not find valid property values');
            return;
        }

        console.log(`Clicked item: ${itemName}, Properties:`, properties);

        const observer = new MutationObserver((mutations, obs) => {
            const anonymousElement = document.querySelector('.anonymous___P3s5s');
            if (anonymousElement) {
                obs.disconnect();
                const userId = 'Anonymous';
                getItemInfo(itemName)
                    .then(items => {
                        const matchingItems = items.filter(item => {
                            if (properties.damage !== null) {
                                return parseFloat(item.damage) === properties.damage &&
                                       parseFloat(item.accuracy) === properties.accuracy;
                            } else {
                                return parseFloat(item.armor) === properties.armor;
                            }
                        });
                        if (matchingItems.length > 0) {
                            return updateUserIdInDatabase(itemName, userId, properties.damage, properties.accuracy, properties.armor);
                        }
                    })
                    .catch(error => console.error('Error in buy button click handler:', error));
            } else {
                const sellerLinkElement = document.querySelector("#item-market-root > div > div > div.marketWrapper___S5pRm > div.itemListWrapper___dguQ9 > div.itemListWrapper___ugBOt > ul > li.sellerListWrapper___PN32N > ul > li > div > div.userInfoWrapper___B2a2P > div > div.honorWrap___BHau4.flexCenter___bV1QP.honorWrapSmall___oFibH > a");
                if (sellerLinkElement && sellerLinkElement.href.includes('profiles.php?XID=')) {
                    obs.disconnect();
                    const userId = sellerLinkElement.href.split('XID=')[1];
                    if (userId) {
                        getItemInfo(itemName)
                            .then(items => {
                                const matchingItems = items.filter(item => {
                                    if (properties.damage !== null) {
                                        return parseFloat(item.damage) === properties.damage &&
                                               parseFloat(item.accuracy) === properties.accuracy;
                                    } else {
                                        return parseFloat(item.armor) === properties.armor;
                                    }
                                });
                                if (matchingItems.length > 0) {
                                    return updateUserIdInDatabase(itemName, userId, properties.damage, properties.accuracy, properties.armor);
                                }
                            })
                            .catch(error => console.error('Error in buy button click handler:', error));
                    }
                }
            }
        });

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

    function setupBuyButtonListener() {
        document.addEventListener('click', handleBuyButtonClick);
    }

    function fetchMissingItems() {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: "http://153.92.5.106:5000/missing_items",
                onload: function(response) {
                    if (response.status === 200) {
                        resolve(JSON.parse(response.responseText));
                    } else {
                        reject(new Error(`Failed to fetch missing items: ${response.statusText}`));
                    }
                },
                onerror: reject
            });
        });
    }

    function processMissingItems(items) {
        const itemMap = new Map();
        items.forEach(item => {
            if (!itemMap.has(item.item_id)) {
                itemMap.set(item.item_id, { name: item.item_name, prices: [] });
            }
            itemMap.get(item.item_id).prices.push(item.price);
        });

        const guiElement = document.createElement('div');
        guiElement.id = 'missingItemsGUI';
        guiElement.innerHTML = '<h3>Missing Items</h3><ul></ul>';

        const listElement = guiElement.querySelector('ul');
        itemMap.forEach((item, itemId) => {
            const minPrice = Math.min(...item.prices);
            const maxPrice = Math.max(...item.prices);
            const listItem = document.createElement('li');
            const link = document.createElement('a');
            link.href = `https://www.torn.com/page.php?sid=ItemMarket#/market/view=search&itemID=${itemId}&sortField=price&sortOrder=ASC&priceFrom=${minPrice}&priceTo=${maxPrice}&bonuses[0]=-2`;
            link.textContent = item.name;
            link.target = '_blank';
            listItem.appendChild(link);
            listElement.appendChild(listItem);
        });

        document.body.appendChild(guiElement);
    }

    function initGUI() {
        fetchMissingItems()
            .then(processMissingItems)
            .catch(error => console.error('Error initializing GUI:', error));
    }

    function init() {
        setupBuyButtonListener();
        initGUI();
    }

    GM_xmlhttpRequest({
        method: "GET",
        url: "http://153.92.5.106:8080/test",
        onload: function(response) {
            if (response.status === 200) {
                console.log("Server connection test successful");
                init();
            } else {
                console.error("Server connection test failed. Status:", response.status);
            }
        },
        onerror: function(error) {
            console.error("Server connection test failed:", error);
        }
    });

    console.log('Scanner loaded');
})();