您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
自动完成 Microsoft Rewards 在必应(Bing)上的每日搜索任务,带有可配置的UI界面,模拟人工操作以提高安全性。目前最稳定的脚本,全自动完成电脑端90分任务。
// ==UserScript== // @name Microsoft Bing Rewards 自动搜索助手 // @name:en Microsoft Bing Rewards Auto Searcher // @namespace WretchedSniper // @version 1.1.2 // @description 自动完成 Microsoft Rewards 在必应(Bing)上的每日搜索任务,带有可配置的UI界面,模拟人工操作以提高安全性。目前最稳定的脚本,全自动完成电脑端90分任务。 // @description:en Automatically completes Microsoft Rewards daily search tasks on Bing. Features a configurable UI and mimics human behavior for better safety. // @author WretchedSniper // @match *://*.bing.com/* // @grant none // @run-at document-end // @license MIT // @icon https://www.bing.com/favicon.ico // ==/UserScript== (function () { 'use strict'; // 存储搜索词和当前进度 let mainPageSearchTerms = []; // 主页面搜索词 let iframeSearchTerms = []; // iframe搜索词 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', // 当前动作:idle, searching, scrolling, checking, waiting, resting countdown: 0, // 倒计时 needRest: false, // 是否需要休息 isCollapsed: false // UI是否折叠 }; // 创建UI控件 function createUI() { const container = document.createElement('div'); container.id = 'rewards-helper-container'; container.style.cssText = ` position: fixed; top: 20px; right: 20px; background-color: white; border: 1px solid #ddd; border-radius: 5px; padding: 10px; z-index: 10000; box-shadow: 0 2px 5px rgba(0,0,0,0.2); width: 300px; `; const header = document.createElement('div'); header.style.cssText = ` font-weight: bold; margin-bottom: 10px; border-bottom: 1px solid #ddd; padding-bottom: 5px; display: flex; justify-content: space-between; align-items: center; cursor: move; `; const headerTitle = document.createElement('span'); headerTitle.textContent = 'Microsoft Rewards 助手'; header.appendChild(headerTitle); const controlsContainer = document.createElement('div'); controlsContainer.style.display = 'flex'; controlsContainer.style.alignItems = 'center'; // --- 广告区域 --- const adContainer = document.createElement('div'); adContainer.style.cssText = 'position: relative; margin-right: 15px;'; const adTrigger = document.createElement('span'); adTrigger.textContent = '领红包'; adTrigger.style.cssText = 'cursor: pointer; font-size: 12px; color: #f44336; font-weight: bold;'; const qrCodeImageUrls = [ 'https://image.baidu.com/search/down?url=https://wx2.sinaimg.cn/mw690/006nCHZDgy1i2fa24fhc5j30u017jage.jpg', 'https://image.baidu.com/search/down?url=https://wx1.sinaimg.cn/mw690/006nCHZDgy1i2fay7ltqdj30u017jn67.jpg' ]; const qrCodeContainer = document.createElement('div'); qrCodeContainer.style.cssText = ` display: none; position: absolute; background-color: white; padding: 5px; border: 1px solid #ccc; border-radius: 5px; box-shadow: 0 0 10px rgba(0,0,0,0.2); z-index: 10002; flex-direction: column; gap: 5px; `; qrCodeImageUrls.forEach(url => { if (!url.startsWith('//')) { // 忽略被注释掉的链接 const img = document.createElement('img'); img.src = url; img.style.cssText = ` width: 225px; height: auto; display: block; `; qrCodeContainer.appendChild(img); } }); adTrigger.addEventListener('mouseenter', () => { // Set default position (below and centered) before showing qrCodeContainer.style.top = '100%'; qrCodeContainer.style.bottom = 'auto'; qrCodeContainer.style.left = '50%'; qrCodeContainer.style.right = 'auto'; qrCodeContainer.style.transform = 'translateX(-50%)'; qrCodeContainer.style.display = 'flex'; setTimeout(() => { if (qrCodeContainer.childElementCount === 0) return; const containerRect = qrCodeContainer.getBoundingClientRect(); const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; // Check vertical overflow if (containerRect.bottom > viewportHeight) { qrCodeContainer.style.top = 'auto'; qrCodeContainer.style.bottom = '100%'; } // Must re-get rect after potential vertical adjustment const finalContainerRect = qrCodeContainer.getBoundingClientRect(); // Check horizontal overflow if (finalContainerRect.right > viewportWidth) { qrCodeContainer.style.left = 'auto'; qrCodeContainer.style.right = '0'; qrCodeContainer.style.transform = 'none'; } else if (finalContainerRect.left < 0) { qrCodeContainer.style.left = '0'; qrCodeContainer.style.right = 'auto'; qrCodeContainer.style.transform = 'none'; } }, 0); }); adTrigger.addEventListener('mouseleave', () => { qrCodeContainer.style.display = 'none'; // Reset position so it can be recalculated next time qrCodeContainer.style.top = ''; qrCodeContainer.style.bottom = ''; qrCodeContainer.style.left = ''; qrCodeContainer.style.right = ''; qrCodeContainer.style.transform = ''; }); adContainer.appendChild(adTrigger); adContainer.appendChild(qrCodeContainer); controlsContainer.appendChild(adContainer); const minimizeBtn = document.createElement('span'); minimizeBtn.id = 'minimize-btn'; minimizeBtn.textContent = '折叠'; minimizeBtn.style.cssText = ` cursor: pointer; font-size: 14px; margin-right: 8px; `; minimizeBtn.onclick = toggleCollapse; controlsContainer.appendChild(minimizeBtn); const closeBtn = document.createElement('span'); closeBtn.textContent = '×'; closeBtn.style.cssText = ` cursor: pointer; font-size: 18px; `; closeBtn.onclick = function () { container.style.display = 'none'; }; controlsContainer.appendChild(closeBtn); header.appendChild(controlsContainer); const content = document.createElement('div'); content.id = 'rewards-helper-content'; content.style.cssText = ` margin-bottom: 10px; `; const progress = document.createElement('div'); progress.id = 'rewards-progress'; progress.textContent = '进度: 加载中...'; content.appendChild(progress); const searchStatus = document.createElement('div'); searchStatus.id = 'search-status'; searchStatus.style.cssText = ` margin-top: 5px; font-style: italic; `; content.appendChild(searchStatus); const countdown = document.createElement('div'); countdown.id = 'countdown'; countdown.style.cssText = ` margin-top: 5px; font-weight: bold; color: #0078d4; `; content.appendChild(countdown); const searchTermsContainer = document.createElement('div'); searchTermsContainer.id = 'rewards-search-terms-container'; searchTermsContainer.style.cssText = ` margin-top: 10px; max-height: 200px; overflow-y: auto; `; const mainTermsTitle = document.createElement('div'); mainTermsTitle.textContent = '主页面搜索词:'; mainTermsTitle.style.fontWeight = 'bold'; searchTermsContainer.appendChild(mainTermsTitle); const mainTerms = document.createElement('div'); mainTerms.id = 'main-search-terms'; mainTerms.style.cssText = ` margin-bottom: 10px; padding-left: 10px; `; searchTermsContainer.appendChild(mainTerms); const iframeTermsTitle = document.createElement('div'); iframeTermsTitle.textContent = '侧栏中推荐的搜索词:'; iframeTermsTitle.style.fontWeight = 'bold'; searchTermsContainer.appendChild(iframeTermsTitle); const iframeTerms = document.createElement('div'); iframeTerms.id = 'iframe-search-terms'; iframeTerms.style.cssText = ` padding-left: 10px; `; searchTermsContainer.appendChild(iframeTerms); content.appendChild(searchTermsContainer); const configSection = document.createElement('div'); configSection.id = 'rewards-config-section'; configSection.style.cssText = ` margin-top: 10px; border-top: 1px solid #ddd; padding-top: 10px; `; const configTitle = document.createElement('div'); configTitle.textContent = '配置参数:'; configTitle.style.fontWeight = 'bold'; configSection.appendChild(configTitle); const configForm = document.createElement('div'); configForm.style.cssText = ` display: grid; grid-template-columns: auto auto; gap: 5px; margin-top: 5px; `; // 添加休息时间配置 configForm.innerHTML += ` <label for="rest-time">休息时间(分):</label> <input type="number" id="rest-time" value="${config.restTime / 60}" min="1" max="30" style="width: 50px;"> <label for="scroll-time">滚动时间(秒):</label> <input type="number" id="scroll-time" value="${config.scrollTime}" min="3" max="30" style="width: 50px;"> <label for="wait-time">等待时间(秒):</label> <input type="number" id="wait-time" value="${config.waitTime}" min="3" max="30" style="width: 50px;"> <label for="max-no-progress">容错次数:</label> <input type="number" id="max-no-progress" value="${config.maxNoProgressCount}" min="1" max="10" style="width: 50px;"> `; configSection.appendChild(configForm); // 添加输入框变化事件监听 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', () => { const restTime = parseInt(restTimeInput.value) || 5; config.restTime = restTime * 60; updateStatus('休息时间已更新: ' + restTime + '分钟'); }); } if (scrollTimeInput) { scrollTimeInput.addEventListener('change', () => { const scrollTime = parseInt(scrollTimeInput.value) || 10; config.scrollTime = scrollTime; updateStatus('滚动时间已更新: ' + scrollTime + '秒'); }); } if (waitTimeInput) { waitTimeInput.addEventListener('change', () => { const waitTime = parseInt(waitTimeInput.value) || 10; config.waitTime = waitTime; updateStatus('等待时间已更新: ' + waitTime + '秒'); }); } if (maxNoProgressInput) { maxNoProgressInput.addEventListener('change', () => { const maxNoProgressCount = parseInt(maxNoProgressInput.value) || 3; config.maxNoProgressCount = maxNoProgressCount; updateStatus('容错次数已更新: ' + maxNoProgressCount + '次'); }); } }, 1000); content.appendChild(configSection); const buttonsContainer = document.createElement('div'); buttonsContainer.id = 'rewards-buttons-container'; buttonsContainer.style.cssText = ` display: flex; justify-content: center; margin-top: 10px; `; const startSearchBtn = document.createElement('button'); startSearchBtn.id = 'start-search-btn'; startSearchBtn.textContent = '开始自动搜索'; startSearchBtn.style.cssText = ` padding: 5px 10px; cursor: pointer; background-color: #0078d4; color: white; border: none; border-radius: 3px; width: 100%; `; startSearchBtn.onclick = function () { if (!isSearching) { startAutomatedSearch(); } else { stopAutomatedSearch(); } }; buttonsContainer.appendChild(startSearchBtn); container.appendChild(header); container.appendChild(content); container.appendChild(buttonsContainer); document.body.appendChild(container); makeDraggable(container, header); } // 让UI窗口可拖动 function makeDraggable(container, header) { let offsetX, offsetY; let isDragging = false; const onMouseDown = (e) => { // 如果点击的是按钮(它们有自己的pointer光标),则不触发拖动 if (window.getComputedStyle(e.target).cursor === 'pointer') { return; } isDragging = true; // 从'right'定位切换到'left'定位 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 }); // Use {once: true} for cleanup }; const onMouseMove = (e) => { if (!isDragging) return; container.style.top = (e.clientY - offsetY) + 'px'; container.style.left = (e.clientX - offsetX) + 'px'; }; const onMouseUp = () => { isDragging = false; document.body.style.userSelect = ''; document.removeEventListener('mousemove', onMouseMove); }; header.addEventListener('mousedown', onMouseDown); } // 更新状态显示 function updateStatus(message) { const statusElement = document.getElementById('search-status'); if (statusElement) { statusElement.textContent = message; } console.log(message); } // 切换UI折叠状态 function toggleCollapse() { searchState.isCollapsed = !searchState.isCollapsed; const searchTermsContainer = document.getElementById('rewards-search-terms-container'); const configSection = document.getElementById('rewards-config-section'); const buttonsContainer = document.getElementById('rewards-buttons-container'); const minimizeBtn = document.getElementById('minimize-btn'); if (searchState.isCollapsed) { // 折叠 if (searchTermsContainer) searchTermsContainer.style.display = 'none'; if (configSection) configSection.style.display = 'none'; if (buttonsContainer) buttonsContainer.style.display = 'none'; if (minimizeBtn) minimizeBtn.textContent = '展开'; } else { // 展开 if (searchTermsContainer) searchTermsContainer.style.display = 'block'; if (configSection) configSection.style.display = 'block'; if (buttonsContainer) buttonsContainer.style.display = 'flex'; if (minimizeBtn) minimizeBtn.textContent = '折叠'; } } // 更新倒计时显示 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; case 'checking': actionText = '检查中'; break; default: actionText = '倒计时'; } countdownElement.textContent = `${actionText}: ${seconds}秒`; countdownElement.style.display = 'block'; } else { countdownElement.style.display = 'none'; } } } // 点击打开侧边栏 function openRewardsSidebar() { const pointsContainer = document.querySelector('.points-container'); if (pointsContainer) { pointsContainer.click(); console.log('已点击积分按钮,正在打开侧边栏...'); return true; } else { console.log('未找到积分按钮'); return false; } } // 从iframe中获取数据 function getDataFromIframe() { const iframe = document.querySelector('iframe'); if (!iframe) { console.log('未找到iframe'); return false; } try { const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; console.log('成功访问iframe文档'); // 获取进度 - 检查任务完成的几种可能情况 // 1. 检查包含"你已获得 X 积分"文本的元素 const allElements = iframeDoc.querySelectorAll('*'); for (let element of allElements) { const text = element.textContent || ''; if (text.includes('你已获得') && text.includes('积分')) { console.log(`找到完成文本: "${text}"`); const match = text.match(/你已获得\s*(\d+)\s*积分/); if (match) { const totalPoints = parseInt(match[1]); currentProgress.current = totalPoints; currentProgress.total = totalPoints; currentProgress.completed = true; document.getElementById('rewards-progress').textContent = `进度: ${totalPoints}/${totalPoints} (已完成)`; console.log(`搜索任务已完成! 总积分: ${totalPoints}`); return true; } } } // 2. 特定检查promo-title类 const promoTitleElements = iframeDoc.querySelectorAll('.promo-title'); if (promoTitleElements.length > 0) { for (let element of promoTitleElements) { const text = element.textContent || ''; console.log(`找到promo-title元素: "${text}"`); 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; document.getElementById('rewards-progress').textContent = `进度: ${totalPoints}/${totalPoints} (已完成)`; console.log(`搜索任务已完成! 总积分: ${totalPoints}`); return true; } } } } // 3. 检查是否有"Offer not Completed"的标识 const offerElements = iframeDoc.querySelectorAll('[aria-label="Offer not Completed"]'); if (offerElements.length > 0) { console.log('找到"Offer not Completed"元素,但仍需检查是否实际完成'); // 即使有这个标识,也可能已经完成,所以继续检查 for (let element of offerElements) { const text = element.textContent || ''; if (text.includes('已获得') && text.includes('积分')) { console.log(`找到完成文本: "${text}"`); const match = text.match(/已获得\s*(\d+)\s*积分/); if (match) { const totalPoints = parseInt(match[1]); currentProgress.current = totalPoints; currentProgress.total = totalPoints; currentProgress.completed = true; document.getElementById('rewards-progress').textContent = `进度: ${totalPoints}/${totalPoints} (已完成)`; console.log(`搜索任务已完成! 总积分: ${totalPoints}`); return true; } } } } // 如果未完成,获取正常进度 const progressElement = iframeDoc.querySelector('.daily_search_row span:last-child'); if (progressElement) { const progress = progressElement.textContent; document.getElementById('rewards-progress').textContent = '进度: ' + progress; console.log('搜索进度: ' + progress); // 解析进度数字 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) { console.log(`进度未增加: ${current} <= ${currentProgress.lastChecked},已连续 ${currentProgress.noProgressCount + 1} 次未增加`); currentProgress.noProgressCount++; // 只有当连续多次未增加进度时才休息 if (currentProgress.noProgressCount >= config.maxNoProgressCount) { searchState.needRest = true; console.log(`达到最大容错次数 ${config.maxNoProgressCount},需要休息`); } } else if (current > currentProgress.lastChecked) { // 进度增加,重置计数器 console.log(`进度增加: ${current} > ${currentProgress.lastChecked},重置未增加计数`); currentProgress.noProgressCount = 0; } currentProgress.current = current; currentProgress.lastChecked = current; // 检查是否完成 if (current >= currentProgress.total) { currentProgress.completed = true; console.log(`进度数字表明任务已完成: ${current}/${currentProgress.total}`); } } } else { console.log('未找到进度元素'); } // 获取iframe中的搜索词 const searchTermsContainer = iframeDoc.querySelector('.ss_items_wrapper'); if (searchTermsContainer) { const terms = []; const spans = searchTermsContainer.querySelectorAll('span'); spans.forEach(span => { terms.push(span.textContent); }); // 保存到iframe搜索词变量 iframeSearchTerms = [...terms]; const termsContainer = document.getElementById('iframe-search-terms'); termsContainer.innerHTML = ''; terms.forEach(term => { const termElem = document.createElement('div'); termElem.textContent = term; termsContainer.appendChild(termElem); }); console.log('找到iframe搜索词: ' + terms.length + '个'); } else { console.log('未找到iframe搜索词容器'); } return true; } catch (e) { console.log('读取iframe内容出错: ' + e.message); return false; } } // 从主文档中获取搜索词 function getSearchTermsFromMainDoc() { const suggestionsContainer = document.querySelector('.richrsrailsugwrapper'); if (suggestionsContainer) { const terms = []; const suggestions = suggestionsContainer.querySelectorAll('.richrsrailsuggestion_text'); suggestions.forEach(suggestion => { terms.push(suggestion.textContent); }); // 保存到主页面搜索词变量 mainPageSearchTerms = [...terms]; const termsContainer = document.getElementById('main-search-terms'); termsContainer.innerHTML = ''; terms.forEach(term => { const termElem = document.createElement('div'); termElem.textContent = term; termsContainer.appendChild(termElem); }); console.log('找到主页面搜索词: ' + terms.length + '个'); return true; } else { console.log('未找到主页面搜索词'); return false; } } // 获取Rewards数据 function getRewardsData(callback) { updateStatus('正在获取奖励数据...'); if (openRewardsSidebar()) { // 等待iframe加载 setTimeout(() => { const iframeLoaded = getDataFromIframe(); const mainTermsLoaded = getSearchTermsFromMainDoc(); 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); }); } // 获取搜索词(优先主页面,其次iframe) 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)) { console.log('所有搜索词已用完,重置已使用列表'); usedSearchTerms = []; availableMainTerms = [...mainPageSearchTerms]; availableIframeTerms = [...iframeSearchTerms]; } // 优先使用主页面搜索词 if (availableMainTerms.length > 0) { const randomIndex = Math.floor(Math.random() * availableMainTerms.length); const term = availableMainTerms[randomIndex]; // 添加到已使用列表 usedSearchTerms.push(term); console.log(`选择搜索词: ${term} (主页面,还有 ${availableMainTerms.length - 1} 个未使用)`); return { term: term, source: '主页面' }; } // 如果主页面没有搜索词,使用iframe搜索词 else if (availableIframeTerms.length > 0) { const randomIndex = Math.floor(Math.random() * availableIframeTerms.length); const term = availableIframeTerms[randomIndex]; // 添加到已使用列表 usedSearchTerms.push(term); console.log(`选择搜索词: ${term} (iframe,还有 ${availableIframeTerms.length - 1} 个未使用)`); return { term: term, source: 'iframe' }; } // 如果都没有搜索词,返回null 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; // 70%向下,30%向上 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(); 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(); // 获取搜索词 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('搜索失败,请检查网页状态'); // 3秒后重试 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').style.backgroundColor = '#d83b01'; updateStatus('自动搜索已开始...'); // 计算还需要搜索的次数 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').style.backgroundColor = '#0078d4'; 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(); }); // 10秒后自动关闭 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 () { console.log('Microsoft Rewards 助手已加载'); createUI(); // 初始获取数据 setTimeout(() => { getRewardsData(); }, 2000); }); })();