// ==UserScript==
// @name Microsoft Rewards助手
// @version 3.5.0
// @description 自动完成Microsoft Rewards必应搜索任务,支持SPA不刷新和页面刷新自动恢复,防卡死,状态记忆,带美观可视化界面。
// @author Sentaku1129 & WretchedSniper UI enhanced & Copilot
// @match *://*.bing.com/*
// @license GNU GPLv3
// @icon https://www.bing.com/favicon.ico
// @run-at document-end
// @grant none
// @namespace https://greasyfork.org/users/1029902
// ==/UserScript==
(function () {
'use strict';
// --- 主题配置 ---
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,
maxNoProgressCount: 3
};
const searchState = {
currentAction: 'idle',
countdown: 0,
needRest: false,
isCollapsed: true
};
const STORAGE_KEY = 'rewardsHelperState_v3.5';
// --- 状态管理 ---
function saveState() {
try {
const stateToSave = {
isSearching,
currentProgress,
usedSearchTerms,
config,
isCollapsed: searchState.isCollapsed
};
localStorage.setItem(STORAGE_KEY, JSON.stringify(stateToSave));
} catch (e) {}
}
function loadState() {
const savedState = localStorage.getItem(STORAGE_KEY);
if (savedState) {
try {
const restoredState = JSON.parse(savedState);
isSearching = restoredState.isSearching || false;
currentProgress = restoredState.currentProgress || currentProgress;
usedSearchTerms = restoredState.usedSearchTerms || [];
Object.assign(config, restoredState.config);
searchState.isCollapsed = restoredState.isCollapsed === false ? false : true;
} catch (e) {
localStorage.removeItem(STORAGE_KEY);
}
}
}
// --- UI相关 ---
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);
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');
function updateConfigAndSave() {
config.restTime = (parseInt(restTimeInput.value) || 5) * 60;
config.scrollTime = parseInt(scrollTimeInput.value) || 10;
config.waitTime = parseInt(waitTimeInput.value) || 10;
config.maxNoProgressCount = parseInt(maxNoProgressInput.value) || 3;
saveState();
}
if (restTimeInput) restTimeInput.addEventListener('change', updateConfigAndSave);
if (scrollTimeInput) scrollTimeInput.addEventListener('change', updateConfigAndSave);
if (waitTimeInput) waitTimeInput.addEventListener('change', updateConfigAndSave);
if (maxNoProgressInput) maxNoProgressInput.addEventListener('change', updateConfigAndSave);
}, 600);
}
function toggleCollapse() {
searchState.isCollapsed = !searchState.isCollapsed;
saveState();
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);
}
});
}
// ----------- 搜索词采集 -----------
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 = [...new Set(terms)];
updateSearchTermsUI();
return true;
}
return false;
}
function getDataFromIframe() {
const iframe = document.querySelector('iframe');
if (!iframe) return false;
try {
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
const progressElement = iframeDoc.querySelector('.daily_search_row span:last-child');
if (progressElement) {
const match = progressElement.textContent.match(/(\d+)\/(\d+)/);
if (match) {
const current = parseInt(match[1]);
const total = parseInt(match[2]);
currentProgress.total = total;
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;
searchState.needRest = false;
}
currentProgress.current = current;
currentProgress.lastChecked = current;
if (current >= total) {
currentProgress.completed = true;
}
}
}
// 搜索词
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 = [...new Set(terms)];
updateSearchTermsUI();
}
return true;
} catch (e) { return false; }
}
function getRewardsData(callback) {
openRewardsSidebar();
setTimeout(() => {
getDataFromIframe();
getSearchTermsFromMainDoc();
updateProgressUI();
updateSearchTermsUI();
if (callback) callback();
}, 1500);
}
function openRewardsSidebar() {
const pointsContainer = document.querySelector('.points-container');
if (pointsContainer) {
pointsContainer.click();
return true;
}
return false;
}
// ----------- 搜索流程 -----------
function getSearchTerm() {
let allTerms = [...new Set([...mainPageSearchTerms, ...iframeSearchTerms])];
let availableTerms = allTerms.filter(term => !usedSearchTerms.includes(term));
if (availableTerms.length === 0 && allTerms.length > 0) {
usedSearchTerms = [];
availableTerms = allTerms;
}
if (availableTerms.length > 0) {
const randomIndex = Math.floor(Math.random() * availableTerms.length);
const term = availableTerms[randomIndex];
usedSearchTerms.push(term);
updateSearchTermsUI();
return term;
}
return null;
}
// 兼容SPA的搜索触发
function performSearch(term, callback) {
if (!term) return false;
const searchBox = document.querySelector('#sb_form_q');
if (searchBox) {
searchBox.value = term;
const searchForm = document.querySelector('#sb_form');
if (searchForm) {
// 记录跳转前的URL
const beforeUrl = location.href;
searchForm.submit();
setTimeout(() => {
if (location.href === beforeUrl) {
waitForSearchResultChange(term, callback);
}
}, 1500);
return true;
}
}
return false;
}
// 监听搜索结果区变化(兼容SPA)
function waitForSearchResultChange(lastTerm, callback) {
const content = document.querySelector('#b_content');
if (!content) {
setTimeout(() => waitForSearchResultChange(lastTerm, callback), 500);
return;
}
let observer = new MutationObserver(() => {
const input = document.querySelector('#sb_form_q');
if (input && input.value === lastTerm) {
observer.disconnect();
if (callback) callback();
}
});
observer.observe(content, { childList: true, subtree: true });
setTimeout(() => observer.disconnect(), 15000);
}
function simulateScrolling(callback) {
updateStatus('正在滚动页面...');
searchState.currentAction = 'scrolling';
startCountdown(config.scrollTime, 'scrolling', callback);
const scrollInterval = setInterval(() => {
if (searchState.currentAction !== 'scrolling') {
clearInterval(scrollInterval); return;
}
const scrollAmount = Math.floor(Math.random() * 300) + 100;
const scrollDirection = Math.random() > 0.3 ? 1 : -1;
window.scrollBy(0, scrollAmount * scrollDirection);
}, 1000);
}
function checkProgress(callback) {
openRewardsSidebar();
setTimeout(() => {
getDataFromIframe();
getSearchTermsFromMainDoc();
updateProgressUI();
updateSearchTermsUI();
saveState();
if (currentProgress.completed) {
updateStatus('搜索任务已完成!');
stopAutomatedSearch();
} else if (searchState.needRest) {
startResting();
} else if (callback) {
callback();
}
}, 1500);
}
function waitForNextSearch() {
updateStatus('等待下一次搜索...');
startCountdown(config.waitTime, 'waiting', performNextSearch);
}
function performNextSearch() {
if (!isSearching) return;
if (currentProgress.completed) {
updateStatus('搜索任务已完成!');
stopAutomatedSearch();
return;
}
const searchTerm = getSearchTerm();
if (!searchTerm) {
updateStatus('无可用搜索词,正在刷新词库...');
getRewardsData(() => {
const newSearchTerm = getSearchTerm();
if (newSearchTerm) {
updateStatus(`已获取新词: ${newSearchTerm}`);
performSearch(newSearchTerm, () => {
setTimeout(() => {
simulateScrolling(() => {
checkProgress(() => {
waitForNextSearch();
});
});
}, 2000);
});
} else {
updateStatus('无法获取搜索词,将休息后重试。');
startResting();
}
});
return;
}
const remainingSearches = currentProgress.total - currentProgress.current;
updateStatus(`正在搜索: ${searchTerm} [剩余约: ${remainingSearches > 0 ? remainingSearches : 'N/A'}]`);
let searchCallbackCalled = false;
function searchCallbackWrapper() {
if (searchCallbackCalled) return;
searchCallbackCalled = true;
setTimeout(() => {
simulateScrolling(() => {
checkProgress(() => {
waitForNextSearch();
});
});
}, 2000);
}
performSearch(searchTerm, searchCallbackWrapper);
setTimeout(searchCallbackWrapper, 18000); // 兜底防断链
}
function startResting() {
searchState.needRest = false;
currentProgress.noProgressCount = 0;
updateStatus(`连续 ${config.maxNoProgressCount} 次无进度,休息 ${config.restTime / 60} 分钟...`);
saveState();
startCountdown(config.restTime, 'resting', () => {
updateStatus('休息结束,继续搜索。');
performNextSearch();
});
}
function startAutomatedSearch() {
getRewardsData(() => {
if (currentProgress.completed) {
updateStatus('任务已完成,无需启动。');
return;
}
if (mainPageSearchTerms.length === 0 && iframeSearchTerms.length === 0) {
alert('未能获取任何搜索词,请检查是否已登录或页面是否正常。');
return;
}
startSearchProcess();
});
}
function startSearchProcess() {
isSearching = true;
saveState();
searchState.needRest = false;
currentProgress.noProgressCount = 0;
usedSearchTerms = [];
document.getElementById('start-search-btn').textContent = '停止搜索';
document.getElementById('start-search-btn').classList.add('stop');
updateStatus('自动搜索已开始...');
updateProgressUI();
updateSearchTermsUI();
performNextSearch();
}
function stopAutomatedSearch() {
if (countdownTimer) { clearInterval(countdownTimer); }
isSearching = false;
saveState();
searchState.currentAction = 'idle';
updateCountdown(0, '');
const startBtn = document.getElementById('start-search-btn');
if (startBtn) {
startBtn.textContent = '开始自动搜索';
startBtn.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); }
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 () {
loadState();
createUI();
applyCollapseState();
updateProgressUI();
updateSearchTermsUI();
if (isSearching) {
updateStatus('页面刷新,自动恢复继续自动搜索...');
document.getElementById('start-search-btn').textContent = '停止搜索';
document.getElementById('start-search-btn').classList.add('stop');
performNextSearch();
} else {
setTimeout(() => { getRewardsData(); }, 2000);
}
});
})();