// ==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);
});
})();