// ==UserScript== // @name 微软积分商城签到 // @namespace https://github.com/geoi6sam1 // @version 3.0.4 // @description 每天自动完成 Microsoft Rewards 任务获取积分奖励,✅必应搜索(Web)、✅每日活动(Web)、✅更多活动(Web)、✅文章阅读(App)、✅每日签到(App) // @author geoi6sam1@qq.com // @icon https://store-images.s-microsoft.com/image/apps.58212.783a7d74-cf5a-4dca-aed6-b5722f311eca.f8c0cb0b-6b57-4f06-99b1-5d7ee04e38e6.517a44fd-f164-40ae-996b-f959198325c2 // @supportURL https://github.com/geoi6sam1/FuckScripts/issues // @crontab */20 * * * * // @grant unsafeWindow // @grant GM_xmlhttpRequest // @grant GM_notification // @grant GM_openInTab // @grant GM_getValue // @grant GM_setValue // @grant GM_log // @grant GM_registerMenuCommand // @connect bing.com // @connect *.bing.com // @connect rewards.bing.com // @connect login.live.com // @connect prod.rewardsplatform.microsoft.com // @connect dailyapi.eray.cc // @connect hot.baiwumm.com // @connect cnxiaobai.com // @connect hotapi.zhusun.top // @connect api-hot.imsyy.top // @connect hotapi.nntool.cc // @match https://login.live.com/oauth20_desktop.srf* // @license GPL-3.0 // ==/UserScript== /* ==UserConfig== Config: app: title: 微软必应App(每日签到 + 文章阅读) type: checkbox default: true limit: title: 限制搜索(每次运行只搜索 3-7 次) type: checkbox default: true span: title: 搜索间隔(默认15,即间隔 10-20 秒) type: number default: 15 min: 10 max: 300 unit: ±5秒 api: title: 搜索词接口(单机模式为随机汉字组句) type: select default: hot.nntool.cc values: [单机模式, hot.eray.cc, hot.baiwumm.com, hot.cnxiaobai.com, hot.zhusun.top, hot.imsyy.top, hot.nntool.cc] push: title: 全部任务完成后推送URL(留空则不推送) type: text default: "" testPush: title: 下次运行时测试一次Push URL type: checkbox default: false ==/UserConfig== */ const obj = { data: { time: { task: 3000 }, auth: { code: "https://login.live.com/oauth20_authorize.srf", token: "https://login.live.com/oauth20_token.srf", clientId: "0000000040170455", scope: "service::prod.rewardsplatform.microsoft.com::MBI_SSL", redirectUri: "https://login.live.com/oauth20_desktop.srf", }, ua: { pc: [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0", "Mozilla/5.0 (Sonoma; Intel Mac OS X 14_4_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/604.1 Edg/122.0.2365.106", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.2210.181", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.140", ], m: [ "Mozilla/5.0 (Linux; Android 14; 2211133C Build/UKQ1.230804.001; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36 EdgA/124.0.2478.64", "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36 EdgA/131.0.0.0", "Mozilla/5.0 (Linux; Android 14; 2210132C Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.52 Version/4.0 Mobile Safari/537.36 EdgA/125.0.2535.51", "Mozilla/5.0 (iPad; CPU OS 16_7_8 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) EdgiOS/120.0.2210.150 Version/16.0 Mobile/15E148 Safari/604.1", "Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) EdgiOS/123.0.2420.108 Version/18.0 Mobile/15E148 Safari/604.1", "Mozilla/5.0 (Linux; Android 10; HarmonyOS; ALN-AL10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Version/4.0 Mobile Safari/537.36 EdgA/110.0.1587.61", ], }, api: { arr: [ ["hot.eray.cc", { url: "https://dailyapi.eray.cc/", hot: ["weibo","douyin","baidu","toutiao","thepaper","qq-news","netease-news","zhihu"] }], ["hot.baiwumm.com", { url: "https://hot.baiwumm.com/api/", hot: ["weibo","douyin","baidu","toutiao","thepaper","qq","netease","zhihu"] }], ["hot.cnxiaobai.com", { url: "https://cnxiaobai.com/DailyHotApi/", hot: ["weibo","douyin","baidu","toutiao","thepaper","qq-news","netease-news","zhihu"] }], ["hot.zhusun.top", { url: "https://hotapi.zhusun.top/", hot: ["weibo","douyin","baidu","toutiao","thepaper","qq-news","netease-news","zhihu"] }], ["hot.imsyy.top", { url: "https://api-hot.imsyy.top/", hot: ["weibo","douyin","baidu","toutiao","thepaper","qq-news","netease-news","zhihu"] }], ["hot.nntool.cc", { url: "https://hotapi.nntool.cc/", hot: ["weibo","douyin","baidu","toutiao","thepaper","qq-news","netease-news","zhihu"] }] ] }, web: 0, app: 0 }, task: { sign: { times: 0, point: 1, end: 0 }, read: { times: 0, point: 0, end: 0 }, promo:{ times: 0, token: 0, end: 0 }, search:{ word:{ list:[], index:0 }, times:0, progressNow:0, pc:{ progress:0, max:1 }, m:{ progress:0, max:1 }, limit:{ min:2, max:6 }, index:0, end:0, }, token: 0, }, }; obj.getRandomNum = num => Math.floor(Math.random()*num); obj.getScopeRandomNum = (min,max)=> Math.floor(Math.random()*(max+1-min)+min); obj.getRandomArr = arr => arr.sort(()=>Math.random()-0.5); obj.getRandomChineseChar = ()=> String.fromCodePoint(Math.floor(Math.random()*(0x9FFF-0x4E00+1))+0x4E00); obj.generateRandomChineseStr = (min=6,max=32)=>{const len=Math.floor(Math.random()*(max-min+1))+min;let s="";for(let i=0;i i!=lastIndex); const randomIndex = obj.getRandomNum(filteredArr.length); GM_setValue("last_index", randomIndex); return filteredArr[randomIndex]; }; obj.pushMsg = function (title, text="") { title = "微软积分商城" + title; GM_log(title + (text?(" "+text):"")); GM_notification({ text, title, onclick: ()=> GM_openInTab("https://rewards.bing.com/pointsbreakdown",{active:true, insert:true, setParent:true}) }); }; obj.beforeStart = function(){ const dateTime = new Date(); const y = dateTime.getFullYear(); const m = ("0"+(dateTime.getMonth()+1)).slice(-2); const d = ("0"+dateTime.getDate()).slice(-2); obj.data.time.hoursNow = Number(dateTime.getHours()); obj.data.time.dateNow = `${m}/${d}/${y}`; obj.data.time.dateNowNum = Number(`${y}${m}${d}`); obj.task.search.limit.index = obj.getScopeRandomNum(obj.task.search.limit.min, obj.task.search.limit.max); if (GM_getValue("Config.api","单机模式")!="单机模式"){ const defaultApiName="hot.eray.cc"; const currentApiName=GM_getValue("Config.api",defaultApiName); const apiConfigMap=new Map(obj.data.api.arr); const getConfigApi=apiConfigMap.get(currentApiName)||apiConfigMap.get(defaultApiName); obj.data.api.url=getConfigApi.url; obj.data.api.hot=getConfigApi.hot; if(!apiConfigMap.has(currentApiName)){ GM_setValue("Config.api","单机模式"); obj.pushMsg("必应搜索🟣","当前搜索词接口失效!已替换成单机模式!"); } } }; /** 改:更鲁棒地获取 code(解析 finalUrl 的 ?code=,并日志/容错) */ obj.getCode = function (url) { return new Promise((resolve) => { GM_xmlhttpRequest({ method: "GET", url, onload(xhr){ GM_log(`[auth] authorize onload status=${xhr.status} finalUrl=${xhr.finalUrl}`); const finalUrl = xhr.finalUrl || ""; const m = finalUrl.match(/[?&]code=([^&]+)/); if (m && m[1]) { resolve(decodeURIComponent(m[1])); } else { resolve(xhr.status || 0); } }, onerror(){ GM_log("[auth] authorize onerror"); resolve(-1); }, ontimeout(){ GM_log("[auth] authorize ontimeout"); resolve(-2); } }); }); }; /** 改:用 POST 表单换取 token,成功时保存 refresh_token 并设置 access_token */ obj.postToken = function (kv) { return new Promise((resolve) => { const body = Object.entries(kv).map(([k,v])=>`${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&"); GM_xmlhttpRequest({ method: "POST", url: obj.data.auth.token, headers: { "Content-Type": "application/x-www-form-urlencoded" }, data: body, onload(xhr){ if (xhr.status==200){ try{ const res = JSON.parse(xhr.responseText||"{}"); const rt = res.refresh_token; const at = res.access_token; if (rt && at){ GM_setValue("refresh_token", rt); obj.task.token = at; resolve(1); return; } } catch(e){} resolve(0); } else { resolve(xhr.status); } }, onerror(){ resolve(-1); }, ontimeout(){ resolve(-2); } }); }); }; obj.getToken = function(url){ // 兼容旧调用(已不使用 GET 换 token) return new Promise((resolve) => { GM_xmlhttpRequest({ url, onload(xhr){ if (xhr.status==200){ try{ const res=JSON.parse(xhr.responseText); const rt=res.refresh_token, at=res.access_token; if (rt && at){ GM_setValue("refresh_token", rt); obj.task.token=at; resolve(1); return; } }catch(e){} resolve(0); } else resolve(xhr.status); }, onerror(){ resolve(-1); }, ontimeout(){ resolve(-2); } }); }); }; /** 改:修掉 xhr.status 引用错误;加入 try/catch;串 POST token */ obj.isExpired = async function(){ const cached = GM_getValue('oauth_code', ''); if (cached) { GM_setValue('oauth_code', ''); const ok = await obj.postToken({ grant_type: "authorization_code", client_id: obj.data.auth.clientId, code: cached, redirect_uri: obj.data.auth.redirectUri, scope: obj.data.auth.scope }); if (ok === 1) return; // 成功就直接返回,后续用 refresh_token } obj.tokenCallback = function (num){ if (obj.data.app > 2){ obj.task.sign.end++; obj.task.read.end++; obj.pushMsg("App授权🔴","Token获取失败,请检查微软账号登录状态!"); } else if (num != 1){ obj.data.app++; GM_setValue("refresh_token", 0); if (num == 0){ GM_log("App授权🟡RefreshToken过期,正在尝试重新获取..."); } else { GM_log(`App授权🟡AccessToken获取失败(状态码:${num}),正在重试...`); } setTimeout(()=>{ obj.isExpired(); }, obj.data.time.task); } }; try{ if (GM_getValue("refresh_token",0)==0){ const url = `${obj.data.auth.code}?client_id=${obj.data.auth.clientId}&scope=${obj.data.auth.scope}&response_type=code&redirect_uri=${obj.data.auth.redirectUri}`; const code = await obj.getCode(encodeURI(url)); if (typeof code == "number"){ if (obj.data.app > 2){ obj.task.sign.end++; obj.task.read.end++; obj.pushMsg("App授权🔴","授权Code获取失败,请检查微软账号登录状态!"); } else { obj.data.app++; GM_log(`App授权🟡授权Code获取失败(状态码:${code}),正在重试...`); setTimeout(()=>{ obj.isExpired(); }, obj.data.time.task); } } else { const token = await obj.postToken({ grant_type: "authorization_code", client_id: obj.data.auth.clientId, code, redirect_uri: obj.data.auth.redirectUri, scope: obj.data.auth.scope }); obj.tokenCallback(token); } } else { const token = await obj.postToken({ grant_type: "refresh_token", client_id: obj.data.auth.clientId, refresh_token: GM_getValue("refresh_token",0), scope: obj.data.auth.scope }); obj.tokenCallback(token); } } catch(e){ GM_log("isExpired() 异常:"+(e && e.stack || e)); setTimeout(()=>{ obj.isExpired(); }, obj.data.time.task); } }; obj.getRewardsInfo = function(){ return new Promise((resolve)=>{ GM_xmlhttpRequest({ url: "https://rewards.bing.com/api/getuserinfo?type=1", onload(xhr){ if (xhr.status==200){ let res = xhr.responseText; const data = res.match(/(\"dashboard\"?)/); if (data && data[0]){ res = JSON.parse(res); resolve(res.dashboard); } else { obj.task.sign.end++; obj.task.read.end++; obj.task.promo.end++; obj.task.search.end++; obj.data.web>0 || obj.pushMsg("All任务🔴","账号状态失效,请检查Microsoft登录状态或重新登录!"); obj.data.web++; resolve(0); } } else { GM_log(`微软积分商城Web任务🟡微软Rewards信息获取出错(状态码:${xhr.status}),正在重试...`); resolve(0); } } }); }); }; obj.getRewardsToken = function(){ return new Promise((resolve)=>{ GM_xmlhttpRequest({ url: "https://rewards.bing.com", onload(xhr){ if (xhr.status==200){ const html = (xhr.responseText||"").replace(/\s/g,""); const data = html.match(/RequestVerificationToken/); if (data && data[0]){ const token = html.match(/RequestVerificationToken"type="hidden"value="(.*?)"\/>/); resolve(token && token[1]); } else { obj.task.promo.end++; obj.pushMsg("活动推广🔴","请求验证失败,请检查Rewards登录状态或重新登录!"); resolve(0); } } else { GM_log(`微软积分商城Web任务🟡RequestVerificationToken获取出错(状态码:${xhr.status}),正在重试...`); resolve(0); } } }); }); }; obj.taskPromo = async function(){ GM_log("=== 开始活动推广任务 ==="); GM_log(`当前小时:${obj.data.time.hoursNow},promo.times:${obj.task.promo.times}`); if (obj.data.time.hoursNow < 12){ GM_log("⏱️ 时间未到 12 点,跳过推广"); obj.task.promo.end++; return true; } if (obj.task.promo.times > 2){ GM_log("🔄 已重试超过 2 次,放弃本次推广"); obj.task.promo.end++; obj.pushMsg("活动推广🔴","未知原因出错,本次活动推广结束!"); return true; } const dashboard = await obj.getRewardsInfo(); if (dashboard==0){ GM_log("❌ getRewardsInfo 返回 0"); return false; } let promotionsArr = []; const morePromotions = dashboard.morePromotions || []; const dailySetPromotions = dashboard.dailySetPromotions?.[obj.data.time.dateNow] || []; GM_log(`dailySetPromotions 数量:${dailySetPromotions.length},morePromotions 数量:${morePromotions.length}`); for (const p of [...dailySetPromotions, ...morePromotions]) { if (p.complete === false) promotionsArr.push({ offerId: p.offerId, hash: p.hash }); } GM_log("未完成的推广任务总数:", promotionsArr.length); obj.task.promo.token = await obj.getRewardsToken(); GM_log("请求校验 token:", obj.task.promo.token); if (!obj.task.promo.token){ GM_log("❌ getRewardsToken 返回空"); return false; } if (promotionsArr.length === 0){ GM_log("✅ 无待做推广,任务完成"); obj.task.promo.end++; if (GM_getValue("task_promo",0) !== obj.data.time.dateNowNum){ obj.pushMsg("活动推广🟢","哇!哥哥好棒!活动推广完成了!"); } GM_setValue("task_promo", obj.data.time.dateNowNum); return true; } GM_log("开始执行推广任务…"); promotionsArr.forEach(item=>{ GM_log(`→ 报告 offerId=${item.offerId||""},hash=${item.hash}`); GM_xmlhttpRequest({ method: "POST", url: `https://rewards.bing.com/api/reportactivity`, headers: { "Content-Type": "application/x-www-form-urlencoded", "Referer": `https://rewards.bing.com/` }, data: `id=${encodeURIComponent(item.offerId||"")}&hash=${encodeURIComponent(item.hash)}&__RequestVerificationToken=${encodeURIComponent(obj.task.promo.token)}`, onload(xhr){ GM_log(`reportactivity 状态码:${xhr.status}`); }, onerror(){ GM_log("reportactivity 请求失败"); } }); }); obj.task.promo.times++; GM_log(`本轮推广完成,promo.times 现在是 ${obj.task.promo.times}`); return false; }; obj.getReadPro = function(){ return new Promise((resolve)=>{ let readArr = { max:1, progress:0 }; GM_xmlhttpRequest({ url: "https://prod.rewardsplatform.microsoft.com/dapi/me?channel=SAAndroid&options=613", headers: { "authorization": `Bearer ${obj.task.token}` }, onload(xhr){ if (xhr.status==200){ try{ const res = JSON.parse(xhr.responseText||"{}"); const pro = res.response && res.response.promotions; if (pro){ for (const o of pro){ if (o.attributes.offerid == "ENUS_readarticle3_30points"){ readArr = { max:Number(o.attributes.max), progress:Number(o.attributes.progress) }; resolve(readArr); return; } } } }catch(e){} } resolve(readArr); } }); }); }; obj.taskRead = async function(){ if (obj.task.read.end>0) return true; else if (obj.data.time.hoursNow<12){ obj.task.read.end++; return true; } else if (obj.task.read.times>2){ obj.task.read.end++; obj.pushMsg("文章阅读🔴","未知原因出错,本次文章阅读结束!"); return true; } else if (obj.task.token==0) return false; else { const readPro = await obj.getReadPro(); if (readPro.progress > obj.task.read.point){ obj.task.read.times=0; obj.task.read.point=readPro.progress; } else { obj.task.read.times++; } if (readPro.progress >= readPro.max){ obj.task.read.end++; if (GM_getValue("task_read",0)!=obj.data.time.dateNowNum) obj.pushMsg("文章阅读🟢","哇!哥哥好棒!文章阅读完成了!"); GM_setValue("task_read", obj.data.time.dateNowNum); return true; } else { GM_setValue("task_read", 0); GM_xmlhttpRequest({ method: "POST", url: "https://prod.rewardsplatform.microsoft.com/dapi/me/activities", headers: { "Content-Type":"application/json", "authorization": `Bearer ${obj.task.token}` }, data: JSON.stringify({ amount:1, country:"cn", id:"", type:101, attributes:{ offerid:"ENUS_readarticle3_30points" } }), responseType: "json" }); return false; } } }; obj.taskSign = function(){ if (obj.task.sign.end>0 || GM_getValue("task_sign",0)==obj.data.time.dateNowNum){ obj.task.sign.end++; return true; } else if (obj.task.sign.times>2){ obj.task.sign.end++; obj.pushMsg("App签到🔴","未知原因出错,本次App签到结束!"); return true; } else if (obj.task.sign.point==0){ obj.task.sign.end++; if (GM_getValue("task_sign",0)!=obj.data.time.dateNowNum) obj.pushMsg("App签到🟢","哇!哥哥好棒!App签到完成了!"); GM_setValue("task_sign", obj.data.time.dateNowNum); return true; } else if (obj.task.token==0){ return false; } else { GM_xmlhttpRequest({ method: "POST", url: "https://prod.rewardsplatform.microsoft.com/dapi/me/activities", headers: { "Content-Type":"application/json", "authorization": `Bearer ${obj.task.token}` }, data: JSON.stringify({ amount:1, attributes:{ offerid:"Gamification_Sapphire_DailyCheckIn", date:obj.data.time.dateNowNum, signIn:false, timezoneOffset:"08:00:00" }, id:"", type:101, country:"cn", risk_context:{}, channel:"SAAndroid" }), responseType: "json", onload(xhr){ obj.task.sign.times=0; try{ const res = JSON.parse(xhr.responseText||"{}"); const point = res.response && res.response.activity && res.response.activity.p; obj.task.sign.point = point ? point : 0; }catch(e){ obj.task.sign.times++; } } }); return false; } }; obj.getTopKeyword = function(){ return new Promise((resolve)=>{ let sentence = obj.generateRandomChineseStr(); if (GM_getValue("Config.api","单机模式")=="单机模式"){ resolve(sentence); } else { if (obj.task.search.word.index<1 || obj.task.search.word.list.length<1){ const apiHot = obj.getRandomApiHot(); GM_xmlhttpRequest({ timeout: 9999, url: obj.data.api.url + apiHot, onload(xhr){ if (xhr.status==200){ try{ const res = JSON.parse(xhr.responseText||"{}"); if (res.code==200){ obj.task.search.word.index = 1; for (let i=0;i obj.task.search.word.list.length - 1) obj.task.search.word.index = 0; const s = obj.task.search.word.list[obj.task.search.word.index]; resolve(s); } } }); }; /** 改:移动端按真机参数拟真;失败/超时也累计 index;加调试日志 */ obj.taskSearch = async function () { if (obj.task.search.end > 0) return true; else { const dashboard = await obj.getRewardsInfo(); if (dashboard == 0) return false; else { if (dashboard.userStatus.counters.pcSearch) { obj.task.search.pc.progress = dashboard.userStatus.counters.pcSearch[0].pointProgress; obj.task.search.pc.max = dashboard.userStatus.counters.pcSearch[0].pointProgressMax; } if (dashboard.userStatus.counters.mobileSearch) { obj.task.search.m.progress = dashboard.userStatus.counters.mobileSearch[0].pointProgress; obj.task.search.m.max = dashboard.userStatus.counters.mobileSearch[0].pointProgressMax; } else obj.task.search.m.max = 0; GM_log(`[search] pc=${obj.task.search.pc.progress}/${obj.task.search.pc.max} m=${obj.task.search.m.progress}/${obj.task.search.m.max} index=${obj.task.search.index}/${obj.task.search.limit.index} limit=${GM_getValue("Config.limit", true)}`); if (GM_getValue("Config.limit", true) == true) { if (obj.task.search.index > obj.task.search.limit.index) { obj.task.search.end++; GM_log(`微软积分商城必应搜索🔵您已开启限制搜索,本次运行搜索 ${obj.task.search.index} 次结束!电脑搜索:${obj.task.search.pc.progress}/${obj.task.search.pc.max} 移动设备搜索:${obj.task.search.m.progress}/${obj.task.search.m.max}`); return true; } } else { if (obj.task.search.times > 2) { obj.task.search.end++; GM_log(`微软积分商城必应搜索🔵您的积分收入限制!本次运行共搜索 ${obj.task.search.index} 次!电脑搜索:${obj.task.search.pc.progress}/${obj.task.search.pc.max} 移动设备搜索:${obj.task.search.m.progress}/${obj.task.search.m.max}`); return true; } if (dashboard.userStatus.counters.dailyPoint[0].pointProgress == obj.task.search.progressNow) { obj.task.search.times++; } else { obj.task.search.times = 0; obj.task.search.progressNow = dashboard.userStatus.counters.dailyPoint[0].pointProgress; } } // 满额就收尾 if (obj.task.search.pc.progress >= obj.task.search.pc.max && obj.task.search.m.progress >= obj.task.search.m.max) { obj.task.search.end++; if (GM_getValue("task_search", 0) != obj.data.time.dateNowNum) obj.pushMsg("必应搜索🟢", "哇!哥哥好棒!必应搜索完成了!"); GM_setValue("task_search", obj.data.time.dateNowNum); return true; } else { GM_setValue("task_search", 0); // 取关键词 const keyword = await obj.getTopKeyword(); // PC:维持 www.bing.com(不影响移动计分) const pcUrl = `https://www.bing.com/search?q=${encodeURIComponent(keyword)}&qs=ds&FORM=QBLH`; // Mobile:严格按你真机两种形态(随机二选一) const mobileMode = Math.random() < 0.5 ? "bingApp" : "edgeApp"; let mUrl; if (mobileMode === "bingApp") { // 你给的 Bing 应用样本 // https://cn.bing.com/search?q=88&cc=CN&PC=SANSAAND&form=LWS001&ssp=1&darkschemeovr=1&safesearch=moderate&setlang=zh-hans mUrl = `https://cn.bing.com/search?q=${encodeURIComponent(keyword)}&cc=CN&PC=SANSAAND&form=LWS001&ssp=1&darkschemeovr=1&safesearch=moderate&setlang=zh-hans`; } else { // 你给的 Edge 应用样本 // https://cn.bing.com/search?q=v8888&setmkt=en-US&PC=EMMX01&form=LBT003&scope=web mUrl = `https://cn.bing.com/search?q=${encodeURIComponent(keyword)}&setmkt=en-US&PC=EMMX01&form=LBT003&scope=web`; } // 统一的发送函数(带上更像浏览器的头) const sendBing = (uaTag, uaVal, url, lang, referer) => { GM_xmlhttpRequest({ method: "GET", url, headers: { "User-Agent": uaVal, "Accept-Language": lang, "Referer": referer, // 以下为可选增强头(有些管理器可能会忽略,不强依赖) // "Upgrade-Insecure-Requests": "1", // "Sec-Fetch-Dest": "document", // "Sec-Fetch-Mode": "navigate", // "Sec-Fetch-Site": "none", }, onload() { obj.task.search.index++; GM_log(`[search] ${uaTag} onload index=${obj.task.search.index} url=${url}`); }, onerror() { obj.task.search.index++; GM_log(`[search] ${uaTag} onerror index=${obj.task.search.index}`); }, ontimeout() { obj.task.search.index++; GM_log(`[search] ${uaTag} ontimeout index=${obj.task.search.index}`); }, }); }; // PC 分支 if (obj.task.search.pc.progress < obj.task.search.pc.max) { const ua = obj.data.ua.pc[obj.getRandomNum(obj.data.ua.pc.length)]; sendBing("PC", ua, pcUrl, "zh-CN,zh;q=0.9", "https://www.bing.com/"); return false; } // 移动分支:只用手机 UA(优先 EdgA/EdgiOS),并用 cn.bing.com if (obj.task.search.m.progress < obj.task.search.m.max) { const mList = (obj.data.ua.m || []).filter(u => /EdgA|EdgiOS/.test(u)); const pool = mList.length ? mList : obj.data.ua.m; const ua = pool[obj.getRandomNum(pool.length)]; sendBing("M", ua, mUrl, "zh-CN,zh;q=0.9", "https://cn.bing.com/"); return false; } } } } }; return new Promise((resolve, reject)=>{ obj.beforeStart(); /** 改:taskEnd 判定 —— 若用户没开启 App,则不强制要求 sign.end>0 */ obj.taskEnd = function(){ const needSign = GM_getValue("Config.app", false); GM_log(`[DEBUG] taskEnd check sign.end=${obj.task.sign.end} search.end=${obj.task.search.end} needSign=${needSign}`); if ( (!needSign || obj.task.sign.end>0) && obj.task.search.end>0 ){ const pushUrl = (GM_getValue("Config.push","")||"").trim(); GM_notification({ title:"[DEBUG] taskEnd", text:"pushUrl="+pushUrl }); if (pushUrl){ GM_notification({ title:"签到脚本", text:"开始推送到:"+pushUrl }); GM_xmlhttpRequest({ method: "GET", url: pushUrl, onload(xhr){ GM_notification({ title:"Push 成功", text:"状态码:"+xhr.status }); resolve(); }, onerror(){ GM_notification({ title:"Push 失败", text:"检查 URL/网络" }); resolve(); } }); } else { GM_notification({ title:"[DEBUG] task End with fail", text:"pushUrl="+pushUrl }); resolve(); } } }; /** 一键测试 push */ async function testPushUrl(){ const pushUrl = (GM_getValue("Config.push","")||"").trim(); if (pushUrl){ GM_log("正在测试 Push URL:" + pushUrl); GM_xmlhttpRequest({ method: "GET", url: pushUrl, onload(xhr){ GM_log(`✅ Push URL测试成功,状态码: ${xhr.status}`); GM_notification({ title:"Push URL测试成功", text:`Push URL请求成功,状态码: ${xhr.status}` }); alert(`✅ Push URL测试成功\n状态码:${xhr.status}`); }, onerror(){ GM_log("❌ Push URL测试失败"); GM_notification({ title:"Push URL测试失败", text:"Push URL请求失败,请检查URL是否正确或网络问题!" }); alert("❌ Push URL测试失败,请检查URL或网络连接!"); } }); } else { GM_log("⚠️ Push URL为空,无法测试!"); GM_notification({ title:"Push URL为空", text:"请先填写Push URL后再测试!" }); alert("⚠️ Push URL为空,请先填写后再测试!"); } GM_setValue("Config.testPush", false); } if (GM_getValue("Config.testPush", false)) testPushUrl(); /** 菜单:① 打开授权页(顶层带 Cookie) ② 粘贴 code 换 token */ GM_registerMenuCommand("① 打开微软授权页(登录/同意后复制 code)", ()=>{ const authUrl = `${obj.data.auth.code}?client_id=${obj.data.auth.clientId}&scope=${obj.data.auth.scope}&response_type=code&redirect_uri=${obj.data.auth.redirectUri}`; GM_openInTab(authUrl, { active:true }); obj.pushMsg("App授权🟡","已打开授权页,请在浏览器里完成登录/同意后,复制地址栏 code=... 的值。"); }); GM_registerMenuCommand("② 粘贴 code 并换取 token(保存 refresh_token)", async ()=>{ const code = prompt("请粘贴 oauth20_desktop.srf 地址栏中的 code= 后面的值:"); if (!code) return; const ok = await obj.postToken({ grant_type: "authorization_code", client_id: obj.data.auth.clientId, code: code.trim(), redirect_uri: obj.data.auth.redirectUri, scope: obj.data.auth.scope }); if (ok===1){ GM_notification({title:"授权成功", text:"已保存 refresh_token;后续将自动刷新。"}); } else { GM_notification({title:"授权失败", text:"请检查 code 是否正确,或稍后再试。"}); } }); /** 启动各任务 */ obj.signStart = async function(){ try{ const r = await obj.taskSign(); r ? obj.taskEnd() : setTimeout(()=>{ obj.signStart(); }, obj.data.time.task); }catch(e){ reject(e); } }; obj.readStart = async function(){ try{ const r = await obj.taskRead(); r ? obj.taskEnd() : setTimeout(()=>{ obj.readStart(); }, obj.data.time.task); }catch(e){ reject(e); } }; obj.promoStart= async function(){ try{ const r = await obj.taskPromo(); r ? obj.taskEnd() : setTimeout(()=>{ obj.promoStart(); }, obj.data.time.task); }catch(e){ reject(e); } }; obj.searchStart= async function(){ try{ const r = await obj.taskSearch(); const timespan = GM_getValue("Config.span",15)*1000; r ? obj.taskEnd() : setTimeout(()=>{ obj.searchStart(); }, obj.getScopeRandomNum(timespan-5000, timespan+5000)); }catch(e){ reject(e); } }; obj.taskStart = function(){ if (GM_getValue("Config.app", false)==true){ obj.isExpired(); // 自动尝试 code/refresh } else { obj.task.sign.end++; // 未开启 App,直接视为签到完成 obj.task.read.end++; } obj.promoStart(); obj.signStart(); obj.readStart(); obj.searchStart(); }(); });