EarnBitMoon Auto Claim

Auto faucet claim and bonus with smart click.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         EarnBitMoon Auto Claim
// @namespace    http://tampermonkey.net/
// @version      2.1
// @description  Auto faucet claim and bonus with smart click.
// @author       Rubystance
// @license      MIT
// @match        https://earnbitmoon.club/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    const MIN_DELAY = 1000;
    const MAX_DELAY = 3000;
    const CAPTCHA_TIMEOUT = 60000;
    const RESULT_TIMEOUT = 20000;
    const HARD_RELOAD_INTERVAL = 5 * 60 * 1000;

    let alreadyClicked = false;

    const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
    const randomDelay = () => sleep(Math.floor(Math.random() * (MAX_DELAY - MIN_DELAY + 1)) + MIN_DELAY);

    const smartClick = async (el, label = 'button') => {
        if (!el) return;
        try {
            const eventResult = el.dispatchEvent(new MouseEvent('click', {
                bubbles: true,
                cancelable: true,
                view: window
            }));
            if (!eventResult) throw new Error('dispatchEvent blocked');
            console.log(`[EarnBitMoon] Smart click (dispatch) on ${label}`);
        } catch (err) {
            console.warn(`[EarnBitMoon] dispatchEvent failed on ${label}, falling back to .click()`);
            try {
                el.click();
                console.log(`[EarnBitMoon] Fallback click() successful on ${label}`);
            } catch (e2) {
                console.error(`[EarnBitMoon] Both click methods failed on ${label}`, e2);
            }
        }
    };

    const isCaptchaSolved = () => {
        const turnstile = document.querySelector('input[name="cf-turnstile-response"]');
        const recaptcha = document.querySelector('#g-recaptcha-response');
        const hcaptcha = document.querySelector('textarea[name="h-captcha-response"]');
        const icon = document.querySelector('.iconcaptcha-wrap.solved, .iconcaptcha-done');
        return (
            (turnstile && turnstile.value.length > 10) ||
            (recaptcha && recaptcha.value.length > 10) ||
            (hcaptcha && hcaptcha.value.length > 10) ||
            icon
        );
    };

    const isButtonClickable = btn => {
        if (!btn) return false;
        const style = window.getComputedStyle(btn);
        return (
            style.display !== 'none' &&
            style.visibility !== 'hidden' &&
            style.opacity !== '0' &&
            !btn.disabled &&
            btn.offsetParent !== null
        );
    };

    async function waitForCaptchaAndPress() {
        console.log('[EarnBitMoon] Waiting for CAPTCHA and "Press & Win"...');
        const startTime = Date.now();

        while (Date.now() - startTime < CAPTCHA_TIMEOUT) {
            const pressBtn = document.querySelector('button.zxz');

            if (isCaptchaSolved() && isButtonClickable(pressBtn) && !alreadyClicked) {
                console.log('[EarnBitMoon] CAPTCHA solved. Claiming reward...');
                alreadyClicked = true;
                await randomDelay();
                await smartClick(pressBtn, '"Press & Win"');
                waitForResultOrReload();
                return;
            }

            await sleep(5000);
        }

        console.warn('[EarnBitMoon] CAPTCHA timeout. Reloading...');
        location.reload();
    }

    async function waitForResultOrReload() {
        console.log('[EarnBitMoon] Waiting for claim result...');
        const start = Date.now();

        while (Date.now() - start < RESULT_TIMEOUT) {
            const restartBtn = document.querySelector('.fa-rotate-right');
            const closeBtn = document.querySelector('.fa-xmark');

            if (restartBtn) {
                console.log('[EarnBitMoon] Claim successful.');
                return;
            }

            if (closeBtn && !restartBtn) {
                console.warn('[EarnBitMoon] Only close button visible. Reloading...');
                location.reload();
                return;
            }

            await sleep(2000);
        }

        console.warn('[EarnBitMoon] No result after timeout. Reloading...');
        location.reload();
    }

    async function clickRollNow() {
        await randomDelay();
        const rollBtn = [...document.querySelectorAll('button')].find(btn =>
            btn.innerText.includes('ROLL NOW') && btn.dataset.toggle === "modal"
        );
        if (rollBtn) {
            console.log('[EarnBitMoon] Clicking "ROLL NOW"...');
            await smartClick(rollBtn, '"ROLL NOW"');
        } else {
            console.warn('[EarnBitMoon] "ROLL NOW" button not found.');
        }
    }

    async function checkAndGoToBonus() {
        const bonusLink = [...document.querySelectorAll('a.btn')].find(a =>
            a.innerText.includes('Daily Bonus') && a.innerText.includes('1')
        );

        if (bonusLink) {
            console.log('[EarnBitMoon] Daily Bonus available. Going to bonus page...');
            bonusLink.click();
            return true;
        }

        return false;
    }

    async function handleBonusPage() {
        console.log('[EarnBitMoon] On bonus page...');
        const start = Date.now();

        while (Date.now() - start < 15000) {
            const claimBtn = [...document.querySelectorAll('button')].find(btn =>
                btn.innerText.includes('CLAIM DAILY BONUS')
            );

            if (claimBtn) {
                console.log('[EarnBitMoon] Clicking "CLAIM DAILY BONUS"...');
                await randomDelay();
                await smartClick(claimBtn, '"CLAIM DAILY BONUS"');

                const modalStart = Date.now();
                while (Date.now() - modalStart < 10000) {
                    const innerClaim = document.querySelector('#dailyBonus');
                    if (innerClaim) {
                        console.log('[EarnBitMoon] Clicking "Claim Coins"...');
                        await randomDelay();
                        await smartClick(innerClaim, '"Claim Coins"');
                        await sleep(4000);
                        location.href = '/faucet.html';
                        return;
                    }
                    await sleep(1000);
                }

                console.warn('[EarnBitMoon] "Claim Coins" button not found. Reloading...');
                location.reload();
                return;
            }

            await sleep(1000);
        }

        console.warn('[EarnBitMoon] Bonus claim button not detected. Returning to faucet...');
        location.href = '/faucet.html';
    }

    function hardReloadTimer() {
        setTimeout(() => {
            console.log('[EarnBitMoon] Hard reload triggered after 5 minutes.');
            location.reload();
        }, HARD_RELOAD_INTERVAL);
    }

    async function main() {
        console.log(`[EarnBitMoon] Current page: ${location.pathname}`);

        if (location.pathname === '/bonus.html') {
            await handleBonusPage();
            return;
        }

        const wentToBonus = await checkAndGoToBonus();
        if (wentToBonus) return;

        await sleep(2000);
        await clickRollNow();
        await waitForCaptchaAndPress();
        hardReloadTimer();
    }

    window.addEventListener('load', main);
})();