Greasy Fork

Greasy Fork is available in English.

Microsoft Rewards助手

模拟操作,自动完成Microsoft Rewards必应搜索任务,带可视化界面与配置,美观安全防检测。

当前为 2025-07-07 提交的版本,查看 最新版本

// ==UserScript==
// @name         Microsoft Rewards助手
// @version      3.0.2
// @description  模拟操作,自动完成Microsoft Rewards必应搜索任务,带可视化界面与配置,美观安全防检测。
// @author       Sentaku1129 & WretchedSniper UI enhanced
// @match        *://*.bing.com/*
// @license      GNU GPLv3
// @icon         https://www.bing.com/favicon.ico
// @run-at       document-end
// @grant        none
// @namespace    http://greasyfork.icu/users/1029902
// ==/UserScript==

(function () {
    'use strict';
    if (window.trustedTypes && window.trustedTypes.createPolicy) {
        window.trustedTypes.createPolicy('default', {
            createHTML: input => input,
            createScript: input => input,
            createScriptURL: input => input
        });
    }

    // --- 颜色与字体配置 ---
    const theme = {
        main: "#0078d4",
        accent: "#4CAF50",
        error: "#f44336",
        bg: "#fff",
        fg: "#222",
        border: "#e0e0e0",
        shadow: "0 4px 20px 0 rgba(0,0,0,.10)",
        font: `-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"`
    };

    let mainPageSearchTerms = [];
    let iframeSearchTerms = [];
    let usedSearchTerms = [];
    let currentProgress = {
        current: 0, total: 0, lastChecked: 0, completed: false, noProgressCount: 0
    };
    let isSearching = false;
    let countdownTimer = null;

    const config = {
        restTime: 5 * 60,
        scrollTime: 10,
        waitTime: 10,
        searchInterval: [5, 10],
        maxNoProgressCount: 3
    };

    const searchState = {
        currentAction: 'idle',
        countdown: 0,
        needRest: false,
        isCollapsed: true
    };

    // ---- UI functions ----

    function injectGlobalStyle() {
        const style = document.createElement('style');
        style.innerHTML = `
        #rewards-helper-container {
            transition: box-shadow .2s, width .2s, height .2s;
        }
        #rewards-helper-container::-webkit-scrollbar, #rewards-helper-content::-webkit-scrollbar, #rewards-search-terms-container::-webkit-scrollbar {
            width: 8px;
            background: #f6f6f6;
        }
        #rewards-helper-container::-webkit-scrollbar-thumb, #rewards-helper-content::-webkit-scrollbar-thumb, #rewards-search-terms-container::-webkit-scrollbar-thumb {
            background: ${theme.main}33;
            border-radius: 5px;
        }
        #rewards-helper-content {
            font-family: ${theme.font};
            font-size: 15px;
            color: ${theme.fg};
        }
        #rewards-helper-container input[type=number] {
            border: 1px solid ${theme.border};
            border-radius: 3px;
            padding: 2px 5px;
            font-size: 13px;
        }
        #rewards-helper-container button {
            transition: background .15s, color .15s;
        }
        #rewards-helper-container .term-pill {
            display: inline-block;
            background: ${theme.main}12;
            border-radius: 14px;
            padding: 2px 10px;
            margin: 2px 2px 2px 0;
            font-size: 13px;
            color: ${theme.main};
            border: 1px solid ${theme.main}22;
            user-select: text;
        }
        #rewards-helper-container .term-pill.used {
            opacity: .45;
            background: #aaa1;
            color: #999;
            border: 1px solid #ccc;
            text-decoration: line-through;
        }
        #rewards-helper-container .heading {
            font-size: 14px;
            color: ${theme.main};
            font-weight: bold;
            margin-bottom: 2px;
            letter-spacing: .05em;
        }
        #rewards-helper-container .action-btn {
            background: ${theme.main};
            color: #fff;
            border: none;
            border-radius: 4px;
            font-weight: bold;
            font-size: 15px;
            padding: 6px 0;
            margin-bottom: 0;
            width: 100%;
            transition: background .15s;
        }
        #rewards-helper-container .action-btn.stop {
            background: ${theme.error};
        }
        #rewards-helper-container .status-message {
            font-size: 13px;
            color: #888;
            margin-top: -1px;
            min-height: 18px;
        }
        #rewards-helper-container .progress-bar {
            background: #eee;
            height: 10px;
            border-radius: 6px;
            overflow: hidden;
            margin: 4px 0 6px 0;
        }
        #rewards-helper-container .progress-bar-inner {
            background: ${theme.accent};
            height: 100%;
            transition: width .5s;
        }
        #rewards-helper-container .countdown {
            font-size: 13px;
            color: ${theme.main};
            margin-top: 3px;
            font-weight: bold;
        }
        @media (max-width: 500px) {
            #rewards-helper-container {
                width: 98vw !important;
                right: 1vw !important;
                left: unset !important;
                min-width: 0 !important;
                max-width: none !important;
            }
        }
        `;
        document.head.appendChild(style);
    }

    function createUI() {
        injectGlobalStyle();

        const container = document.createElement('div');
        container.id = 'rewards-helper-container';
        container.style.cssText = `
            position: fixed; top: 32px; right: 24px; background: ${theme.bg};
            border: 1.5px solid ${theme.border}; border-radius: 10px; padding: 0 0 10px 0;
            z-index: 10000; width: 340px; min-width: 260px; max-width: 97vw;
            box-shadow: ${theme.shadow}; user-select: none; font-family: ${theme.font};
            font-size: 15px;
        `;

        const header = document.createElement('div');
        header.style.cssText = `
            font-weight: bold;
            background: ${theme.main};
            color: #fff;
            border-radius: 10px 10px 0 0;
            padding: 10px 12px 8px 18px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            cursor: move;
            font-size: 18px;
        `;
        header.innerHTML = `<span>🎁 Microsoft Rewards 助手</span>`;

        const controls = document.createElement('div');
        controls.style.cssText = `display:flex;align-items:center;gap:10px;`;

        const minimizeBtn = document.createElement('span');
        minimizeBtn.id = 'minimize-btn';
        minimizeBtn.textContent = '-';
        minimizeBtn.title = '折叠/展开';
        minimizeBtn.style.cssText = `
            cursor:pointer;font-size:22px;transform:scaleX(1.3);margin-right:10px;user-select:none;
        `;
        minimizeBtn.onclick = () => { toggleCollapse(); };
        controls.appendChild(minimizeBtn);

        const closeBtn = document.createElement('span');
        closeBtn.textContent = '×';
        closeBtn.title = '关闭助手';
        closeBtn.style.cssText = `
            cursor:pointer;font-size:24px;user-select:none;opacity:.85;
        `;
        closeBtn.onclick = () => { container.style.display = 'none'; };
        controls.appendChild(closeBtn);

        header.appendChild(controls);

        const content = document.createElement('div');
        content.id = 'rewards-helper-content';
        content.style.cssText = `padding: 14px 18px 0 18px;`;

        const progress = document.createElement('div');
        progress.id = 'rewards-progress';
        progress.style.cssText = `font-size:15px;margin-bottom:6px;font-weight:500;letter-spacing:.02em;`;
        progress.innerHTML = `进度: <span class="progress-value">加载中...</span>`;
        content.appendChild(progress);

        const progressBar = document.createElement('div');
        progressBar.className = 'progress-bar';
        progressBar.style.width = "100%";
        const progressBarInner = document.createElement('div');
        progressBarInner.className = 'progress-bar-inner';
        progressBarInner.style.width = "0%";
        progressBar.appendChild(progressBarInner);
        content.appendChild(progressBar);

        const statusLine = document.createElement('div');
        statusLine.id = 'search-status';
        statusLine.className = 'status-message';
        statusLine.textContent = "";
        content.appendChild(statusLine);

        const countdown = document.createElement('div');
        countdown.id = 'countdown';
        countdown.className = 'countdown';
        countdown.style.display = 'none';
        content.appendChild(countdown);

        const searchTermsContainer = document.createElement('div');
        searchTermsContainer.id = 'rewards-search-terms-container';
        searchTermsContainer.style.cssText = `margin-top:8px;max-height:120px;overflow-y:auto;`;

        const mainTermsTitle = document.createElement('div');
        mainTermsTitle.className = 'heading';
        mainTermsTitle.textContent = '主页面搜索词';
        searchTermsContainer.appendChild(mainTermsTitle);
        const mainTerms = document.createElement('div');
        mainTerms.id = 'main-search-terms';
        mainTerms.style.cssText = `margin-bottom: 6px;line-height:1.7;`;
        searchTermsContainer.appendChild(mainTerms);

        const iframeTermsTitle = document.createElement('div');
        iframeTermsTitle.className = 'heading';
        iframeTermsTitle.textContent = '侧栏推荐搜索词';
        searchTermsContainer.appendChild(iframeTermsTitle);
        const iframeTerms = document.createElement('div');
        iframeTerms.id = 'iframe-search-terms';
        iframeTerms.style.cssText = `margin-bottom:3px;line-height:1.7;`;
        searchTermsContainer.appendChild(iframeTerms);

        content.appendChild(searchTermsContainer);

        const divider = document.createElement('hr');
        divider.style.cssText = `border:0;border-top:1px solid ${theme.border};margin:10px 0 8px 0;`;
        content.appendChild(divider);

        const configSection = document.createElement('div');
        configSection.id = 'rewards-config-section';
        configSection.style.cssText = `margin-bottom:10px;`;

        const configTitle = document.createElement('div');
        configTitle.className = 'heading';
        configTitle.textContent = '配置参数:';
        configSection.appendChild(configTitle);

        const configForm = document.createElement('div');
        configForm.style.cssText = `
            display: grid; grid-template-columns: 110px auto; gap: 4px 6px; align-items:center;
            font-size:13px;margin-top:2px;
        `;
        configForm.innerHTML = `
            <label for="rest-time">休息时间(分):</label>
            <input type="number" id="rest-time" value="${config.restTime / 60}" min="1" max="30">
            <label for="scroll-time">滚动时间(秒):</label>
            <input type="number" id="scroll-time" value="${config.scrollTime}" min="3" max="30">
            <label for="wait-time">等待时间(秒):</label>
            <input type="number" id="wait-time" value="${config.waitTime}" min="3" max="30">
            <label for="max-no-progress">容错次数:</label>
            <input type="number" id="max-no-progress" value="${config.maxNoProgressCount}" min="1" max="10">
        `;
        configSection.appendChild(configForm);
        content.appendChild(configSection);

        const buttonsContainer = document.createElement('div');
        buttonsContainer.id = 'rewards-buttons-container';
        buttonsContainer.style.cssText = `
            display:flex;flex-direction:column;align-items:stretch;margin-top:0;gap:7px 0;padding:0 18px;
        `;

        const startSearchBtn = document.createElement('button');
        startSearchBtn.id = 'start-search-btn';
        startSearchBtn.className = 'action-btn';
        startSearchBtn.textContent = '开始自动搜索';
        startSearchBtn.onclick = function () {
            if (!isSearching) startAutomatedSearch();
            else stopAutomatedSearch();
        };
        buttonsContainer.appendChild(startSearchBtn);

        const linksContainer = document.createElement('div');
        linksContainer.style.cssText = `
            display: flex;justify-content:center;gap:15px;margin-top:5px;width:100%;font-size:13px;color:#888;
        `;
        const supportAuthorContainer = document.createElement('div');
        const supportAuthorLink = document.createElement('span');
        supportAuthorLink.textContent = '🧧 支持作者';
        supportAuthorLink.style.cssText = 'cursor:pointer;color:' + theme.error + ';font-weight:bold;';
        const qrCodeContainer = document.createElement('div');
        qrCodeContainer.style.cssText = `
            display:none;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);
            background:#fff;padding:22px 25px 18px 25px;border:1.5px solid #eee;border-radius:8px;box-shadow:0 0 30px 0 #0004;z-index:10002;flex-direction:row;gap:16px;
        `;
        [
            'https://image.baidu.com/search/down?url=https://tokyo.sentaku.trade:9999/down/A3Z8wGynBHGo.png',
            'https://image.baidu.com/search/down?url=https://tokyo.sentaku.trade:9999/down/DcDNyzGgGG4E.png'
        ].forEach(url => {
            if (!url.startsWith('//')) {
                const img = document.createElement('img');
                img.src = url;
                // img.style.cssText = `width: 150px; height: auto; display: block; border-radius:6px;border:1px solid #eee;box-shadow:0 0 8px #0002;`;
                img.style.cssText = `max-width: 250px;max-height: 300px;width: auto;height: auto;display: block;border-radius: 6px;border: 1px solid #eee;box-shadow: 0 0 8px #0002;margin: 0 auto;background: #fff;`;
                qrCodeContainer.appendChild(img);
            }
        });
        supportAuthorLink.onclick = (e) => {
            e.preventDefault(); qrCodeContainer.style.display = 'flex';
            const overlay = document.createElement('div');
            overlay.style.cssText = `
                position:fixed;top:0;left:0;width:100vw;height:100vh;
                background:rgba(0,0,0,.36);z-index:10001;
            `;
            overlay.onclick = () => {
                qrCodeContainer.style.display = 'none'; document.body.removeChild(overlay);
            };
            document.body.appendChild(overlay);
            if (qrCodeContainer.parentElement !== document.body) document.body.appendChild(qrCodeContainer);
        };
        supportAuthorContainer.appendChild(supportAuthorLink);
        supportAuthorContainer.appendChild(qrCodeContainer);
        linksContainer.appendChild(supportAuthorContainer);

        const rateLink = document.createElement('a');
        rateLink.href = 'http://greasyfork.icu/zh-CN/scripts/460310-%E5%BF%85%E5%BA%94rewards%E7%83%AD%E6%90%9C%E8%87%AA%E5%8A%A8%E8%BE%93%E5%85%A5%E4%BB%BB%E5%8A%A1/feedback';
        rateLink.target = '_blank';
        rateLink.textContent = '👍 给个好评';
        rateLink.style.cssText = 'color:' + theme.accent + ';font-weight:bold;text-decoration:none;';
        linksContainer.appendChild(rateLink);

        buttonsContainer.appendChild(linksContainer);

        container.appendChild(header);
        container.appendChild(content);
        container.appendChild(buttonsContainer);
        document.body.appendChild(container);

        makeDraggable(container, header);

        setTimeout(() => {
            const restTimeInput = document.getElementById('rest-time');
            const scrollTimeInput = document.getElementById('scroll-time');
            const waitTimeInput = document.getElementById('wait-time');
            const maxNoProgressInput = document.getElementById('max-no-progress');
            if (restTimeInput) restTimeInput.addEventListener('change', () => {
                config.restTime = (parseInt(restTimeInput.value) || 5) * 60;
                updateStatus('休息时间已更新: ' + restTimeInput.value + '分钟');
            });
            if (scrollTimeInput) scrollTimeInput.addEventListener('change', () => {
                config.scrollTime = parseInt(scrollTimeInput.value) || 10;
                updateStatus('滚动时间已更新: ' + scrollTimeInput.value + '秒');
            });
            if (waitTimeInput) waitTimeInput.addEventListener('change', () => {
                config.waitTime = parseInt(waitTimeInput.value) || 10;
                updateStatus('等待时间已更新: ' + waitTimeInput.value + '秒');
            });
            if (maxNoProgressInput) maxNoProgressInput.addEventListener('change', () => {
                config.maxNoProgressCount = parseInt(maxNoProgressInput.value) || 3;
                updateStatus('容错次数已更新: ' + maxNoProgressInput.value + '次');
            });
        }, 600);
    }

    function toggleCollapse() {
        searchState.isCollapsed = !searchState.isCollapsed;
        applyCollapseState();
    }
    function applyCollapseState() {
        const searchTermsContainer = document.getElementById('rewards-search-terms-container');
        const configSection = document.getElementById('rewards-config-section');
        const minimizeBtn = document.getElementById('minimize-btn');
        if (searchState.isCollapsed) {
            if (searchTermsContainer) searchTermsContainer.style.display = 'none';
            if (configSection) configSection.style.display = 'none';
            if (minimizeBtn) minimizeBtn.textContent = '+';
        } else {
            if (searchTermsContainer) searchTermsContainer.style.display = 'block';
            if (configSection) configSection.style.display = 'block';
            if (minimizeBtn) minimizeBtn.textContent = '-';
        }
    }
    function updateStatus(message) {
        const statusElement = document.getElementById('search-status');
        if (statusElement) statusElement.textContent = message || '';
    }
    function updateCountdown(seconds, action) {
        const countdownElement = document.getElementById('countdown');
        if (countdownElement) {
            if (seconds > 0) {
                let actionText = "";
                switch (action) {
                    case 'scrolling': actionText = '滚动中'; break;
                    case 'waiting': actionText = '等待中'; break;
                    case 'resting': actionText = '休息中'; break;
                    default: actionText = '倒计时';
                }
                countdownElement.textContent = `${actionText}: ${seconds}秒`;
                countdownElement.style.display = 'block';
            } else {
                countdownElement.style.display = 'none';
            }
        }
    }
    function updateProgressUI() {
        const elem = document.getElementById('rewards-progress');
        const bar = document.querySelector('.progress-bar-inner');
        let current = currentProgress.current, total = currentProgress.total;
        if (!total || total === 0) total = 1;
        let percent = Math.min(100, Math.round((current / total) * 100));
        if (elem) {
            let done = currentProgress.completed;
            elem.innerHTML = `进度: <span class="progress-value">${current}/${total}${done ? " (已完成)" : ""}</span>`;
        }
        if (bar) bar.style.width = percent + "%";
    }
    function updateSearchTermsUI() {
        const mainTermsContainer = document.getElementById('main-search-terms');
        if (mainTermsContainer) {
            mainTermsContainer.innerHTML = "";
            mainPageSearchTerms.forEach(term => {
                const div = document.createElement('span');
                div.className = "term-pill" + (usedSearchTerms.includes(term) ? " used" : "");
                div.textContent = term;
                mainTermsContainer.appendChild(div);
            });
        }
        const iframeTermsContainer = document.getElementById('iframe-search-terms');
        if (iframeTermsContainer) {
            iframeTermsContainer.innerHTML = "";
            iframeSearchTerms.forEach(term => {
                const div = document.createElement('span');
                div.className = "term-pill" + (usedSearchTerms.includes(term) ? " used" : "");
                div.textContent = term;
                iframeTermsContainer.appendChild(div);
            });
        }
    }

    function makeDraggable(container, header) {
        let offsetX, offsetY, isDragging = false;
        header.addEventListener('mousedown', (e) => {
            if (window.getComputedStyle(e.target).cursor === 'pointer') return;
            isDragging = true;
            if (container.style.right) {
                container.style.left = container.offsetLeft + 'px';
                container.style.right = '';
            }
            offsetX = e.clientX - container.offsetLeft;
            offsetY = e.clientY - container.offsetTop;
            document.body.style.userSelect = 'none';
            document.addEventListener('mousemove', onMouseMove);
            document.addEventListener('mouseup', onMouseUp, { once: true });
            function onMouseMove(e) {
                if (!isDragging) return;
                container.style.top = (e.clientY - offsetY) + 'px';
                container.style.left = (e.clientX - offsetX) + 'px';
            }
            function onMouseUp() {
                isDragging = false;
                document.body.style.userSelect = '';
                document.removeEventListener('mousemove', onMouseMove);
            }
        });
    }

    // ----------- 自动Rewards主逻辑(融合UI) -----------

    function openRewardsSidebar() {
        const pointsContainer = document.querySelector('.points-container');
        if (pointsContainer) {
            pointsContainer.click();
            return true;
        }
        return false;
    }

    function getDataFromIframe() {
        const iframe = document.querySelector('iframe');
        if (!iframe) return false;

        try {
            const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

            // 1. 检查已获取积分
            const allElements = iframeDoc.querySelectorAll('*');
            for (let element of allElements) {
                const text = element.textContent || '';
                if (text.includes('你已获得') && text.includes('积分')) {
                    const match = text.match(/你已获得\s*(\d+)\s*积分/);
                    if (match) {
                        const totalPoints = parseInt(match[1]);
                        currentProgress.current = totalPoints;
                        currentProgress.total = totalPoints;
                        currentProgress.completed = true;
                        updateProgressUI();
                        return true;
                    }
                }
            }

            // 2. 特定promo-title
            const promoTitleElements = iframeDoc.querySelectorAll('.promo-title');
            if (promoTitleElements.length > 0) {
                for (let element of promoTitleElements) {
                    const text = element.textContent || '';
                    if (text.includes('已获得')) {
                        const match = text.match(/已获得\s*(\d+)\s*积分/);
                        if (match) {
                            const totalPoints = parseInt(match[1]);
                            currentProgress.current = totalPoints;
                            currentProgress.total = totalPoints;
                            currentProgress.completed = true;
                            updateProgressUI();
                            return true;
                        }
                    }
                }
            }

            // 3. offer not completed
            const offerElements = iframeDoc.querySelectorAll('[aria-label="Offer not Completed"]');
            if (offerElements.length > 0) {
                for (let element of offerElements) {
                    const text = element.textContent || '';
                    if (text.includes('已获得') && text.includes('积分')) {
                        const match = text.match(/已获得\s*(\d+)\s*积分/);
                        if (match) {
                            const totalPoints = parseInt(match[1]);
                            currentProgress.current = totalPoints;
                            currentProgress.total = totalPoints;
                            currentProgress.completed = true;
                            updateProgressUI();
                            return true;
                        }
                    }
                }
            }

            // 未完成,获取正常进度
            const progressElement = iframeDoc.querySelector('.daily_search_row span:last-child');
            if (progressElement) {
                const progress = progressElement.textContent;
                const match = progress.match(/(\d+)\/(\d+)/);
                if (match) {
                    const current = parseInt(match[1]);
                    currentProgress.total = parseInt(match[2]);
                    if (currentProgress.lastChecked > 0 && current <= currentProgress.lastChecked && isSearching) {
                        currentProgress.noProgressCount++;
                        if (currentProgress.noProgressCount >= config.maxNoProgressCount) {
                            searchState.needRest = true;
                        }
                    } else if (current > currentProgress.lastChecked) {
                        currentProgress.noProgressCount = 0;
                    }
                    currentProgress.current = current;
                    currentProgress.lastChecked = current;
                    if (current >= currentProgress.total) {
                        currentProgress.completed = true;
                    }
                }
                updateProgressUI();
            }

            // 获取iframe中的搜索词
            const searchTermsContainer = iframeDoc.querySelector('.ss_items_wrapper');
            if (searchTermsContainer) {
                const terms = [];
                const spans = searchTermsContainer.querySelectorAll('span');
                spans.forEach(span => {
                    if (span.textContent) terms.push(span.textContent);
                });
                iframeSearchTerms = [...terms];
                updateSearchTermsUI();
            }

            return true;
        } catch (e) {
            return false;
        }
    }

    function getSearchTermsFromMainDoc() {
        const suggestionsContainer = document.querySelector('.richrsrailsugwrapper');
        if (suggestionsContainer) {
            const terms = [];
            const suggestions = suggestionsContainer.querySelectorAll('.richrsrailsuggestion_text');
            suggestions.forEach(suggestion => {
                if (suggestion.textContent) terms.push(suggestion.textContent);
            });
            mainPageSearchTerms = [...terms];
            updateSearchTermsUI();
            return true;
        }
        return false;
    }

    function getRewardsData(callback) {
        updateStatus('正在获取奖励数据...');
        if (openRewardsSidebar()) {
            setTimeout(() => {
                const iframeLoaded = getDataFromIframe();
                const mainTermsLoaded = getSearchTermsFromMainDoc();

                updateProgressUI();
                updateSearchTermsUI();

                if (!iframeLoaded && !mainTermsLoaded) {
                    updateStatus('获取数据失败,请重试');
                } else {
                    updateStatus('数据获取成功');
                    if (currentProgress.completed) {
                        updateStatus('搜索任务已完成!');
                        if (isSearching) {
                            showCompletionNotification();
                            stopAutomatedSearch();
                        }
                    }
                }

                if (searchState.needRest && isSearching) {
                    startResting();
                } else if (callback) {
                    callback();
                }
            }, 1500);
        } else {
            updateStatus('未找到积分按钮,请确保已登录');
            if (callback) callback();
        }
    }

    function startResting() {
        searchState.needRest = false;
        currentProgress.noProgressCount = 0;
        updateStatus(`连续 ${config.maxNoProgressCount} 次搜索无进度,休息 ${config.restTime / 60} 分钟后继续`);
        startCountdown(config.restTime, 'resting', () => {
            updateStatus('休息结束,继续搜索');
            setTimeout(performNextSearch, 1000);
        });
    }

    function getSearchTerm() {
        let availableMainTerms = mainPageSearchTerms.filter(term => !usedSearchTerms.includes(term));
        let availableIframeTerms = iframeSearchTerms.filter(term => !usedSearchTerms.includes(term));

        if (availableMainTerms.length === 0 && availableIframeTerms.length === 0 &&
            (mainPageSearchTerms.length > 0 || iframeSearchTerms.length > 0)) {
            usedSearchTerms = [];
            availableMainTerms = [...mainPageSearchTerms];
            availableIframeTerms = [...iframeSearchTerms];
        }

        if (availableMainTerms.length > 0) {
            const randomIndex = Math.floor(Math.random() * availableMainTerms.length);
            const term = availableMainTerms[randomIndex];
            usedSearchTerms.push(term);
            updateSearchTermsUI();
            return { term: term, source: '主页面' };
        } else if (availableIframeTerms.length > 0) {
            const randomIndex = Math.floor(Math.random() * availableIframeTerms.length);
            const term = availableIframeTerms[randomIndex];
            usedSearchTerms.push(term);
            updateSearchTermsUI();
            return { term: term, source: 'iframe' };
        }
        return null;
    }

    function performSearch(term) {
        if (!term) return false;
        const searchBox = document.querySelector('#sb_form_q');
        if (searchBox) {
            searchBox.value = term;
            const searchForm = document.querySelector('#sb_form');
            if (searchForm) {
                searchForm.submit();
                return true;
            }
        }
        return false;
    }

    function simulateScrolling(callback) {
        updateStatus('正在滚动页面...');
        searchState.currentAction = 'scrolling';
        startCountdown(config.scrollTime, 'scrolling', callback);

        const scrollInterval = setInterval(() => {
            const scrollAmount = Math.floor(Math.random() * 300) + 100;
            const scrollDirection = Math.random() > 0.3 ? 1 : -1;
            window.scrollBy(0, scrollAmount * scrollDirection);
            if (searchState.currentAction !== 'scrolling') clearInterval(scrollInterval);
        }, 1000);

        setTimeout(() => { clearInterval(scrollInterval); }, config.scrollTime * 1000);
    }

    function checkProgress(callback) {
        updateStatus('正在检查搜索进度...');
        searchState.currentAction = 'checking';

        if (openRewardsSidebar()) {
            setTimeout(() => {
                getDataFromIframe();
                getSearchTermsFromMainDoc();
                updateProgressUI();
                updateSearchTermsUI();

                if (currentProgress.completed) {
                    showCompletionNotification();
                    updateStatus('搜索任务已完成!');
                    stopAutomatedSearch();
                    return;
                }

                if (searchState.needRest) {
                    startResting();
                } else if (callback) {
                    callback();
                }
            }, 1500);
        } else {
            updateStatus('无法打开侧边栏检查进度');
            if (callback) callback();
        }
    }

    function waitForNextSearch() {
        updateStatus('等待下一次搜索...');
        startCountdown(config.waitTime, 'waiting', performNextSearch);
    }

    function performNextSearch() {
        if (!isSearching) return;
        const remainingSearches = currentProgress.total - currentProgress.current;
        if (remainingSearches <= 0 || currentProgress.completed) {
            showCompletionNotification();
            updateStatus('搜索任务已完成!');
            stopAutomatedSearch();
            return;
        }

        updateStatus('获取最新搜索词...');
        getSearchTermsFromMainDoc();
        updateSearchTermsUI();

        const searchTermObj = getSearchTerm();

        if (!searchTermObj) {
            updateStatus('没有可用的搜索词,获取数据...');
            getRewardsData(() => {
                const newSearchTermObj = getSearchTerm();
                if (newSearchTermObj) {
                    setTimeout(performNextSearch, 1000);
                } else {
                    updateStatus('无法获取搜索词,停止搜索');
                    stopAutomatedSearch();
                }
            });
            return;
        }

        const { term, source } = searchTermObj;
        updateStatus(`正在搜索: ${term} (${source}搜索词) [剩余:${remainingSearches}]`);

        if (performSearch(term)) {
            setTimeout(() => {
                simulateScrolling(() => {
                    checkProgress(() => {
                        waitForNextSearch();
                    });
                });
            }, 2000);
        } else {
            updateStatus('搜索失败,请检查网页状态');
            setTimeout(performNextSearch, 3000);
        }
    }

    function startAutomatedSearch() {
        if (mainPageSearchTerms.length === 0 && iframeSearchTerms.length === 0) {
            updateStatus('获取搜索词中...');
            getRewardsData(() => {
                if (mainPageSearchTerms.length === 0 && iframeSearchTerms.length === 0) {
                    alert('没有搜索词,无法开始搜索');
                    return;
                } else {
                    startSearchProcess();
                }
            });
        } else {
            startSearchProcess();
        }
    }

    function startSearchProcess() {
        isSearching = true;
        searchState.needRest = false;
        currentProgress.noProgressCount = 0;
        usedSearchTerms = [];
        document.getElementById('start-search-btn').textContent = '停止搜索';
        document.getElementById('start-search-btn').classList.add('stop');
        updateStatus('自动搜索已开始...');
        updateProgressUI();
        updateSearchTermsUI();

        const remainingSearches = currentProgress.total - currentProgress.current;
        if (remainingSearches <= 0 || currentProgress.completed) {
            updateStatus('搜索任务已完成!');
            stopAutomatedSearch();
            return;
        }
        performNextSearch();
    }

    function stopAutomatedSearch() {
        if (countdownTimer) {
            clearInterval(countdownTimer);
            countdownTimer = null;
        }

        isSearching = false;
        searchState.currentAction = 'idle';
        searchState.needRest = false;
        currentProgress.noProgressCount = 0;
        usedSearchTerms = [];
        updateCountdown(0, '');

        document.getElementById('start-search-btn').textContent = '开始自动搜索';
        document.getElementById('start-search-btn').classList.remove('stop');
        updateStatus('搜索已停止');
    }

    function showCompletionNotification() {
        const notification = document.createElement('div');
        notification.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: #0078d4;
            color: white;
            padding: 20px;
            border-radius: 5px;
            box-shadow: 0 4px 8px rgba(0,0,0,0.2);
            z-index: 10001;
            text-align: center;
            font-size: 16px;
        `;
        notification.innerHTML = `
            <div style="font-weight: bold; margin-bottom: 10px; font-size: 18px;">任务完成!</div>
            <div>已完成所有 ${currentProgress.total} 次搜索任务</div>
            <button id="notification-close" style="
                margin-top: 15px;
                padding: 5px 15px;
                background-color: white;
                color: #0078d4;
                border: none;
                border-radius: 3px;
                cursor: pointer;
            ">关闭</button>
        `;
        document.body.appendChild(notification);

        document.getElementById('notification-close').addEventListener('click', function () {
            notification.remove();
        });

        setTimeout(() => {
            if (document.body.contains(notification)) notification.remove();
        }, 10000);
    }

    function startCountdown(seconds, action, callback) {
        if (countdownTimer) {
            clearInterval(countdownTimer);
            countdownTimer = null;
        }
        searchState.currentAction = action;
        searchState.countdown = seconds;
        updateCountdown(seconds, action);

        countdownTimer = setInterval(() => {
            searchState.countdown--;
            updateCountdown(searchState.countdown, action);
            if (searchState.countdown <= 0) {
                clearInterval(countdownTimer);
                countdownTimer = null;
                if (callback) callback();
            }
        }, 1000);
    }

    window.addEventListener('load', function () {
        createUI();
        applyCollapseState();
        setTimeout(() => {
            getRewardsData();
        }, 2000);
    });

})();