AntiCaptcha & uCaptcha Solver

Menangani AntiCaptcha (chillfaucet.in/offerzono.com) dan uCaptcha (litoshipay.com/claimlitoshi.top)

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==UserScript==
// @name               AntiCaptcha & uCaptcha Solver
// @namespace          http://tampermonkey.net/ http://violentmonkey.net
// @version            1.0
// @description        Menangani AntiCaptcha (chillfaucet.in/offerzono.com) dan uCaptcha (litoshipay.com/claimlitoshi.top)
// @author             OjoNgono
// @match              https://chillfaucet.in/*
// @match              https://offerzono.com/*
// @match              https://litoshipay.com/*
// @match              https://claimlitoshi.top/*
// @grant              none
// @run-at             document-end
// @icon               https://i.ibb.co/XJSPdz0/large.png
// @license            Copyright of OjoNgono
// ==/UserScript==

(function() {
    'use strict';

    // ========== DETEKSI JENIS SITUS ==========
    const currentUrl = window.location.hostname;
    const isAntiCaptchaSite = currentUrl.includes('chillfaucet.in') || currentUrl.includes('offerzono.com');
    const isUCaptchaSite = currentUrl.includes('litoshipay.com') || currentUrl.includes('claimlitoshi.top');

    console.log(`Combined Captcha Solver: Running on ${currentUrl} (${isAntiCaptchaSite ? 'AntiCaptcha' : isUCaptchaSite ? 'uCaptcha' : 'Unknown'})`);

    // ========== ANTI-CAPTCHA SECTION ==========
    if (isAntiCaptchaSite) {
        // ========== ANTI-CAPTCHA SETTING ==========
        const WEIGHTS = {
            ssim: 44,
            contour: 3,
            color: 12,
            edge: 13,
            template: 8,
            histogram: 20
        };

        const ANTI_CONFIG = {
            weights: WEIGHTS,
            autoStart: true,
            maxRetries: 5,
            maxSessionRetries: 3,
            retryDelay: 2000,
            checkboxDelay: 1500,
            errorCheckDelay: 1000,
            refreshDelay: 3000,
            debugMode: false,
            boxTimeout: 25000 // 25 detik timeout untuk anticap-box
        };

        let isProcessing = false;
        let retryCount = 0;
        let sessionRetryCount = 0;
        let captchaSolved = false;
        let errorObserver = null;
        let boxTimeoutId = null;

        // ========== ANTI-CAPTCHA UTILITY ==========
        function wait(ms) {
            return new Promise(resolve => setTimeout(resolve, ms));
        }

        // ========== ANTI-CAPTCHA FUNGSI SCROLL ==========
        function scrollToAnticapBox() {
            const anticapBox = document.querySelector('[data-id="anticap-box"]');
            if (anticapBox) {
                anticapBox.scrollIntoView({
                    behavior: 'smooth',
                    block: 'center',
                    inline: 'center'
                });
                return true;
            }
            return false;
        }

        // ========== ANTI-CAPTCHA FUNGSI REFRESH ==========
        function refreshAnticapBox() {
            console.log('AntiCaptcha: Timeout 25 detik, merefresh anticap-box...');

            // Cari tombol refresh atau reload captcha
            const refreshButton = document.querySelector('[data-id="anticap-refresh"], .anticap-refresh, button[onclick*="refresh"]');
            if (refreshButton) {
                refreshButton.click();
                return true;
            }

            // Alternatif: reload halaman jika tidak ada tombol refresh
            location.reload();
            return false;
        }

        // ========== ANTI-CAPTCHA FUNGSI CEK STATUS ==========
        function checkAntiCaptchaStatus() {
            const feedback = document.querySelector('[data-id="anticap-feedback"]');
            if (feedback) {
                const text = feedback.textContent || '';
                if (text.includes('Success') || text.includes('success')) {
                    return 'success';
                }
                if (text.includes('Error') || text.includes('error') || text.includes('Wrong')) {
                    return 'error';
                }
            }

            // Cek juga dari info label
            const infoLabel = document.querySelector('[data-id="anticap-info-label"]');
            if (infoLabel) {
                const text = infoLabel.textContent || '';
                if (text.includes('Success')) return 'success';
                if (text.includes('Error')) return 'error';
            }

            return 'unknown';
        }

        // ========== ANTI-CAPTCHA FUNGSI MONITOR TIMEOUT ==========
        function startAntiCaptchaTimeoutMonitor() {
            // Hapus timeout sebelumnya jika ada
            if (boxTimeoutId) {
                clearTimeout(boxTimeoutId);
            }

            // Set timeout baru
            boxTimeoutId = setTimeout(async () => {
                const status = checkAntiCaptchaStatus();

                // Jika masih unknown (tidak ada respon success/error) setelah 25 detik
                if (status === 'unknown' && !captchaSolved) {
                    console.log('AntiCaptcha: Box tidak merespon selama 25 detik');

                    // Reset processing state
                    isProcessing = false;

                    // Refresh box
                    refreshAnticapBox();

                    // Tunggu sebentar lalu coba lagi
                    await wait(3000);
                    if (!captchaSolved && !isProcessing) {
                        solveAntiCaptcha();
                    }
                }

                boxTimeoutId = null;
            }, ANTI_CONFIG.boxTimeout);
        }

        // ========== ANTI-CAPTCHA ERROR DETECTION ==========
        function checkAntiCaptchaError() {
            const feedback = document.querySelector('[data-id="anticap-feedback"]');
            if (feedback && feedback.classList.contains('error')) {
                const errorText = feedback.textContent || '';
                if (errorText.includes('Wrong selection') || errorText.includes('Try again')) {
                    return true;
                }
            }

            const captchaRoot = document.querySelector('[data-id="anticap-root"]');
            if (captchaRoot && captchaSolved) {
                return true;
            }

            return false;
        }

        async function waitForAntiCaptchaError() {
            const startTime = Date.now();
            const timeout = 5000;

            while (Date.now() - startTime < timeout) {
                if (checkAntiCaptchaError()) {
                    return true;
                }
                await wait(500);
            }
            return false;
        }

        // ========== ANTI-CAPTCHA REFRESH PAGE ==========
        function refreshAntiCaptchaPage() {
            sessionRetryCount++;
            captchaSolved = false;
            isProcessing = false;

            if (errorObserver) {
                errorObserver.disconnect();
            }

            if (boxTimeoutId) {
                clearTimeout(boxTimeoutId);
            }

            location.reload();
        }

        // ========== ANTI-CAPTCHA CHECKBOX CLICK ==========
        async function findAndClickAntiCaptchaCheckbox() {
            // Scroll ke box terlebih dahulu
            scrollToAnticapBox();
            await wait(500); // Tunggu scroll selesai

            const checkbox = document.querySelector('input[data-id="anticap-checkbox"]');
            if (checkbox && !checkbox.disabled) {
                checkbox.click();
                checkbox.dispatchEvent(new Event('change', { bubbles: true }));
                checkbox.dispatchEvent(new Event('input', { bubbles: true }));

                ['mousedown', 'mouseup', 'click'].forEach(eventType => {
                    checkbox.dispatchEvent(new MouseEvent(eventType, {
                        view: window,
                        bubbles: true,
                        cancelable: true
                    }));
                });

                return true;
            }

            const toggleLabel = document.querySelector('.anticap-toggle');
            if (toggleLabel) {
                toggleLabel.click();
                return true;
            }

            const elements = document.querySelectorAll('span, div, label');
            for (let el of elements) {
                if (el.textContent && el.textContent.includes('I\'m not a robot')) {
                    el.click();
                    return true;
                }
            }

            return false;
        }

        // ========== ANTI-CAPTCHA GRID DETECTION ==========
        async function waitForAntiCaptchaGrid(timeout = 8000) {
            const startTime = Date.now();

            while (Date.now() - startTime < timeout) {
                const grid = document.querySelector('[data-id="anticap-grid"]');
                if (grid && grid.children.length > 0) {
                    return grid;
                }
                await wait(300);
            }

            return null;
        }

        // ========== ANTI-CAPTCHA IMAGE PROCESSING ==========
        async function loadImage(src, size = 128) {
            return new Promise((resolve, reject) => {
                const img = new Image();
                img.crossOrigin = 'Anonymous';
                img.onload = () => {
                    const canvas = document.createElement('canvas');
                    canvas.width = size;
                    canvas.height = size;
                    const ctx = canvas.getContext('2d');
                    ctx.drawImage(img, 0, 0, size, size);
                    resolve(ctx.getImageData(0, 0, size, size));
                };
                img.onerror = reject;
                img.src = src;
            });
        }

        // SSIM
        function calculateSSIM(img1, img2) {
            let mssim = 0;
            let windows = 0;

            for (let y = 0; y < 128 - 8; y += 4) {
                for (let x = 0; x < 128 - 8; x += 4) {
                    let mu1 = 0, mu2 = 0, sigma1 = 0, sigma2 = 0, sigma12 = 0;

                    for (let wy = 0; wy < 8; wy++) {
                        for (let wx = 0; wx < 8; wx++) {
                            const idx = ((y + wy) * 128 + (x + wx)) * 4;
                            const val1 = (img1.data[idx] + img1.data[idx+1] + img1.data[idx+2]) / 3;
                            const val2 = (img2.data[idx] + img2.data[idx+1] + img2.data[idx+2]) / 3;

                            mu1 += val1;
                            mu2 += val2;
                        }
                    }

                    mu1 /= 64;
                    mu2 /= 64;

                    for (let wy = 0; wy < 8; wy++) {
                        for (let wx = 0; wx < 8; wx++) {
                            const idx = ((y + wy) * 128 + (x + wx)) * 4;
                            const val1 = (img1.data[idx] + img1.data[idx+1] + img1.data[idx+2]) / 3;
                            const val2 = (img2.data[idx] + img2.data[idx+1] + img2.data[idx+2]) / 3;

                            sigma1 += Math.pow(val1 - mu1, 2);
                            sigma2 += Math.pow(val2 - mu2, 2);
                            sigma12 += (val1 - mu1) * (val2 - mu2);
                        }
                    }

                    sigma1 = Math.sqrt(sigma1 / 63);
                    sigma2 = Math.sqrt(sigma2 / 63);
                    sigma12 /= 63;

                    const c1 = 0.01 * 255;
                    const c2 = 0.03 * 255;

                    const ssim = ((2 * mu1 * mu2 + c1) * (2 * sigma12 + c2)) /
                                ((mu1 * mu1 + mu2 * mu2 + c1) * (sigma1 * sigma1 + sigma2 * sigma2 + c2));

                    if (!isNaN(ssim)) {
                        mssim += ssim;
                        windows++;
                    }
                }
            }

            return windows > 0 ? mssim / windows : 0;
        }

        // Contour detection
        function detectContours(img) {
            const width = 128;
            const height = 128;
            const binary = new Array(width * height);

            for (let i = 0; i < img.data.length; i += 4) {
                const gray = (img.data[i] + img.data[i+1] + img.data[i+2]) / 3;
                binary[i/4] = gray < 128 ? 1 : 0;
            }

            let contourCount = 0;
            const visited = new Array(width * height).fill(false);

            for (let y = 1; y < height - 1; y++) {
                for (let x = 1; x < width - 1; x++) {
                    const idx = y * width + x;
                    if (binary[idx] === 1 && !visited[idx]) {
                        contourCount++;
                        const stack = [{x, y}];
                        while (stack.length) {
                            const p = stack.pop();
                            const pIdx = p.y * width + p.x;
                            if (p.x < 0 || p.x >= width || p.y < 0 || p.y >= height) continue;
                            if (visited[pIdx] || binary[pIdx] !== 1) continue;

                            visited[pIdx] = true;

                            stack.push({x: p.x+1, y: p.y});
                            stack.push({x: p.x-1, y: p.y});
                            stack.push({x: p.x, y: p.y+1});
                            stack.push({x: p.x, y: p.y-1});
                        }
                    }
                }
            }

            return contourCount;
        }

        // Color similarity
        function calculateColorSimilarity(img1, img2) {
            let diff = 0;
            const samples = 800;
            const step = Math.floor(img1.data.length / 4 / samples) * 4;

            for (let i = 0; i < img1.data.length; i += step) {
                const rDiff = Math.abs(img1.data[i] - img2.data[i]);
                const gDiff = Math.abs(img1.data[i+1] - img2.data[i+1]);
                const bDiff = Math.abs(img1.data[i+2] - img2.data[i+2]);
                diff += (rDiff + gDiff + bDiff) / 3;
            }

            return 1 - (diff / (255 * samples));
        }

        // Edge detection
        function detectEdges(img) {
            let edgeCount = 0;
            for (let y = 1; y < 127; y++) {
                for (let x = 1; x < 127; x++) {
                    const idx = (y * 128 + x) * 4;
                    const left = (img.data[((y) * 128 + (x-1)) * 4] +
                                 img.data[((y) * 128 + (x-1)) * 4 + 1] +
                                 img.data[((y) * 128 + (x-1)) * 4 + 2]) / 3;
                    const right = (img.data[((y) * 128 + (x+1)) * 4] +
                                  img.data[((y) * 128 + (x+1)) * 4 + 1] +
                                  img.data[((y) * 128 + (x+1)) * 4 + 2]) / 3;
                    if (Math.abs(left - right) > 30) edgeCount++;
                }
            }
            return edgeCount;
        }

        // Template matching
        function templateMatching(img1, img2) {
            let bestScore = 0;
            for (let y = 0; y <= 64; y += 8) {
                for (let x = 0; x <= 64; x += 8) {
                    let score = 0;
                    for (let ty = 0; ty < 64; ty += 2) {
                        for (let tx = 0; tx < 64; tx += 2) {
                            const pIdx = (ty * 128 + tx) * 4;
                            const gIdx = ((y + ty) * 128 + (x + tx)) * 4;
                            const rDiff = Math.abs(img1.data[pIdx] - img2.data[gIdx]);
                            const gDiff = Math.abs(img1.data[pIdx+1] - img2.data[gIdx+1]);
                            const bDiff = Math.abs(img1.data[pIdx+2] - img2.data[gIdx+2]);
                            score += (255*3 - (rDiff + gDiff + bDiff)) / (255*3);
                        }
                    }
                    bestScore = Math.max(bestScore, score / (32*32));
                }
            }
            return bestScore;
        }

        // Histogram
        function calculateHistogram(img) {
            const hist = new Array(48).fill(0);
            for (let i = 0; i < img.data.length; i += 4) {
                const r = Math.floor(img.data[i] / 32);
                const g = Math.floor(img.data[i+1] / 32);
                const b = Math.floor(img.data[i+2] / 32);
                hist[r]++;
                hist[16 + g]++;
                hist[32 + b]++;
            }
            return hist;
        }

        function compareHistogram(h1, h2) {
            let sim = 0;
            for (let i = 0; i < 48; i++) {
                const max = Math.max(h1[i], h2[i], 1);
                sim += 1 - Math.abs(h1[i] - h2[i]) / max;
            }
            return sim / 48;
        }

        // ========== ANTI-CAPTCHA MAIN SOLVER ==========
        async function solveAntiCaptcha() {
            if (isProcessing || captchaSolved) return;
            if (sessionRetryCount >= ANTI_CONFIG.maxSessionRetries) {
                return;
            }

            isProcessing = true;

            // Mulai monitor timeout untuk box
            startAntiCaptchaTimeoutMonitor();

            try {
                await findAndClickAntiCaptchaCheckbox();
                await wait(ANTI_CONFIG.checkboxDelay);

                const grid = await waitForAntiCaptchaGrid();
                if (!grid) {
                    throw new Error('Grid tidak muncul');
                }

                const previewImg = document.querySelector('.anticap-preview');
                if (!previewImg) {
                    throw new Error('Preview tidak ditemukan');
                }

                const previewData = await loadImage(previewImg.src, 128);
                const previewContours = detectContours(previewData);
                const previewEdges = detectEdges(previewData);
                const previewHist = calculateHistogram(previewData);
                const items = Array.from(grid.querySelectorAll('.anticap-item img'));
                const matches = [];

                for (let i = 0; i < items.length; i++) {
                    try {
                        const gridData = await loadImage(items[i].src, 128);

                        const ssim = calculateSSIM(previewData, gridData);
                        const contour = 1 - (Math.abs(previewContours - detectContours(gridData)) / Math.max(previewContours, 1));
                        const color = calculateColorSimilarity(previewData, gridData);
                        const edge = 1 - (Math.abs(previewEdges - detectEdges(gridData)) / Math.max(previewEdges, 1));
                        const template = templateMatching(previewData, gridData);
                        const histogram = compareHistogram(previewHist, calculateHistogram(gridData));

                        const totalWeight = (WEIGHTS.ssim + WEIGHTS.contour + WEIGHTS.color +
                                            WEIGHTS.edge + WEIGHTS.template + WEIGHTS.histogram) / 100;

                        const score = (
                            (ssim * WEIGHTS.ssim) +
                            (contour * WEIGHTS.contour) +
                            (color * WEIGHTS.color) +
                            (edge * WEIGHTS.edge) +
                            (template * WEIGHTS.template) +
                            (histogram * WEIGHTS.histogram)
                        ) / (totalWeight * 100);

                        matches.push({
                            index: i,
                            element: items[i].closest('.anticap-item'),
                            score: score
                        });

                    } catch (e) {}
                }

                matches.sort((a, b) => b.score - a.score);
                const best = matches[0];

                if (!best) {
                    throw new Error('Tidak ada gambar');
                }

                await wait(300);
                best.element.scrollIntoView({ behavior: 'smooth', block: 'center' });
                await wait(200);

                best.element.click();
                best.element.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
                best.element.dispatchEvent(new MouseEvent('mouseup', { bubbles: true }));
                best.element.dispatchEvent(new MouseEvent('click', { bubbles: true }));

                await wait(ANTI_CONFIG.errorCheckDelay);

                // Cek status box setelah klik
                const status = checkAntiCaptchaStatus();

                if (checkAntiCaptchaError() || status === 'error') {
                    if (retryCount < ANTI_CONFIG.maxRetries) {
                        retryCount++;
                        isProcessing = false;
                        await wait(ANTI_CONFIG.retryDelay);
                        await solveAntiCaptcha();
                    } else {
                        refreshAntiCaptchaPage();
                    }
                } else if (status === 'success') {
                    captchaSolved = true;
                    retryCount = 0;
                    sessionRetryCount = 0;

                    // Hentikan monitor timeout karena sudah success
                    if (boxTimeoutId) {
                        clearTimeout(boxTimeoutId);
                    }
                }

            } catch (error) {
                if (retryCount < ANTI_CONFIG.maxRetries) {
                    retryCount++;
                    await wait(ANTI_CONFIG.retryDelay);
                    isProcessing = false;
                    await solveAntiCaptcha();
                } else {
                    refreshAntiCaptchaPage();
                }
            } finally {
                isProcessing = false;
            }
        }

        // ========== ANTI-CAPTCHA ERROR OBSERVER ==========
        function startAntiCaptchaErrorObserver() {
            if (errorObserver) {
                errorObserver.disconnect();
            }

            errorObserver = new MutationObserver((mutations) => {
                for (const mutation of mutations) {
                    if (mutation.type === 'childList' || mutation.type === 'attributes') {
                        const feedback = document.querySelector('[data-id="anticap-feedback"].error');
                        if (feedback && !isProcessing && !captchaSolved) {
                            if (retryCount < ANTI_CONFIG.maxRetries) {
                                retryCount++;
                                setTimeout(() => {
                                    isProcessing = false;
                                    solveAntiCaptcha();
                                }, ANTI_CONFIG.retryDelay);
                            } else {
                                refreshAntiCaptchaPage();
                            }
                        }
                    }
                }
            });

            errorObserver.observe(document.body, {
                childList: true,
                subtree: true,
                attributes: true,
                attributeFilter: ['class']
            });
        }

        // ========== ANTI-CAPTCHA INITIALIZATION ==========
        function initAntiCaptcha() {
            startAntiCaptchaErrorObserver();

            const captchaObserver = new MutationObserver((mutations) => {
                if (captchaSolved) return;

                for (const mutation of mutations) {
                    if (mutation.addedNodes.length) {
                        if (document.querySelector('[data-id="anticap-root"]')) {
                            if (ANTI_CONFIG.autoStart && !isProcessing && !captchaSolved) {
                                setTimeout(solveAntiCaptcha, 1000);
                            }
                        }
                    }
                }
            });

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

            if (document.querySelector('[data-id="anticap-root"]')) {
                setTimeout(solveAntiCaptcha, 2000);
            }
        }

        // Jalankan AntiCaptcha
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', initAntiCaptcha);
        } else {
            initAntiCaptcha();
        }
    }

    // ========== uCaptcha SECTION ==========
    if (isUCaptchaSite) {
        // ========== uCaptcha KONFIGURASI ==========
        const WIDGET_SELECTOR = 'div.upside-captcha-widget[data-pc-theme="light"][data-ucaptcha="widget"]';
        const CHECKBOX_SELECTOR = 'input[data-uc-checkbox]';
        const CONTAINER_SELECTOR = 'div.ucaptcha-container[data-uc-container]';
        const SHOW_SELECTOR = 'div.ucaptcha-show[data-uc-show]';
        const IMG_SELECTOR = 'img[data-uc-img]';
        const DOT_SELECTOR = '[data-uc-dot]';

        let ukuranGambar = 40;
        let widgetElement = null;
        let refreshTimer = null;
        let klikTerjadi = false;
        let prosesSedangBerjalan = false;

        // ========== uCaptcha FUNGSI CEK APAKAH SUDAH ADA KLIK ==========
        function isUCaptchaClicked() {
            // Cek apakah sudah ada elemen dot (indikator sudah diklik)
            return document.querySelector(DOT_SELECTOR) !== null;
        }

        // ========== uCaptcha FUNGSI RESET TIMER ==========
        function resetUCaptchaRefreshTimer() {
            if (refreshTimer) {
                clearTimeout(refreshTimer);
            }

            refreshTimer = setTimeout(() => {
                if (!klikTerjadi && !isUCaptchaClicked() && widgetElement) {
                    console.log('⏰ 25 detik tanpa klik - Merefresh widget uCaptcha...');
                    refreshUCaptchaWidget();
                }
            }, 25000); // 25 detik
        }

        // ========== uCaptcha FUNGSI REFRESH WIDGET ==========
        function refreshUCaptchaWidget() {
            if (!widgetElement || prosesSedangBerjalan) return;

            // Cari checkbox dan klik ulang untuk memicu refresh
            const checkbox = widgetElement.querySelector(CHECKBOX_SELECTOR);

            if (checkbox) {
                prosesSedangBerjalan = true;
                klikTerjadi = false;

                // Uncheck dulu jika sudah checked
                if (checkbox.checked) {
                    checkbox.click();
                }

                // Trigger events
                ['mousedown', 'mouseup', 'change'].forEach(t => {
                    try {
                        checkbox.dispatchEvent(new Event(t, { bubbles: true }));
                    } catch (e) {}
                });

                // Tunggu sebentar lalu check lagi
                setTimeout(() => {
                    if (!checkbox.checked) {
                        checkbox.click();

                        ['mousedown', 'mouseup', 'change'].forEach(t => {
                            try {
                                checkbox.dispatchEvent(new Event(t, { bubbles: true }));
                            } catch (e) {}
                        });
                    }

                    // Reset timer dan proses
                    setTimeout(() => {
                        prosesSedangBerjalan = false;
                        resetUCaptchaRefreshTimer();

                        // Mulai proses klik lagi
                        setTimeout(() => {
                            klikUCaptchaGambarFlipped();
                        }, 2000);
                    }, 3000);

                }, 1000);
            }
        }

        // ========== uCaptcha FUNGSI CEK APAKAH INI WIDGET YANG DITUJU ==========
        function isTargetUCaptchaWidget() {
            widgetElement = document.querySelector(WIDGET_SELECTOR);
            return widgetElement !== null;
        }

        // ========== uCaptcha FUNGSI TUNGGU WIDGET READY ==========
        function tungguUCaptchaPageLoad() {
            return new Promise(resolve => {
                if (document.readyState === 'complete') {
                    resolve();
                } else {
                    window.addEventListener('load', resolve);
                }
            });
        }

        // ========== uCaptcha FUNGSI SCROLL KE WIDGET ==========
        function scrollKeUCaptchaWidget() {
            return new Promise(resolve => {
                if (!widgetElement) {
                    resolve();
                    return;
                }

                // Scroll ke widget
                widgetElement.scrollIntoView({
                    behavior: 'smooth',
                    block: 'center',
                    inline: 'center'
                });

                // Tunggu scroll selesai
                setTimeout(resolve, 1500);
            });
        }

        // ========== uCaptcha FUNGSI CENTANG CHECKBOX ==========
        async function centangUCaptchaCheckbox() {
            if (!widgetElement) return false;

            // Cari checkbox hanya dalam widget
            const checkbox = widgetElement.querySelector(CHECKBOX_SELECTOR);

            if (checkbox && !checkbox.checked) {
                checkbox.click();

                // Trigger events
                ['mousedown', 'mouseup', 'change'].forEach(t => {
                    try {
                        checkbox.dispatchEvent(new Event(t, { bubbles: true }));
                    } catch (e) {}
                });

                // Tunggu captcha muncul
                await new Promise(r => setTimeout(r, 3000));
                return true;
            }

            return checkbox !== null;
        }

        // ========== uCaptcha FUNGSI CEK APAKAH ELEMEN VISIBLE ==========
        function isUCaptchaElementVisible(el) {
            if (!el) return false;

            const rect = el.getBoundingClientRect();
            return (
                rect.top >= 0 &&
                rect.left >= 0 &&
                rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
                rect.right <= (window.innerWidth || document.documentElement.clientWidth)
            );
        }

        // ========== uCaptcha FUNGSI KLIK GAMBAR FLIPPED ==========
        async function klikUCaptchaGambarFlipped() {
            if (!widgetElement) return false;

            // Reset status klik
            klikTerjadi = false;

            // Reset timer
            resetUCaptchaRefreshTimer();

            // Tunggu data captcha (max 20 detik)
            for (let i = 0; i < 20; i++) {
                // Cek apakah sudah ada klik dari luar
                if (isUCaptchaClicked()) {
                    console.log('✅ uCaptcha sudah diklik secara manual');
                    klikTerjadi = true;
                    if (refreshTimer) clearTimeout(refreshTimer);
                    return true;
                }

                if (window.UCaptchaPos && window.UCaptchaPos.length > 0) {

                    // Ambil ukuran gambar
                    if (window.UCaptchaPos[0] && window.UCaptchaPos[0].icon_size) {
                        ukuranGambar = window.UCaptchaPos[0].icon_size;
                    }

                    // Filter gambar flipped
                    const flippedItems = window.UCaptchaPos.filter(item => item.flipped === true);

                    if (flippedItems.length === 0) {
                        return false;
                    }

                    // Cari elemen show dalam widget
                    const showElement = widgetElement.querySelector(SHOW_SELECTOR);
                    if (!showElement) return false;

                    // Scroll ke show element
                    showElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
                    await new Promise(r => setTimeout(r, 1500));

                    // Pastikan visible
                    if (!isUCaptchaElementVisible(showElement)) {
                        showElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
                        await new Promise(r => setTimeout(r, 1500));
                    }

                    const rect = showElement.getBoundingClientRect();

                    // Klik semua gambar flipped
                    for (const item of flippedItems) {
                        // Hitung titik tengah
                        const x = rect.left + item.x + ukuranGambar/2;
                        const y = rect.top + item.y + ukuranGambar/2;

                        // Pastikan koordinat dalam viewport
                        if (x >= 0 && x <= window.innerWidth && y >= 0 && y <= window.innerHeight) {
                            const el = document.elementFromPoint(x, y);

                            if (el) {
                                // Direct click
                                el.click();

                                // Simulasi events
                                ['mousedown', 'mouseup', 'click'].forEach(t => {
                                    try {
                                        const event = new MouseEvent(t, {
                                            clientX: x,
                                            clientY: y,
                                            bubbles: true,
                                            cancelable: true,
                                            view: window
                                        });
                                        el.dispatchEvent(event);
                                    } catch (e) {}
                                });

                                // Tandai bahwa klik sudah terjadi
                                klikTerjadi = true;
                            }
                        }

                        // Jeda antar klik
                        await new Promise(r => setTimeout(r, 400));
                    }

                    // Reset timer setelah klik
                    if (klikTerjadi) {
                        if (refreshTimer) clearTimeout(refreshTimer);
                    }

                    return true;
                }

                await new Promise(r => setTimeout(r, 1000));
            }

            return false;
        }

        // ========== uCaptcha FUNGSI UTAMA ==========
        async function mainUCaptcha() {
            // Cek apakah ini widget yang dituju
            if (!isTargetUCaptchaWidget()) {
                return;
            }

            // Tunggu page load
            await tungguUCaptchaPageLoad();

            // Scroll ke widget
            await scrollKeUCaptchaWidget();

            // Centang checkbox
            await centangUCaptchaCheckbox();

            // Klik gambar flipped
            await klikUCaptchaGambarFlipped();
        }

        // ========== uCaptcha EKSEKUSI ==========

        // Jalankan setelah DOM siap
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', () => {
                setTimeout(mainUCaptcha, 1000);
            });
        } else {
            setTimeout(mainUCaptcha, 1000);
        }

        // Observer untuk mendeteksi jika widget muncul kemudian
        const uCaptchaObserver = new MutationObserver((mutations) => {
            for (const mutation of mutations) {
                if (mutation.addedNodes.length) {
                    for (const node of mutation.addedNodes) {
                        if (node.nodeType === 1) {
                            if (node.matches && node.matches(WIDGET_SELECTOR)) {
                                setTimeout(mainUCaptcha, 1000);
                                break;
                            }
                            if (node.querySelector && node.querySelector(WIDGET_SELECTOR)) {
                                setTimeout(mainUCaptcha, 1000);
                                break;
                            }
                        }
                    }
                }
            }
        });

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

        // Observer untuk mendeteksi klik manual
        const uCaptchaClickObserver = new MutationObserver(() => {
            if (isUCaptchaClicked() && refreshTimer) {
                clearTimeout(refreshTimer);
            }
        });

        // Tunggu sebentar sebelum observe dot
        setTimeout(() => {
            uCaptchaClickObserver.observe(document.body, {
                childList: true,
                subtree: true,
                attributes: true,
                attributeFilter: ['data-uc-dot']
            });
        }, 5000);
    }

    // ========== LOG STATUS ==========
    console.log(`Combined Captcha Solver: Active on ${currentUrl}`);
    if (isAntiCaptchaSite) {
        console.log('Mode: AntiCaptcha (chillfaucet/offerzono)');
    } else if (isUCaptchaSite) {
        console.log('Mode: uCaptcha (litoshipay/claimlitoshi)');
    }

})();