Bing Rewards Lite (Win & Mac)

自动搜索热榜词刷积分(桌面 40 / 手机 30);兼容新版 Bing / Copilot Search

// ==UserScript==
// @name         Bing Rewards Lite (Win & Mac)
// @version      1.2
// @description  自动搜索热榜词刷积分(桌面 40 / 手机 30);兼容新版 Bing / Copilot Search             
// @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-hot.imsyy.top
// @license      MIT
// @namespace    https://greasyfork.org/users/737649
// ==/UserScript==

(function () {
/* ===== 基本配置 ===== */
const ID   = 'bru_panel';
const VER  = '1.2';
const MAX  = { pc: 40, ph: 30 };
const TYPE = { min: 35, max: 80 };
const SCROLL_TIMES = 4;
const FALL = ['今日新闻','天气预报','电影票房','体育比分','股票行情'];

/* ===== 兼容新版 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);
const def   = { date: today, pc: 0, ph: 0, running: true };
let   rec   = GM_getValue('bru_lite', def);
if (rec.date !== today) { rec = { ...def }; GM_setValue('bru_lite', rec); }

const mobile = /mobile|android|iphone|ipad|touch/i.test(navigator.userAgent);
const key    = mobile ? 'ph' : 'pc';
const limit  = mobile ? MAX.ph : MAX.pc;

/* ===== 热榜词 ===== */
let HOT = [];
function fetchHot() {
  return new Promise(done => {
    GM_xmlhttpRequest({
      method: 'GET', url: 'https://api-hot.imsyy.top/baidu?num=50',
      onload: ({ responseText }) => {
        try { HOT = JSON.parse(responseText).data.map(x => x.title).filter(Boolean); }
        catch { HOT = []; }
        if (!HOT.length) HOT = FALL;
        done();
      },
      onerror: () => { HOT = FALL; done(); }
    });
  });
}

/* ===== 样式(保持不变) ===== */
GM_addStyle(`
#${ID}{position:fixed;top:10px;right:10px;z-index:99999;width:190px;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}
.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:46px;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)}}
`);

/* ===== 页面加载后:延迟下滑 ===== */
window.addEventListener('load', () => tSet(() => softScroll(), 1000 + Math.random()*1500));

/* ===== 面板(未改动) ===== */
function buildPanel(){if(document.getElementById(ID))return;const box=document.createElement('div');box.id=ID;box.innerHTML=`<div id="drag" style="display:flex;justify-content:space-between;user-select:none;cursor:move;margin-bottom:2px"><b>BR Lite</b><div><button id="run">${rec.running?'暂停':'启动'}</button><button id="clr">清零</button></div></div><div><div>模式:<b>${mobile?'手机':'桌面'}</b></div><div>状态:<b id="sta">${rec.running?'运行中':'已暂停'}</b></div><div>下次:<b id="ctd">--</b>s</div><div>计数:<span id="num">${rec[key]}</span> / ${limit}</div><div class="bar"><div class="fill" id="fill"></div></div><div style="font-size:9px;margin-top:1px">运行:<span id="time">00:00:00</span></div><div class="err" id="err">热词获取失败!</div></div><div style="font-size:9px;text-align:right;margin-top:2px">v${VER}</div><div class="decor"></div>`;document.body.append(box);const drag=document.getElementById('drag');let d=false,sx=0,sy=0,lx=0,ly=0;drag.onmousedown=e=>{if(e.button!==0||e.target.tagName==='BUTTON')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}};document.getElementById('run').onclick=toggle;document.getElementById('clr').onclick=()=>{rec.pc=rec.ph=0;GM_setValue('bru_lite',rec);draw()}};

/* ===== 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('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(){const r=Math.random();if(r<.25)return(10+Math.random()*10)*1000;if(r<.75)return(20+Math.random()*20)*1000;return(40+Math.random()*40)*1000}
async function typeHuman(inp,str){inp.focus();inp.value='';for(const c of str){inp.value+=c;inp.dispatchEvent(new Event('input',{bubbles:true}));await new Promise(r=>tSet(r,TYPE.min+Math.random()*(TYPE.max-TYPE.min)))}}
function softScroll(){const h=document.body.scrollHeight-innerHeight;for(let i=0;i<SCROLL_TIMES;i++)tSet(()=>scrollTo({top:Math.random()*h,behavior:'smooth'}),i*120)}

/* ===== 主循环 & 搜索动作 ===== */
let loopTimer=0,ctdTimer=0;
async function doSearch(){try{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);
  // 触发 3 种回车方式,保证成功
  ['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();
  // 800ms 后若仍在主页,则强制跳转
  tSet(()=>{if(location.pathname==='/'||location.pathname==='')location.href=`https://www.bing.com/search?q=${encodeURIComponent(kw)}`;},800);
  rec[key]++;GM_setValue('bru_lite',rec);softScroll();
}else{
  rec[key]++;GM_setValue('bru_lite',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',rec);loop()}function stop(){rec.running=false;GM_setValue('bru_lite',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()})();
})();