Auto Luarmor V2 (Remade!)

Automatically does Luarmor for you with smart key/button handling + options menu (auto-copy, auto-next, delay changer)

// ==UserScript==
// @name         Auto Luarmor V2 (Remade!)
// @namespace    http://tampermonkey.net/
// @license MIT
// @version      2.4
// @description  Automatically does Luarmor for you with smart key/button handling + options menu (auto-copy, auto-next, delay changer)
// @author       Aro
// @match        https://ads.luarmor.net/get_key?*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function() {
    let isPaused = false;
    let currentAction = "Idle";
    let currentKey = "N/A";
    let logHistory = [];
    const logCache = new Set();
    let firstNextClick = true;

    // Flags
    let blacklistLogged = false;
    let loaderLogged = false;
    let captchaLogged = false;
    let discordLogged = false;
    let nextBtnNotClickableLogged = false;
    let blacklistUrlLogged = false;

    // Options with defaults
    let options = {
        autoCopy: localStorage.getItem("opt_autoCopy") === "true",
        nextDelay: parseInt(localStorage.getItem("opt_nextDelay") || "3000", 10),
        reloadOnResume: localStorage.getItem("opt_reloadOnResume") !== "false", // default true
    };

    // Floating UI
    // Floating UI
    const ui = document.createElement("div");
    ui.style.cssText = `
    position: fixed; top: 20px; right: 20px; width: 250px;
    background: rgba(25,25,25,0.9); color: #fff;
    font-family: Arial,sans-serif; border-radius: 8px;
    box-shadow: 0 0 10px rgba(0,0,0,0.5);
    padding: 10px; z-index: 999999; font-size: 13px;
`;
    ui.innerHTML = `
    <div style="display: flex; justify-content: space-between; align-items: center;">
        <strong>Script Status</strong>
        <div>
            <button id="optionsBtn" style="
                background:#444;border:none;color:#fff;padding:4px 8px;
                border-radius:4px;cursor:pointer;margin-right:4px;">⚙</button>
            <button id="toggleBtn" style="
                background:#444;border:none;color:#fff;padding:4px 8px;
                border-radius:4px;cursor:pointer;">Pause</button>
        </div>
    </div>
    <div style="margin-top: 5px;">
        <b>Current Key:</b>
        <span id="keyDisplay" style="display:inline-block; max-width:220px; word-break:break-all;">
            ${currentKey}
        </span>
    </div>
    <div style="margin-top: 5px;">
        <b>Action:</b> <span id="actionDisplay">${currentAction}</span>
    </div>
    <div style="margin-top: 5px;">
        <b style="cursor:pointer;" id="logToggle">Log ▼</b>
        <div id="logAreaContainer" style="display:none; max-height:100px; overflow-y:auto;
             background:rgba(0,0,0,0.3); padding:5px; border-radius:4px; margin-top:3px;">
            <div id="logArea" style="font-size:12px;"></div>
        </div>
    </div>
    <div id="optionsMenu" style="display:none; margin-top:10px; padding:5px;
        background:rgba(0,0,0,0.4); border-radius:6px;">
        <label><input type="checkbox" id="opt_autoCopy"> Auto-copy Key</label><br>
        <label><input type="checkbox" id="opt_reloadOnResume"> Reload on Resume</label><br>
        <label>Next Delay (ms):
            <input type="number" id="opt_nextDelay" style="width:80px;">
        </label><br>
        <button id="saveOptions" style="
            margin-top:5px; background:#555; color:#fff; border:none;
            border-radius:4px; padding:3px 6px; cursor:pointer;">Save</button>
    </div>
`;
    document.body.appendChild(ui);

    // UI elements
    const toggleBtn = ui.querySelector("#toggleBtn");
    const optionsBtn = ui.querySelector("#optionsBtn");
    const optionsMenu = ui.querySelector("#optionsMenu");
    const keyDisplay = ui.querySelector("#keyDisplay");
    const actionDisplay = ui.querySelector("#actionDisplay");
    const logArea = ui.querySelector("#logArea");
    const logToggle = ui.querySelector("#logToggle");
    const logAreaContainer = ui.querySelector("#logAreaContainer");

    // Initialize options UI
    ui.querySelector("#opt_autoCopy").checked = options.autoCopy;
    ui.querySelector("#opt_nextDelay").value = options.nextDelay;
    ui.querySelector("#opt_reloadOnResume").checked = options.reloadOnResume;

    // Toggle pause/resume
    toggleBtn.addEventListener("click", () => {
        isPaused = !isPaused;
        toggleBtn.textContent = isPaused ? "Resume" : "Pause";
        if (isPaused) {
            log("Script paused");
        } else {
            log("Script resumed");
            if (options.reloadOnResume) {
                log("Reloading page...");
                location.reload();
            } else {
                onLoad();
            }
        }
    });

    // Options open/close
    optionsBtn.addEventListener("click", () => {
        optionsMenu.style.display = optionsMenu.style.display === "none" ? "block" : "none";
    });

    // Save options
    ui.querySelector("#saveOptions").addEventListener("click", () => {
        options.autoCopy = ui.querySelector("#opt_autoCopy").checked;
        options.nextDelay = parseInt(ui.querySelector("#opt_nextDelay").value, 10) || 3000;
        options.reloadOnResume = ui.querySelector("#opt_reloadOnResume").checked;

        localStorage.setItem("opt_autoCopy", options.autoCopy);
        localStorage.setItem("opt_nextDelay", options.nextDelay);
        localStorage.setItem("opt_reloadOnResume", options.reloadOnResume);

        log("Options saved");
    });

    // Log toggle
    logToggle.addEventListener("click", () => {
        const isHidden = logAreaContainer.style.display === "none";
        logAreaContainer.style.display = isHidden ? "block" : "none";
        logToggle.textContent = isHidden ? "Log ▲" : "Log ▼";
    });

    // Logger
    function log(message) {
        if (logCache.has(message)) return;
        logCache.add(message);
        const timestamp = new Date().toLocaleTimeString();
        logHistory.unshift(`[${timestamp}] ${message}`);
        if (logHistory.length > 100) logHistory.pop();
        logArea.innerHTML = logHistory.join("<br>");
        console.log(message);
        setTimeout(() => logCache.delete(message), 5000);
    }

    function setAction(action) {
        currentAction = action;
        actionDisplay.textContent = action;
        log(action);
    }

    function setKey(key) {
        currentKey = key;
        keyDisplay.textContent = key;
        if (options.autoCopy) {
            navigator.clipboard.writeText(key).then(() => log("Key copied to clipboard"));
        }
    }

    // Block detection
    function isBlocked() {
        const blacklist = document.querySelector('.swal2-x-mark');
        const loader = document.querySelector('.loader');
        const captcha = document.getElementById('captchafield');
        const discord = document.querySelector('h2.swal2-title#swal2-title');

        const blacklistVisible = blacklist && blacklist.offsetParent !== null;
        const loaderVisible = loader && loader.offsetParent !== null;
        const captchaVisible = captcha && captcha.offsetParent !== null;
        const discordVisible = discord && discord.textContent.includes("Log In with Discord");
        const blacklistUrl = window.location.href.includes("ads.luarmor.net/Blacklisted");

        if (blacklistUrl) {
            if (!blacklistUrlLogged) {
                setAction("Waiting (blacklisted URL)...");
                blacklistUrlLogged = true;
            }
            return true;
        } else blacklistUrlLogged = false;

        if (blacklistVisible) {
            if (!blacklistLogged) {
                setAction("Waiting (blacklisted)...");
                blacklistLogged = true;
            }
            return true;
        } else blacklistLogged = false;

        if (loaderVisible) {
            if (!loaderLogged) {
                setAction("Waiting for loader...");
                loaderLogged = true;
            }
            return true;
        } else loaderLogged = false;

        if (captchaVisible) {
            if (!captchaLogged) {
                setAction("Waiting for captcha...");
                captchaLogged = true;
            }
            return true;
        } else captchaLogged = false;

        if (discordVisible) {
            if (!discordLogged) {
                setAction("Waiting for Discord login...");
                discordLogged = true;
            }
            return true;
        } else discordLogged = false;

        return false;
    }

    function grabKeyOnce() {
        if (currentKey !== "N/A") return;
        const keyElement = document.querySelector('h6.mb-0.text-sm');
        if (keyElement) {
            const keyText = keyElement.textContent.trim();
            if (keyText) {
                setKey(keyText);
                log(`Key grabbed: ${keyText}`);
            }
        }
    }

    function onLoad() {
        if (isPaused) return setAction("Paused");
        if (isBlocked()) return setTimeout(onLoad, 500);

        grabKeyOnce();
        checkProgress();

        // ✅ only schedule first run
        if (!onLoad.started) {
            setTimeout(clickNextLoop, options.nextDelay);
            onLoad.started = true; // prevent double scheduling
        }
    }

    function checkProgress() {
        if (isPaused) return setAction("Paused");
        if (isBlocked()) return;

        const progressElement = document.getElementById('adprogressp');
        if (!progressElement) return;
        const progressText = progressElement.textContent;
        const progressParts = progressText.match(/(\d+)\/(\d+)/);
        if (!progressParts) return;
        const currentProgress = parseInt(progressParts[1], 10);
        const totalProgress = parseInt(progressParts[2], 10);
        const remainingProgress = totalProgress - currentProgress;
        setAction(`Remaining Progress: ${remainingProgress}`);

        if (remainingProgress === 0) {
            const keyElement = document.querySelector('h6.mb-0.text-sm');
            const addTimeBtn = keyElement ? document.getElementById(`addtimebtn_${keyElement.textContent.trim()}`) : null;
            const newKeyBtn = document.getElementById('newkeybtn');

            if (keyElement && addTimeBtn && addTimeBtn.offsetParent !== null && !addTimeBtn.disabled) {
                addTimeBtn.click();
                setAction(`Clicked Add Time for key: ${keyElement.textContent.trim()}`);
            } else if (newKeyBtn && newKeyBtn.offsetParent !== null && !newKeyBtn.disabled) {
                newKeyBtn.click();
                setAction("Clicked Get a New Key");
            }
        }
    }

    function clickNextLoop() {
        if (isPaused) return setAction("Paused");
        if (isBlocked()) return setTimeout(clickNextLoop, 500);

        const btn = document.getElementById('nextbtn');
        if (btn && btn.offsetParent !== null && !(btn.style.cursor === 'not-allowed' || btn.disabled)) {

            if (firstNextClick) {
                btn.click();
                setAction("Clicked Next button (first)");

                // 🔎 Defer focus check to let browser update focus
                setTimeout(() => {
                    if (!document.hasFocus()) {
                        setAction("Focused Ad Tab");
                        return;
                    }
                    firstNextClick = false;
                    setTimeout(clickNextLoop, options.nextDelay);
                }, 0);

            } else {
                if (!document.hasFocus()) {
                    setAction("Focused Ad Tab");
                    return;
                }

                btn.click();
                setAction("Clicked Next button");
                setTimeout(clickNextLoop, options.nextDelay);
            }

        } else {
            if (!nextBtnNotClickableLogged) {
                setAction("Waiting to click button");
                nextBtnNotClickableLogged = true;
            }
            setTimeout(clickNextLoop, 500);
        }
    }

    if (document.readyState === "complete") {
        onLoad();
    } else {
        window.addEventListener("load", onLoad, {
            once: true
        });
    }
})();