// ==UserScript==
// @name Bing Rewards Lite (Win & Mac)
// @version 1.5
// @description v1.5 双模版 - 可在“快速模式(~42分)”与“超稳健模式(~60分)”间切换。
// ✨ 功能: 自定义次数/高级拟人化/触屏拖拽/热词/双模式计时
// @match https://*.bing.com/*
// @match https://*.bing.cn/*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_addStyle
// @grant GM_xmlhttpRequest
// @grant GM_setTimeout
// @grant GM_clearTimeout
// @grant GM_setInterval
// @grant GM_clearInterval
// @connect api.vvhan.com
// @connect api-hot.imsyy.top
// @license MIT
// @namespace https://greasyfork.org/users/737649
// @downloadURL https://update.greasyfork.icu/scripts/534088/Bing%20Rewards%20Lite%20%28Win%20%20Mac%29.user.js
// @updateURL https://update.greasyfork.icu/scripts/534088/Bing%20Rewards%20Lite%20%28Win%20%20Mac%29.meta.js
// ==/UserScript==
(function () {
/* ===== 基本配置 ===== */
const ID = 'bru_panel';
const VER = '1.5'; // 版本号更新
const TYPE = { min: 35, max: 80 };
const FALL = ['今日新闻', '天气预报', '电影票房', '体育比分', '股票行情'];
/* ===== 热榜接口(按优先级) ===== */
const HOT_APIS = [
'https://api.vvhan.com/api/hotlist/all', // 聚合
'https://api.vvhan.com/api/hotlist/wbHot', // 微博
'https://api-hot.imsyy.top/baidu?num=50' // 百度
];
/* ===== 兼容新版 Bing 选择器 ===== */
const SELECTORS = ['#sb_form_q','.b_searchbox','input[name="q"]','#searchboxinput','textarea[name="q"]'];
/* ===== 通用工具 ===== */
const tSet =(typeof GM_setTimeout ==='function'?GM_setTimeout :setTimeout);
const tClr =(typeof GM_clearTimeout==='function'?GM_clearTimeout:clearTimeout);
const iSet =(typeof GM_setInterval ==='function'?GM_setInterval :setInterval);
const iClr =(typeof GM_clearInterval==='function'?GM_clearInterval:clearInterval);
const z2=n=> (n<10?'0':'')+n;
/* ===== 状态记录 ===== */
const today = new Date().toISOString().slice(0,10);
// 新增 ultra_stable_mode 状态
const def = {date:today, pc:0, ph:0, running:true, max_pc: 40, max_ph: 30, ultra_stable_mode: false};
// 使用新的存储键,确保数据纯净
let rec = { ...def, ...GM_getValue('bru_lite_v15_final', {}) };
if(rec.date !== today) {
rec.date = today;
rec.pc = 0;
rec.ph = 0;
}
GM_setValue('bru_lite_v15_final', rec);
const mobile = /mobile|android|iphone|ipad|touch/i.test(navigator.userAgent);
const key = mobile ? 'ph' : 'pc';
let limit;
function updateLimit() {
limit = mobile ? rec.max_ph : rec.max_pc;
}
updateLimit();
/* ===== 热榜词 ===== */
let HOT = [];
async function fetchHot(){ for(const url of HOT_APIS){ try{ const json=await new Promise((ok,err)=>{ GM_xmlhttpRequest({method:'GET',url,onload:({responseText})=>{try{ok(JSON.parse(responseText));}catch(e){err(e);}},onerror:err}); }); HOT=parseHot(json); if(HOT.length) return; }catch{} } HOT=FALL; }
function parseHot(obj){ const words=[]; const seen=new Set(); const isWord=s=> typeof s==='string' && s.trim().length>0 && s.length<=40; const skipRe=/^(微博|知乎|百度|抖音|36氪|哔哩哔哩|IT资讯|虎嗅网|豆瓣|人人都是产品经理|热搜|热榜|API)/; function add(s){s=s.trim();if(isWord(s)&&!skipRe.test(s)&&!seen.has(s)){seen.add(s);words.push(s);}} function walk(v){ if(Array.isArray(v)){ v.forEach(walk); }else if(v&&typeof v==='object'){ if(v.title) add(v.title); if(v.keyword)add(v.keyword); if(v.name) add(v.name); if(v.word) add(v.word); for(const k of ['list','hotList','data','hot','children','items']){ if(v[k]) walk(v[k]); } } } const root=obj?.data??obj; walk(root); return words; }
/* ===== 样式 ===== */
GM_addStyle(`#${ID}{position:fixed;top:10px;right:10px;z-index:99999;width:200px;padding:10px 10px 8px 10px;font:11px/1.45 system-ui,-apple-system,BlinkMacSystemFont,sans-serif;color:#222;background:rgba(255,255,255,.55);backdrop-filter:blur(12px)saturate(1.4);border-radius:10px;box-shadow:0 4px 12px rgba(0,0,0,.18);overflow:visible;}#${ID} button{all:unset;font-size:10px;background:#3b82f6;color:#fff;border-radius:5px;padding:3px 8px;margin-left:4px;cursor:pointer;text-align:center;}#${ID} input[type="number"]{width:40px;font-size:10px;border:1px solid #ccc;border-radius:4px;padding:2px 4px;margin:0 4px;}#${ID} input[type="checkbox"]{vertical-align:middle;margin-right:4px;}.bar{height:4px;background:#d0d0d0;border-radius:3px;overflow:hidden;margin-top:3px}.fill{height:100%;width:100%;background:linear-gradient(90deg,#00b7ff,#00ffb7,#d4ff00,#ff6600,#ff00aa,#00b7ff);background-size:400% 100%;transform-origin:left;transition:transform .6s ease;animation:flow 5s linear infinite}@keyframes flow{0%{background-position:0 0}100%{background-position:100% 0}}.err{display:none;color:#e63946;font-weight:600;margin-top:2px;font-size:10px}.decor{position:absolute;right:4px;top:60px;width:32px;height:32px;border-radius:50%;background:conic-gradient(#00b7ff,#00ffb7,#d4ff00,#ff6600,#ff00aa,#00b7ff);animation:spin 7s linear infinite,pulse 3.5s ease-in-out infinite alternate;pointer-events:none;opacity:.75;filter:blur(1px) drop-shadow(0 0 4px rgba(0,0,0,.12));}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{from{transform:scale(.9)}to{transform:scale(1.05)}}`);
/* ===== 面板 ===== */
function buildPanel(){if(document.getElementById(ID))return;const box=document.createElement('div');box.id=ID;box.innerHTML=`
BR Lite 模式:${mobile?'手机':'桌面'}
状态:${rec.running?'运行中':'已暂停'}
下次:--s
计数:${rec[key]} / ${limit}
运行:00:00:00
热词获取失败!
v${VER}
`;document.body.append(box);const drag=document.getElementById('drag');let d=false,sx=0,sy=0,lx=0,ly=0; const isInteractive=e=>e.target.tagName==='BUTTON'||e.target.tagName==='INPUT'||e.target.tagName==='LABEL'; drag.onmousedown=e=>{if(e.button!==0||isInteractive(e))return;d=true;sx=e.clientX;sy=e.clientY;lx=box.offsetLeft;ly=box.offsetTop;document.onmousemove=ev=>{if(!d)return;box.style.left=lx+ev.clientX-sx+'px';box.style.top=ly+ev.clientY-sy+'px'};document.onmouseup=()=>{d=false;document.onmousemove=document.onmouseup=null}}; drag.ontouchstart=e=>{if(isInteractive(e))return;d=true;sx=e.touches[0].clientX;sy=e.touches[0].clientY;lx=box.offsetLeft;ly=box.offsetTop;document.ontouchmove=ev=>{if(!d)return;box.style.left=lx+ev.touches[0].clientX-sx+'px';box.style.top=ly+ev.touches[0].clientY-sy+'px'};document.ontouchend=()=>{d=false;document.ontouchmove=document.ontouchend=null}}; document.getElementById('run').onclick=toggle;document.getElementById('clr').onclick=()=>{rec.pc=rec.ph=0;GM_setValue('bru_lite_v15_final',rec);draw()};document.getElementById('save').onclick=()=>{const newPc=parseInt(document.getElementById('max_pc').value,10);const newPh=parseInt(document.getElementById('max_ph').value,10);if(!isNaN(newPc)&&newPc>0)rec.max_pc=newPc;if(!isNaN(newPh)&&newPh>0)rec.max_ph=newPh;GM_setValue('bru_lite_v15_final',rec);updateLimit();draw();const saveBtn=document.getElementById('save');saveBtn.textContent='已保存!';tSet(()=>saveBtn.textContent='保存',1500)};document.getElementById('mode_switch').onchange=function(){rec.ultra_stable_mode=this.checked;GM_setValue('bru_lite_v15_final',rec);};}
/* ===== UI 渲染 ===== */
const start=Date.now();
function draw(t='--'){document.getElementById('sta').textContent=rec.running?'运行中':'已暂停';document.getElementById('ctd').textContent=rec.running?t:'--';document.getElementById('num').textContent=rec[key];document.getElementById('limit').textContent=limit;document.getElementById('fill').style.transform=`scaleX(${Math.min(rec[key]/limit,1)})`;const d=Date.now()-start;document.getElementById('time').textContent=`${z2(d/3600000|0)}:${z2(d%3600000/60000|0)}:${z2(d%60000/1000|0)}`};
/* ===== 小工具 (核心拟人化升级) ===== */
function waitMs(){
if (rec.ultra_stable_mode) {
// “超稳健模式” (~60分钟完成)
const r = Math.random();
if (r < 0.6) { return (90 + Math.random() * 30) * 1000; } // 90-120秒
else { return (120 + Math.random() * 30) * 1000; } // 120-150秒
} else {
// “快速模式” (~42分钟完成)
const r = Math.random();
if (r < 0.33) { return (35 + Math.random() * 20) * 1000; } // 35-55秒
else if (r < 0.66) { return (60 + Math.random() * 30) * 1000; } // 60-90秒
else { return (100 + Math.random() * 50) * 1000; } // 100-150秒
}
}
async function preSearchHesitation() { await new Promise(r => tSet(r, 600 + Math.random() * 1400)); }
async function typeHuman(inp,str){ inp.focus(); inp.value=''; for(const c of str){ inp.value+=c; inp.dispatchEvent(new Event('input',{bubbles:true})); if (c === ' ') { await new Promise(r => tSet(r, 120 + Math.random() * 150)); } await new Promise(r=>tSet(r,TYPE.min+Math.random()*(TYPE.max-TYPE.min))) } }
async function advancedSoftScroll() { const h = document.body.scrollHeight - innerHeight; if (h <= 0) return; const scroll = (y, t) => new Promise(r => tSet(() => { window.scrollTo({ top: y, behavior: 'smooth' }); r(); }, t)); await scroll(h * (0.2 + Math.random() * 0.2), 300 + Math.random() * 300); await scroll(h * (0.5 + Math.random() * 0.2), 500 + Math.random() * 400); if (Math.random() < 0.3) { await scroll(h * (0.4 + Math.random() * 0.1), 400 + Math.random() * 200); } await scroll(h, 800 + Math.random() * 500); }
/* ===== 主循环 & 搜索动作 ===== */
let loopTimer=0,ctdTimer=0;
async function doSearch(){
try{
await preSearchHesitation();
const kw=HOT[Math.random()*HOT.length|0];
if(!kw)return;
let inp=null;
for(const sel of SELECTORS){inp=document.querySelector(sel);if(inp)break}
if(inp){
await typeHuman(inp,kw);
['keydown','keypress','keyup'].forEach(evt=>inp.dispatchEvent(new KeyboardEvent(evt,{key:'Enter',keyCode:13,which:13,bubbles:true,cancelable:true})));
const form=inp.closest('form');
if(form)form.submit();
tSet(()=>{if(location.pathname==='/'||location.pathname==='')location.href=`https://www.bing.com/search?q=${encodeURIComponent(kw)}`;},800);
rec[key]++;
GM_setValue('bru_lite_v15_final',rec);
await advancedSoftScroll();
} else {
rec[key]++;
GM_setValue('bru_lite_v15_final',rec);
location.href=`https://www.bing.com/search?q=${encodeURIComponent(kw)}`;
}
}
catch(e){console.error('[BR]',e)}
}
function loop(){if(!rec.running)return;if(rec[key]>=limit){stop();return}const w=waitMs();let c=w/1000|0;draw(c);ctdTimer=iSet(()=>{if(!rec.running){iClr(ctdTimer);return}draw(--c)},1000);loopTimer=tSet(async()=>{iClr(ctdTimer);await doSearch();loop()},w)}
function startLoop(){if(rec[key]>=limit)return;rec.running=true;GM_setValue('bru_lite_v15_final',rec);loop()}
function stop(){rec.running=false;GM_setValue('bru_lite_v15_final',rec);tClr(loopTimer);iClr(ctdTimer);draw()}
function toggle(){rec.running?stop():startLoop();document.getElementById('run').textContent=rec.running?'暂停':'启动'}
/* ===== 页面加载 ===== */
(async()=>{buildPanel();await fetchHot();if(HOT===FALL)document.getElementById('err').style.display='block';draw();if(rec.running)startLoop()})();
})();