PoE2 Against the Darkness Search Helper

Adds a floating control window for PoE2 trade site to find modifiers on against the darkness jewels.load results.

目前為 2025-01-16 提交的版本,檢視 最新版本

// ==UserScript==
// @name         PoE2 Against the Darkness Search Helper
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Adds a floating control window for PoE2 trade site to find modifiers on against the darkness jewels.load results.
// @author       Qinsoon
// @match        https://www.pathofexile.com/trade2/search/poe2*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    let targetResultCount = 100; // Default target result count
    let highlightedResults = []; // Store highlighted results
    let currentHighlightIndex = -1; // Track current highlighted result

    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    function createFloatingWindow() {
        const floatingWindow = document.createElement('div');
        floatingWindow.id = 'floating-window';
        floatingWindow.style.position = 'fixed';
        floatingWindow.style.top = '10px';
        floatingWindow.style.right = '10px';
        floatingWindow.style.width = '300px';
        floatingWindow.style.backgroundColor = 'white';
        floatingWindow.style.border = '1px solid black';
        floatingWindow.style.padding = '10px';
        floatingWindow.style.zIndex = '9999';
        floatingWindow.style.display = 'none'; // Initially hidden

        floatingWindow.innerHTML = `
            <h4>POE2 Against the Darkness Search Helper</h4>
            <p>You are searching for Against the Darkness. Fill in the mods below and click "Search" to find matching items.</p>
            <label>Mod 1: <input type="text" id="mod1" placeholder="Enter keyword" style="width: 90%;" value="mana" /></label><br>
            <label>Mod 2: <input type="text" id="mod2" placeholder="Enter keyword" style="width: 90%;" value="intelligence" /></label><br>
            <button id="search-button">Search</button>
            <button id="prev-button" disabled>Prev</button>
            <button id="next-button" disabled>Next</button>
            <button id="close-button">Close</button><br>
            <p>Total Results: <span id="total-results">0</span></p>
            <p>Highlighted Results: <span id="highlighted-results">0</span></p>
        `;

        document.body.appendChild(floatingWindow);

        document.getElementById('search-button').addEventListener('click', () => {
            highlightedResults = [];
            currentHighlightIndex = -1;
            loadResults();
        });

        document.getElementById('prev-button').addEventListener('click', () => {
            navigateHighlights(-1);
        });

        document.getElementById('next-button').addEventListener('click', () => {
            navigateHighlights(1);
        });

        document.getElementById('close-button').addEventListener('click', () => {
            document.getElementById('floating-window').style.display = 'none';
            monitorPage(); // Re-enable the observer to reopen the window when the condition is met
        });
    }

    function monitorPage() {
        const observer = new MutationObserver(() => {
            const items = document.querySelectorAll('.itemBoxContent');
            for (const item of items) {
                const headerText = item.querySelector('.itemHeader')?.innerText || '';
                if (headerText.includes('Against the Darkness') && headerText.includes('Time-Lost Diamond')) {
                    document.getElementById('floating-window').style.display = 'block';
                    return;
                }
            }
        });

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

    async function loadResults() {
        let loadedResults = 0;
        let emptyLoadCounter = 0; // Track consecutive empty loads

        while (loadedResults < targetResultCount) {
            const loadMoreButton = document.querySelector('button.btn.load-more-btn');

            if (loadMoreButton) {
                console.log("Clicking Load More button...");
                loadMoreButton.click();
            } else {
                console.log("Load More button not found, stopping further loading.");
                break;
            }

            await sleep(1000); // Wait for results to load

            const newLoadedResults = document.querySelectorAll('.itemBoxContent').length;
            if (newLoadedResults === loadedResults) {
                emptyLoadCounter++;
                console.log(`No new results loaded (${emptyLoadCounter}/10).`);

                if (emptyLoadCounter >= 10) {
                    console.log("Max empty loads reached. Stopping loop.");
                    break;
                }
            } else {
                emptyLoadCounter = 0; // Reset counter if new results are loaded
            }

            loadedResults = newLoadedResults;
            document.getElementById('total-results').textContent = loadedResults;
            console.log(`Loaded results: ${loadedResults}`);

            // Search for adjacent mods during the loop
            searchAdjacentModsByItem();

            if (loadedResults >= targetResultCount) {
                break;
            }
        }

        updateNavigationButtons();
    }

    function searchAdjacentModsByItem() {
        const items = document.querySelectorAll('.itemBoxContent'); // Group mods by .itemBoxContent
        const mod1 = document.getElementById('mod1').value.toLowerCase();
        const mod2 = document.getElementById('mod2').value.toLowerCase();

        highlightedResults = []; // Clear previous results

        items.forEach(item => {
            const mods = item.querySelectorAll('.explicitMod');
            if (mods.length < 2) return; // Skip if fewer than 2 mods

            for (let i = 0; i < mods.length - 1; i++) {
                const currentMod = mods[i].innerText.toLowerCase();
                const nextMod = mods[i + 1].innerText.toLowerCase();

                if ((currentMod.includes(mod1) && nextMod.includes(mod2)) ||
                    (currentMod.includes(mod2) && nextMod.includes(mod1))) {
                    item.style.border = "2px solid red"; // Highlight the item
                    highlightedResults.push(item);
                    break; // Stop checking further mods in this item
                }
            }
        });

        document.getElementById('highlighted-results').textContent = highlightedResults.length;
        updateNavigationButtons();
    }

    function navigateHighlights(direction) {
        if (highlightedResults.length === 0) return;

        currentHighlightIndex += direction;
        if (currentHighlightIndex < 0) {
            currentHighlightIndex = highlightedResults.length - 1;
        } else if (currentHighlightIndex >= highlightedResults.length) {
            currentHighlightIndex = 0;
        }

        const currentElement = highlightedResults[currentHighlightIndex];
        currentElement.scrollIntoView({ behavior: "smooth", block: "center" });
        currentElement.style.backgroundColor = "yellow";

        console.log(`Navigated to result ${currentHighlightIndex + 1}/${highlightedResults.length}`);
    }

    function updateNavigationButtons() {
        const prevButton = document.getElementById('prev-button');
        const nextButton = document.getElementById('next-button');

        if (highlightedResults.length > 0) {
            prevButton.disabled = false;
            nextButton.disabled = false;
        } else {
            prevButton.disabled = true;
            nextButton.disabled = true;
        }
    }

    (function () {
        console.log("Starting script...");
        createFloatingWindow();
        monitorPage();
    })();
})();