diff --git a/52pojie-DailyBonus/52pojie.js b/52pojie-DailyBonus/52pojie.js index 52572b8bdc..c7e169b703 100644 --- a/52pojie-DailyBonus/52pojie.js +++ b/52pojie-DailyBonus/52pojie.js @@ -1,7 +1,7 @@ /* 吾爱破解签到脚本 -更新时间: 2021.09.22 +更新时间: 2022.6.18 脚本兼容: QuantumultX, Surge, Loon, Node.js 电报频道: @NobyDa 问题反馈: @NobyDa_bot @@ -16,7 +16,7 @@ QX, Surge, Loon说明: ************************ Node.js说明: ************************ -需自行安装"got"与"tough-cookie"模块. 例: npm install got tough-cookie -g +需自行安装"got"与"iconv-lite"模块. 例: npm install got iconv-lite -g 抓取Cookie说明: 浏览器打开 https://www.52pojie.cn/home.php 登录账号后, 开启抓包软件并刷新页面. @@ -69,79 +69,65 @@ http-request https:\/\/www\.52pojie\.cn\/home\.php\? script-path=https://raw.git hostname= www.52pojie.cn */ -var $ = new Env('吾爱破解'); -var date = new Date() -if (typeof $request != "undefined") { +const $ = API('nobyda_52pojie'); +const date = new Date(); +const reqData = { + url: 'https://www.52pojie.cn/home.php?mod=task&do=apply&id=2', + headers: { + Cookie: CookieWA || $.read("COOKIE"), + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0", + } +}; +if ($.env.isRequest) { GetCookie() +} else if (!reqData.headers.Cookie) { + $.notify('吾爱破解', ``, `未填写/未获取Cookie!`); +} else if (!reqData.headers.Cookie.includes('_auth=')) { + $.notify('吾爱破解', ``, `Cookie关键授权字段缺失, 需重新获取!`); } else { - checkin() -} - -function checkin() { - $.get({ - url: 'https://www.52pojie.cn/home.php?mod=task&do=apply&id=2&mobile=no', - headers: { - Cookie: CookieWA || $.getdata("CookieWA"), - } - }, async function(error, response, data) { - if (error && !data) { - $.msgBody = `签到请求失败 ‼️‼️\n${error}` - } else { - if (data.match(/(ÒÑÍê³É|\u606d\u559c\u60a8|��̳΢�š��ᰮ�ƽ�)/)) { + $.http.put(reqData) + .then((resp) => { + if (resp.body.match(/(ÒÑÍê³É|\u606d\u559c\u60a8|��̳΢�š��ᰮ�ƽ�)/)) { $.msgBody = date.getMonth() + 1 + "月" + date.getDate() + "日, 签到成功 🎉" - } else if (data.match(/(ÄúÒÑ|\u4e0b\u671f\u518d\u6765|>��Ǹ������)/)) { + } else if (resp.body.match(/(ÄúÒÑ|\u4e0b\u671f\u518d\u6765|>��Ǹ������)/)) { $.msgBody = date.getMonth() + 1 + "月" + date.getDate() + "日, 已签过 ⚠️" - } else if (data.match(/(ÏȵǼ|\u9700\u8981\u5148\u767b\u5f55|�Ҫ�ȵ�¼���ܼ�)/)) { + } else if (resp.body.match(/(ÏȵǼ|\u9700\u8981\u5148\u767b\u5f55|�Ҫ�ȵ�¼���ܼ�)/)) { $.msgBody = "签到失败, Cookie失效 ‼️‼️" - } else if (response.statusCode == 403) { + } else if (resp.statusCode == 403) { $.msgBody = "服务器暂停签到 ⚠️" } else { $.msgBody = "脚本待更新 ‼️‼️" } - } - if (barkKey) { - await BarkNotify($, barkKey, $.name, $.msgBody); - } - $.msg($.name, ``, $.msgBody); - $.done(); - }) + }) + .catch((err) => ($.msgBody = `签到失败 ‼️‼️\n${err || err.message}`)) + .finally(async () => { + if (barkKey) { + await BarkNotify($, barkKey, '吾爱破解', $.msgBody); + } + $.notify('吾爱破解', ``, $.msgBody); + $.done(); + }) } function GetCookie() { - try { - if ($request.headers && $request.url.match(/www\.52pojie\.cn/)) { - var CookieName = "吾爱破解"; - var CookieKey = "CookieWA"; - var CookieValue = $request.headers['Cookie']; - if ($.getdata(CookieKey)) { - if ($.getdata(CookieKey) != CookieValue) { - var cookie = $.setdata(CookieValue, CookieKey); - if (!cookie) { - $.msg("", "", "更新" + CookieName + "Cookie失败 ‼️"); - } else { - $.msg("", "", "更新" + CookieName + "Cookie成功 🎉"); - } - } - } else { - var cookie = $.setdata(CookieValue, CookieKey); - if (!cookie) { - $.msg("", "", "首次写入" + CookieName + "Cookie失败 ‼️"); - } else { - $.msg("", "", "首次写入" + CookieName + "Cookie成功 🎉"); - } - } + const TM = $.read("TIME"); + const CK = $request.headers['Cookie'] || $request.headers['cookie']; + if (CK && CK.includes('_auth=')) { + $.write(CK, "COOKIE"); + if (!TM || TM && (Date.now() - TM) / 1000 >= 21600) { + $.notify("吾爱破解", "", `写入Cookie成功 🎉`); + $.write(JSON.stringify(Date.now()), "TIME"); } else { - $.msg("写入Cookie失败", "", "请检查匹配URL或配置内脚本类型 ‼️"); + $.info(`吾爱破解\n写入Cookie成功 🎉`) } - } catch (eor) { - $.msg("写入Cookie失败", "", "未知错误 ‼️") - $.log(JSON.stringify(eor) + "\n" + eor + "\n" + JSON.stringify($request.headers)) + } else { + $.info(`吾爱破解\n写入Cookie失败, 关键值缺失`) } - $.done(); + $.done() } //Bark APP notify -async function BarkNotify(c,k,t,b){for(let i=0;i<3;i++){console.log(`🔷Bark notify >> Start push (${i+1})`);const s=await new Promise((n)=>{c.post({url:'https://api.day.app/push',headers:{'Content-Type':'application/json'},body:JSON.stringify({title:t,body:b,device_key:k,ext_params:{group:t}})},(e,r,d)=>r&&r.status==200?n(1):n(d||e))});if(s===1){console.log('✅Push success!');break}else{console.log(`❌Push failed! >> ${s.message||s}`)}}}; +async function BarkNotify(c, k, t, b) { for (let i = 0; i < 3; i++) { console.log(`🔷Bark notify >> Start push (${i + 1})`); const s = await new Promise((n) => { c.post({ url: 'https://api.day.app/push', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: t, body: b, device_key: k, ext_params: { group: t } }) }, (e, r, d) => r && r.status == 200 ? n(1) : n(d || e)) }); if (s === 1) { console.log('✅Push success!'); break } else { console.log(`❌Push failed! >> ${s.message || s}`) } } }; -//Compatible code from https://github.com/chavyleung/scripts/blob/master/Env.min.js -function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("","")}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),a={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(a,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon()?(this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)})):this.isQuanX()?(this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t))):this.isNode()&&(this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>{const{message:s,response:i}=t;e(s,i,i&&i.body)}))}post(t,e=(()=>{})){if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.post(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method="POST",this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){this.initGotEnv(t);const{url:s,...i}=t;this.got.post(s,i).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>{const{message:s,response:i}=t;e(s,i,i&&i.body)})}}time(t){let e={"M+":(new Date).getMonth()+1,"d+":(new Date).getDate(),"H+":(new Date).getHours(),"m+":(new Date).getMinutes(),"s+":(new Date).getSeconds(),"q+":Math.floor(((new Date).getMonth()+3)/3),S:(new Date).getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,((new Date).getFullYear()+"").substr(4-RegExp.$1.length)));for(let s in e)new RegExp("("+s+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?e[s]:("00"+e[s]).substr((""+e[s]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl;return{"open-url":e,"media-url":s}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r)));let h=["",""];h.push(e),s&&h.push(s),i&&h.push(i),console.log(h.join("\n")),this.logs=this.logs.concat(h)}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`${s} \u79d2`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)} \ No newline at end of file +//https://github.com/Peng-YM/QuanX/tree/master/Tools/OpenAPI +function ENV() { const e = "function" == typeof require && "undefined" != typeof $jsbox; return { isQX: "undefined" != typeof $task, isLoon: "undefined" != typeof $loon, isSurge: "undefined" != typeof $httpClient && "undefined" == typeof $loon, isBrowser: "undefined" != typeof document, isNode: "function" == typeof require && !e, isJSBox: e, isRequest: "undefined" != typeof $request, isScriptable: "undefined" != typeof importModule } } function HTTP(e = { baseURL: "" }) { function t(t, a) { a = "string" == typeof a ? { url: a } : a; const h = e.baseURL; h && !d.test(a.url || "") && (a.url = h ? h + a.url : a.url), a.body && a.headers && !a.headers["Content-Type"] && (a.headers["Content-Type"] = "application/x-www-form-urlencoded"), a = { ...e, ...a }; const c = a.timeout, l = { onRequest: () => { }, onResponse: e => e, onTimeout: () => { }, ...a.events }; let f, y; if (l.onRequest(t, a), s) f = $task.fetch({ method: t, ...a }); else if (o || n) f = new Promise((e, s) => { $httpClient[t.toLowerCase()](a, (t, o, n) => { t ? s(t) : e({ statusCode: o.status || o.statusCode, headers: o.headers, body: n }) }) }); else if (r) { const e = require("got"), s = require("iconv-lite"); f = new Promise((o, n) => { e[t.toLowerCase()](a).then(e => o({ statusCode: e.statusCode, headers: e.headers, body: s.decode(e.rawBody, "utf-8") })).catch(n) }) } else if (i) { const e = new Request(a.url); e.method = t, e.headers = a.headers, e.body = a.body, f = new Promise((t, s) => { e.loadString().then(s => { t({ statusCode: e.response.statusCode, headers: e.response.headers, body: s }) }).catch(e => s(e)) }) } else u && (f = new Promise((e, s) => { fetch(a.url, { method: t, headers: a.headers, body: a.body }).then(e => e.json()).then(t => e({ statusCode: t.status, headers: t.headers, body: t.data })).catch(s) })); const p = c ? new Promise((e, s) => { y = setTimeout(() => (l.onTimeout(), s(`${t} URL: ${a.url} exceeds the timeout ${c} ms`)), c) }) : null; return (p ? Promise.race([p, f]).then(e => (clearTimeout(y), e)) : f).then(e => l.onResponse(e)) } const { isQX: s, isLoon: o, isSurge: n, isScriptable: i, isNode: r, isBrowser: u } = ENV(), a = ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH"], d = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/, h = {}; return a.forEach(e => h[e.toLowerCase()] = (s => t(e, s))), h } function API(e = "untitled", t = !1) { const { isQX: s, isLoon: o, isSurge: n, isNode: i, isJSBox: r, isScriptable: u } = ENV(); return new class { constructor(e, t) { this.name = e, this.debug = t, this.http = HTTP(), this.env = ENV(), this.node = (() => { if (i) { const e = require("fs"); return { fs: e } } return null })(), this.initCache(); const s = (e, t) => new Promise(function (s) { setTimeout(s.bind(null, t), e) }); Promise.prototype.delay = function (e) { return this.then(function (t) { return s(e, t) }) } } initCache() { if (s && (this.cache = JSON.parse($prefs.valueForKey(this.name) || "{}")), (o || n) && (this.cache = JSON.parse($persistentStore.read(this.name) || "{}")), i) { let e = "root.json"; this.node.fs.existsSync(e) || this.node.fs.writeFileSync(e, JSON.stringify({}), { flag: "wx" }, e => console.log(e)), this.root = {}, e = `${this.name}.json`, this.node.fs.existsSync(e) ? this.cache = JSON.parse(this.node.fs.readFileSync(`${this.name}.json`)) : (this.node.fs.writeFileSync(e, JSON.stringify({}), { flag: "wx" }, e => console.log(e)), this.cache = {}) } } persistCache() { const e = JSON.stringify(this.cache, null, 2); s && $prefs.setValueForKey(e, this.name), (o || n) && $persistentStore.write(e, this.name), i && (this.node.fs.writeFileSync(`${this.name}.json`, e, { flag: "w" }, e => console.log(e)), this.node.fs.writeFileSync("root.json", JSON.stringify(this.root, null, 2), { flag: "w" }, e => console.log(e))) } write(e, t) { if (this.log(`SET ${t}`), -1 !== t.indexOf("#")) { if (t = t.substr(1), n || o) return $persistentStore.write(e, t); if (s) return $prefs.setValueForKey(e, t); i && (this.root[t] = e) } else this.cache[t] = e; this.persistCache() } read(e) { return this.log(`READ ${e}`), -1 === e.indexOf("#") ? this.cache[e] : (e = e.substr(1), n || o ? $persistentStore.read(e) : s ? $prefs.valueForKey(e) : i ? this.root[e] : void 0) } delete(e) { if (this.log(`DELETE ${e}`), -1 !== e.indexOf("#")) { if (e = e.substr(1), n || o) return $persistentStore.write(null, e); if (s) return $prefs.removeValueForKey(e); i && delete this.root[e] } else delete this.cache[e]; this.persistCache() } notify(e, t = "", a = "", d = {}) { const h = d["open-url"], c = d["media-url"]; if (s && $notify(e, t, a, d), n && $notification.post(e, t, a + `${c ? "\n多媒体:" + c : ""}`, { url: h }), o) { let s = {}; h && (s.openUrl = h), c && (s.mediaUrl = c), "{}" === JSON.stringify(s) ? $notification.post(e, t, a) : $notification.post(e, t, a, s) } if (i || u) { const s = a + (h ? `\n点击跳转: ${h}` : "") + (c ? `\n多媒体: ${c}` : ""); if (r) { const o = require("push"); o.schedule({ title: e, body: (t ? t + "\n" : "") + s }) } else console.log(`${e}\n${t}\n${s}\n\n`) } } log(e) { this.debug && console.log(`[${this.name}] LOG: ${this.stringify(e)}`) } info(e) { console.log(`[${this.name}] INFO: ${this.stringify(e)}`) } error(e) { console.log(`[${this.name}] ERROR: ${this.stringify(e)}`) } wait(e) { return new Promise(t => setTimeout(t, e)) } done(e = {}) { s || o || n ? $done(e) : i && !r && "undefined" != typeof $context && ($context.headers = e.headers, $context.statusCode = e.statusCode, $context.body = e.body) } stringify(e) { if ("string" == typeof e || e instanceof String) return e; try { return JSON.stringify(e, null, 2) } catch (e) { return "[object Object]" } } }(e, t) } \ No newline at end of file diff --git a/BDTieBa-DailyBonus/TieBa.js b/BDTieBa-DailyBonus/TieBa.js index a5c9984c0c..104b018db5 100644 --- a/BDTieBa-DailyBonus/TieBa.js +++ b/BDTieBa-DailyBonus/TieBa.js @@ -1,57 +1,32 @@ -/* +/********************************* 百度贴吧签到脚本 -脚本修改自: https://github.com/sazs34/TaskConfig -兼容: QuantumultX, Surge4, Loon +脚本原作者: @sazs34 +平台兼容: QuantumultX, Surge, Loon +更新日期: 2024/06/01 获取Cookie说明: -打开百度贴吧App后(AppStore中国区, 非内部版),点击"我的", 如通知成功获取cookie, 则可以使用此签到脚本. -获取Cookie后, 请将Cookie脚本禁用并移除主机名,以免产生不必要的MITM. -脚本将在每天上午9:00执行, 您可以修改执行时间。 +打开百度贴吧App后(AppStore中国区, 非内部版),点击"我的", 如通知成功获取cookie则可以使用该脚本. -************************ -Surge 4.2.0+ 脚本配置: -************************ +********************************* +Surge(iOS 5.9.0+/macOS 5.5.0+)模块: +https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/TieBaDailyBonus.sgmodule -[Script] -贴吧签到 = type=cron,cronexp=0 9 * * *,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js +********************************* +QuantumultX 任务仓库(Gallery)订阅: +https://raw.githubusercontent.com/NobyDa/Script/master/NobyDa_BoxJs.json -贴吧获取Cookie = type=http-request,pattern=https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js +工具&分析->HTTP请求->右上角添加任务仓库->选择百度贴吧签到脚本添加定时任务和附加组件 -[MITM] -hostname= c.tieba.baidu.com +********************************* +Loon 脚本订阅(非插件): +https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_Daily_bonus.plugin -************************ -QuantumultX 本地脚本配置: -************************ +添加后请按需启用脚本 -[task_local] -# 贴吧签到 -0 9 * * * TieBa.js +*********************************/ -[rewrite_local] -# 获取Cookie -https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login url script-request-header TieBa.js -[mitm] -hostname= c.tieba.baidu.com - -************************ -Loon 2.1.0+ 脚本配置: -************************ - -[Script] -# 贴吧签到 -cron "0 9 * * *" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js - -# 获取Cookie -http-request https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login script-path=https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js - -[Mitm] -hostname= c.tieba.baidu.com - - -*/ var $nobyda = nobyda(); var cookieVal = $nobyda.read("CookieTB"); var useParallel = 0; //0自动切换,1串行,2并行(当贴吧数量大于30个以后,并行可能会导致QX崩溃,所以您可以自动切换) @@ -254,31 +229,18 @@ function checkIsAllProcessed() { } function GetCookie() { - var headerCookie = $request.headers["Cookie"]; - if (headerCookie) { - if ($nobyda.read("CookieTB") != undefined) { - if ($nobyda.read("CookieTB") != headerCookie) { - if (headerCookie.indexOf("BDUSS") != -1) { - var cookie = $nobyda.write(headerCookie, "CookieTB"); - if (!cookie) { - $nobyda.notify("更新贴吧Cookie失败‼️", "", ""); - } else { - $nobyda.notify("更新贴吧Cookie成功 🎉", "", ""); - } - } - } - } else { - if (headerCookie.indexOf("BDUSS") != -1) { - var cookie = $nobyda.write(headerCookie, "CookieTB"); - if (!cookie) { - $nobyda.notify("首次写入贴吧Cookie失败‼️", "", ""); - } else { - $nobyda.notify("首次写入贴吧Cookie成功 🎉", "", ""); - } + let headerCookie = $request.headers["Cookie"] || $request.headers["cookie"]; + if (headerCookie && headerCookie.includes('BDUSS=')) { + if (!cookieVal) { + $nobyda.notify("写入百度贴吧Cookie成功 🎉", "", ""); + } else { + console.log(`写入百度贴吧Cookie成功 🎉`); } - } + $nobyda.write(headerCookie, "CookieTB") + } else { + console.log(`写入Cookie失败, BDUSS值缺失. `); } - $nobyda.done() + return $nobyda.done(); } function nobyda() { diff --git a/Bahamut/BahamutAnimeAds.js b/Bahamut/BahamutAnimeAds.js new file mode 100644 index 0000000000..09a88fcc7e --- /dev/null +++ b/Bahamut/BahamutAnimeAds.js @@ -0,0 +1,68 @@ +/************************ + +动画疯,屏蔽播放广告脚本 (黑屏25秒自动播放) +由于动画疯强制验证观看广告时间,无法实现真正意义上的跳过广告。 + +Surge(4.11+)模块: +https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/BahamutAnimeAds.sgmodule + +QX(1.0.27+)用户请自行搭配KOP-XIAO资源解析器重写引用Surge模块。 + +************************/ + +let [req, rsp] = [$request, JSON.parse($response.body || '{}')]; + +runs().catch((err) => { + console.log(`[BahamutAnime] ERROR: ${err.message||err}`) +}).finally(() => $done({ + body: JSON.stringify(rsp) +})); + +async function runs() { + if (req.url.includes('token.php')) { + if (rsp.ad) { + rsp.ad.minor = []; + rsp.ad.major = []; + } + if (rsp.data && rsp.data.ad) { + rsp.data.ad.minor = []; + rsp.data.ad.major = []; + } + } + if (req.url.includes('m3u8.php') && (rsp.message || rsp.error)) { + await adURL(''); + await new Promise(r => setTimeout(r, 25000)); + await adURL('end'); + rsp = await playURL(); + } +} + +function adURL(str) { + return new Promise((res) => { + get({ + url: `https://api.gamer.com.tw/mobile_app/anime/v1/stat_ad.php?ad=${str}&schedule=0&sn=${req.url.split(/sn=(\d+)/i)[1]}`, + headers: req.headers + }, (err, resp, data) => res()) + }) +} + +function playURL() { + return new Promise((res) => { + get({ + url: req.url, + headers: req.headers + }, (err, resp, data) => res(JSON.parse(data || '{}'))) + }) +} + +function get(options, callback) { + if (typeof $task != "undefined") { + $task.fetch(options).then(response => { + response["status"] = response.statusCode + callback(null, response, response.body) + }, reason => callback(reason.error, null, null)) + } + if (typeof $httpClient != "undefined") { + $httpClient.get(options, callback) + } +} \ No newline at end of file diff --git a/Bilibili-DailyBonus/ExchangePoints.js b/Bilibili-DailyBonus/ExchangePoints.js index 811e34634c..f66e06761b 100644 --- a/Bilibili-DailyBonus/ExchangePoints.js +++ b/Bilibili-DailyBonus/ExchangePoints.js @@ -1,240 +1,272 @@ -/* -哔哩哔哩漫画, 积分商城自动抢购脚本 +/******************************** +哔哩哔哩漫画积分商城自动抢购脚本 -脚本兼容: Surge, QuantumultX, Loon +默认兑换积分商城中的"【超特惠】限量-0点秒杀" +兑换数量为用户积分可兑换的最大值 (可于BoxJs内修改) +默认执行时间为:每周日、每周一的凌晨 0:00:00 - 0:00:30 之间每秒执行一次 -************************* -【 抢购脚本注意事项 】: -************************* +该脚本需要使用签到脚本获取Cookie后方可使用,支持多账号。 -该脚本需要使用签到脚本获取Cookie后方可使用. -默认兑换积分商城中的"积分兑换", 兑换数量为用户积分可兑换的最大值 (可于BoxJs内修改) -默认执行时间为中午12:00:10、12:00:20、12:00:30 +脚本作者:@NobyDa is powered by AI +更新时间:2025/12/19 +平台兼容:Surge / QuantumultX / Loon / Stash -BoxJs订阅地址: https://raw.githubusercontent.com/NobyDa/Script/master/NobyDa_BoxJs.json +********************************* +Surge(iOS 5.9.0+/macOS 5.5.0+)模块: +********************************* -************************* -【 Surge & Loon 脚本配置 】: -************************* +https://raw.githubusercontent.com/NobyDa/Script/refs/heads/master/Surge/Module/BiliComicsExchangePoints.sgmodule -[Script] -cron "10,20,30 0 12 * * *" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/ExchangePoints.js, wake-system=1, timeout=60 +********************************* +QuantumultX 任务仓库(Gallery)订阅: +********************************* -************************* -【 QX 1.0.10+ 脚本配置 】 : -************************* +https://raw.githubusercontent.com/NobyDa/Script/master/NobyDa_BoxJs.json +工具&分析->HTTP请求->右上角添加任务仓库->选择相关脚本添加定时任务和附加组件 +或者添加QuantumultX配置: [task_local] -10,20,30 0 12 * * * https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/ExchangePoints.js, tag=哔哩哔哩漫画抢券, enabled=true - -*/ - -// 新建一个实例对象, 把兼容函数定义到$中, 以便统一调用 -let $ = new nobyda(); - -// 读取兑换商品名, 默认兑换积分商城中的"积分兑换"; 该接口为BoxJs预留, 以便修改 -let productName = $.read('BM_ProductName') || '积分兑换'; - -// 读取兑换数量, 默认兑换最大值; 该接口为BoxJs预留, 以便修改 -let productNum = $.read('BM_ProductNum'); - -// 读取循环抢购次数, 默认100次; 该接口为BoxJs预留, 以便修改 -let exchangeNum = $.read('BM_ExchangeNum') || '100'; - -// 读取哔哩哔哩漫画签到脚本所使用的Cookie -let cookie = $.read('CookieBM'); - -// 预留的空对象, 便于函数之间读取数据 -let user = {}; - -(async function() { // 立即运行的匿名异步函数 - // 使用await关键字声明, 表示以同步方式执行异步函数, 可以简单理解为顺序执行 - await Promise.all([ //该方法用于将多个实例包装成一个新的实例, 可以简单理解为同时调用函数, 以进一步提高执行速度 - GetUserPoint(), //查询积分函数 - ListProduct() //查询商品函数 - ]); - await ExchangeProduct(); //上面的查询都完成后, 则执行抢购 - $.done(); //抢购完成后调用Surge、QX内部特有的函数, 用于退出脚本执行 -})(); - -function GetUserPoint() { - const pointUrl = { //查询积分接口 - url: 'https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/GetUserPoint', - headers: { //请求头 - 'Cookie': cookie //用户鉴权Cookie - } - } - return new Promise((resolve) => { //主函数返回Promise实例对象, 以便后续调用时可以实现顺序执行异步函数 - $.post(pointUrl, (error, resp, data) => { //使用post请求查询, 再使用回调函数处理返回的结果 - try { //使用try方法捕获可能出现的代码异常 - if (error) { - throw new Error(error); //如果请求失败, 例如无法联网, 则抛出一个异常 - } else { - const body = JSON.parse(data); //解析响应体json并转化为对象 - if (body.code == 0 && body.data) { //如果响应体为预期格式 - user.point = parseInt(body.data.point); //把查询的积分赋值到全局变量user中 - console.log(`\n当前积分: ${body.data.point}`); //打印日志 - } else { //否则抛出一个异常 - throw new Error(body.msg || data); - } - } - } catch (e) { //接住try代码块中抛出的异常, 并打印日志 - console.log(`\n查询积分: 失败\n出现错误: ${e.message}`); - } finally { //finally语句在try和catch之后无论有无异常都会执行 - resolve(); //异步操作成功时调用, 将Promise对象的状态标记为"成功", 表示已完成查询积分 - } - }) - }) +0-59 0 0 * * 0-1 * * * https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/ExchangePoints.js, tag=哔哩哔哩漫画抢券, enabled=true + +*********************************/ + +const $ = new Env('BILI_COMICS_CHECKIN'); +const barkKey = $.isNode() && process.env['BM_BARK_KEY'] || ''; +const notifyMsg = []; + +!(async () => { + $.logLevel = $.getdata(`@${$.name}.Debug`) == 'true' && 'debug' || 'info'; + const args = argsList(typeof $argument == "string" && $argument || ''); + const user = JSON.parse($.getdata($.name) || ($.isNode() && process.env[$.name]) || '{}'); + const userNum = Object.keys(user.account || {}).length; + const todayFlag = getTodayFlag(); + // 读取配置参数 + const productName = args.ProductName || user.ProductName || '【超特惠】限量-0点秒杀'; + const productNum = args.ProductNum || parseInt(user.ProductNum) || 0; + const exchangeNum = args.ExchangeNum || parseInt(user.ExchangeNum) || 100; + if (userNum) { + for (const i in user.account) { + // 检查今日是否已抢购成功 + if (user.account[i].lastSuccessDate === todayFlag) { + const text = `账号(${i})今日已抢购成功,跳过执行`; + $.info(text); + continue + } + // 检查今日是否已标记积分不足 + if (user.account[i].lastInsufficientDate === todayFlag) { + const text = `账号(${i})今日积分不足,跳过执行`; + $.info(text); + continue + } + const accountPrefix = userNum > 1 ? `[账号(${i})]` : ''; + try { + const result = await ExchangeForAccount(user.account[i], productName, productNum, exchangeNum); + const text = accountPrefix ? `${accountPrefix} ${result.message}` : result.message; + $.info(text); + // 只有抢购成功时才加入通知消息并标记成功 + if (result.success) { + notifyMsg.push(text); + user.account[i].lastSuccessDate = todayFlag; + // 清除积分不足标记 + delete user.account[i].lastInsufficientDate; + $.setjson(user, $.name); + $.info(`账号 ${i} 已标记今日抢购成功`); + } + // 如果是积分不足(非异常情况),标记今日积分不足 + else if (result.insufficient) { + user.account[i].lastInsufficientDate = todayFlag; + $.setjson(user, $.name); + $.info(`账号 ${i} 已标记今日积分不足`); + } + } catch (err) { + const text = `${accountPrefix} 抢购错误: ${err.message}`; + $.error(text); + notifyMsg.push(text); + } + } + } else { + notifyMsg.push(`抢购Cookie失效/未获取 ⚠️`); + } +})() + .catch((err) => notifyMsg.push(`错误: ${err}`) && $.error(err)) + .finally(async () => { + if (notifyMsg.length) { + if (barkKey) { + await BarkNotify($, barkKey, `哔哩哔哩漫画抢券`, notifyMsg.join('\n')); + } + $.msg(`哔哩哔哩漫画抢券`, ``, notifyMsg.join('\n')); + } + $.done({}); + }); + +async function ExchangeForAccount(account, productName, productNum, exchangeNum) { + // 先只查询商品信息(不查询积分) + const productList = await ListProduct(account); + + // 查找目标商品 + const product = productList.find(t => t.title == productName); + if (!product) { + return { success: false, insufficient: false, message: `查询商品失败: 未找到"${productName}"` }; + } + + // 先检查商品库存,如果库存为0则直接返回,不查询积分 + if (!product.remain_amount) { + $.info(`查询商品: ${productName}, 库存: 0`); + return { success: false, insufficient: false, message: `抢购终止: 商品库存为0` }; + } + + // 库存充足时才查询积分 + const userPoint = await GetUserPoint(account); + $.info(`查询商品: ${productName}, 库存: ${product.remain_amount}, 当前积分: ${userPoint}`); + + // 检查积分是否足够 + if (userPoint < product.real_cost) { + return { + success: false, + insufficient: true, + message: `抢购终止: 积分不足 (需要${product.real_cost}, 当前${userPoint})` + }; + } + + // 计算兑换数量 + const num = productNum > 0 ? Math.min(productNum, Math.floor(userPoint / product.real_cost)) : Math.floor(userPoint / product.real_cost); + + if (num <= 0) { + return { + success: false, + insufficient: true, + message: `抢购终止: 积分不足以兑换` + }; + } + + // 开始抢购 + for (let i = 0; i < exchangeNum; i++) { + const result = await StartExchange(account, product, num, i); + if (result.success) { + return { + success: true, + insufficient: false, + message: `抢购成功: 第${i + 1}次, 数量: ${num}, 消耗积分: ${num * product.real_cost}` + }; + } + if (i === exchangeNum - 1) { + return { + success: false, + insufficient: false, + message: `抢购失败: 已尝试${exchangeNum}次 (${result.message})` + }; + } + } } -function ListProduct() { - const listUrl = { //查询商品接口 - url: 'https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/ListProduct', - headers: {} - } - return new Promise((resolve) => { //主函数返回Promise实例对象, 以便后续调用时可以实现顺序执行异步函数 - $.post(listUrl, (error, resp, data) => { //使用post请求查询, 再使用回调函数处理返回的结果 - try { //使用try方法捕获可能出现的代码异常 - if (error) { - throw new Error(error); //如果请求失败, 例如无法联网, 则抛出一个异常 - } else { - const body = JSON.parse(data); //解析响应体json并转化为对象 - if (body.code == 0 && body.data.length >= 1) { //如果接口正常返回商品信息 - // 按全局变量所填写的商品名进行过滤, 并把商品信息赋值到全局变量user中 - user.list = body.data.filter(t => t.title == productName).pop(); - if (!user.list) { - throw new Error('请检查商品名'); //如果填错商品名则抛出一个异常 - } else { //否则打印日志 - console.log(`\n查询商品: ${productName}\n商品库存: ${user.list.remain_amount}`) - } - } else { //否则抛出一个异常 - throw new Error('无商品列表'); - } - } - } catch (e) { //接住try代码块中抛出的异常并打印日志 - console.log(`\n查询商品: ${productName}\n出现错误: ${e.message}`); - } finally { //finally语句在try和catch之后无论有无异常都会执行 - resolve(); //异步操作成功时调用, 将Promise对象的状态标记为"成功", 表示已完成查询商品 - } - }) - }) +function GetUserPoint(account) { + const opts = { + url: 'https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/GetUserPoint', + headers: { + "User-Agent": "comic-universal/3412 CFNetwork/1410.0.3 Darwin/22.6.0 os/ios model/iPhone 12 mobi_app/iphone_comic build/3412 osVer/16.6 network/2 channel/AppStore", + "Cookie": account.cookie + }, + throwHttpErrors: false + }; + + $.debug(`Send GetUserPoint request:`, $.toStr(opts, null, null, 1)); + + return $.http.post(opts) + .then((resp) => { + $.debug(`Receive GetUserPoint response:`, $.toStr(resp, null, null, 1)); + const body = JSON.parse(resp.body?.startsWith('{') && resp.body || '{}'); + if (body.code == 0 && body.data) { + return parseInt(body.data.point); + } else { + throw new Error(body.msg || '查询积分失败'); + } + }) + .catch((err) => { + $.error(`GetUserPoint error:`, err); + throw err; + }); } -function ExchangeProduct() { - return new Promise(async (resolve) => { //主函数返回Promise实例对象, 以便后续调用时可以实现顺序执行异步函数, 该实例函数带有async关键字, 表示里面有异步操作, 例如可使用await得到异步结果 - if (user.list && user.list.remain_amount && user.point >= 100) { //如果商品有库存并且用户积分大于100则进行抢购 - //兑换商品数量(用户积分 除与 商品单价得到兑换数量), 并转成整数; 默认兑换最大数量 - const num = parseInt(productNum || (user.point / user.list.real_cost)); - const exchangeUrl = { - url: 'https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/Exchange', //兑换商品接口 - headers: { //请求头 - 'Content-Type': 'application/json', //声明请求体数据格式 - 'Cookie': cookie //用户鉴权Cookie - }, - body: JSON.stringify({ //请求体转成字符串类型 - product_id: user.list.id, //兑换的商品id - product_num: num, //兑换的商品数量 - point: num * user.list.real_cost //消耗的积分总数 (兑换数量乘单价得到积分总数) - }) - }; - for (let i = 0; i < parseInt(exchangeNum); i++) { //根据全局变量定义的次数, 暴力循环抢购 - // 循环内调用另一个抢购函数, 并传入请求、第几次循环、兑换数量等参数, - // 使用await关键字声明, 表示需要等待每一次的执行结果 - const run = await startExchange(exchangeUrl, i, num); - if (run) { - break; //如果函数返回布尔值true, 则跳出循环, 脚本结束 - } - } - } else { //商品无库存或用户积分小于100等情况, 则不执行抢购, 脚本结束 - console.log(`\n抢购终止: 不具备兑换条件`); //打印日志 - } - resolve(); //将主函数的Promise对象状态标记为"成功", 表示已完成抢购任务 - }) +function ListProduct(account) { + const opts = { + url: 'https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/ListProduct', + headers: { + "User-Agent": "comic-universal/3412 CFNetwork/1410.0.3 Darwin/22.6.0 os/ios model/iPhone 12 mobi_app/iphone_comic build/3412 osVer/16.6 network/2 channel/AppStore" + }, + throwHttpErrors: false + }; + + $.debug(`Send ListProduct request:`, $.toStr(opts, null, null, 1)); + + return $.http.post(opts) + .then((resp) => { + $.debug(`Receive ListProduct response:`, $.toStr(resp, null, null, 1)); + const body = JSON.parse(resp.body?.startsWith('{') && resp.body || '{}'); + if (body.code == 0 && body.data && body.data.length >= 1) { + return body.data; + } else { + throw new Error(body.msg || '查询商品列表失败'); + } + }) + .catch((err) => { + $.error(`ListProduct error:`, err); + throw err; + }); } -function startExchange(url, item, amount) { - return new Promise((resolve) => { //主函数返回Promise实例对象, 以便后续调用时可以实现顺序执行异步函数 - $.post(url, (error, resp, data) => { //使用post请求查询, 再使用回调函数处理返回的结果 - try { //使用try方法捕获可能出现的代码异常 - if (error) { - throw new Error(error); //如果请求失败, 例如无法联网, 则抛出一个异常 - } else { - const body = JSON.parse(data); //解析响应体json并转化为对象 - if (body.code == 0) { //如果抢购成功, 则输出日志和通知 - console.log(`\n抢购成功: 第${item+1}次\n抢购数量: ${amount}\n消耗积分: ${amount * user.list.real_cost}`); - $.notify('哔哩哔哩漫画抢券', '', `"${productName}"抢购成功, 数量: ${amount}, 消耗积分: ${amount * user.list.real_cost}`); - resolve(true); //将Promise对象的状态标记为"成功", 然后返回一个布尔值true用于跳出循环 - } else { - throw new Error(body.msg || '未知'); //抢购失败则抛出异常 - } - } - } catch (e) { //接住try代码块中抛出的异常并打印日志 - console.log(`\n抢购失败: 第${item+1}次\n失败原因: ${e.message}`); - resolve(); //将Promise对象的状态标记为"成功", 但不返回任何值, 表示继续循环抢购 - } - }) - }) +function StartExchange(account, product, num, attempt) { + const opts = { + url: 'https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/Exchange', + headers: { + "User-Agent": "comic-universal/3412 CFNetwork/1410.0.3 Darwin/22.6.0 os/ios model/iPhone 12 mobi_app/iphone_comic build/3412 osVer/16.6 network/2 channel/AppStore", + "Content-Type": "application/json", + "Cookie": account.cookie + }, + body: JSON.stringify({ + product_id: product.id, + product_num: num, + point: num * product.real_cost + }), + throwHttpErrors: false + }; + + $.debug(`Send Exchange request (attempt ${attempt + 1}):`, $.toStr(opts, null, null, 1)); + + return $.http.post(opts) + .then((resp) => { + $.debug(`Receive Exchange response (attempt ${attempt + 1}):`, $.toStr(resp, null, null, 1)); + const body = JSON.parse(resp.body?.startsWith('{') && resp.body || '{}'); + if (body.code == 0) { + return { success: true, message: '兑换成功' }; + } else { + return { success: false, message: body.msg || '未知错误' }; + } + }) + .catch((err) => { + $.error(`Exchange error (attempt ${attempt + 1}):`, err); + return { success: false, message: err.message || '请求失败' }; + }); } -function nobyda() { - const isSurge = typeof $httpClient != "undefined"; - const isQuanX = typeof $task != "undefined"; - const isNode = typeof require == "function"; - const node = (() => { - if (isNode) { - const request = require('request'); - return { - request - } - } else { - return null; - } - })() - const adapterStatus = (response) => { - if (response) { - if (response.status) { - response["statusCode"] = response.status - } else if (response.statusCode) { - response["status"] = response.statusCode - } - } - return response - } - this.read = (key) => { - if (isQuanX) return $prefs.valueForKey(key) - if (isSurge) return $persistentStore.read(key) - } - this.notify = (title, subtitle, message) => { - if (isQuanX) $notify(title, subtitle, message) - if (isSurge) $notification.post(title, subtitle, message) - if (isNode) console.log(`${title}\n${subtitle}\n${message}`) - } - this.post = (options, callback) => { - options.headers['User-Agent'] = 'User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 13_6_1 like Mac OS X) AppleWebKit/609.3.5.0.2 (KHTML, like Gecko) Mobile/17G80 BiliApp/822 mobi_app/ios_comic channel/AppStore BiliComic/822' - if (isQuanX) { - if (typeof options == "string") options = { - url: options - } - options["method"] = "POST" - $task.fetch(options).then(response => { - callback(null, adapterStatus(response), response.body) - }, reason => callback(reason.error, null, null)) - } - if (isSurge) { - options.headers['X-Surge-Skip-Scripting'] = false - $httpClient.post(options, (error, response, body) => { - callback(error, adapterStatus(response), body) - }) - } - if (isNode) { - node.request.post(options, (error, response, body) => { - callback(error, adapterStatus(response), body) - }) - } - } - this.done = () => { - if (isQuanX || isSurge) { - $done() - } - } -}; \ No newline at end of file +function getTodayFlag() { + const now = new Date(); + const year = now.getFullYear(); + const month = String(now.getMonth() + 1).padStart(2, '0'); + const day = String(now.getDate()).padStart(2, '0'); + return `${year}-${month}-${day}`; +} + +function argsList(data) { + return Array.from( + data.split("&") + .map((i) => i.split("=")) + .map(([k, v]) => [k, decodeURIComponent(v)]) + ) + .reduce((a, [k, v]) => Object.assign(a, { [k]: v }), {}) +} + +//Bark APP notify +async function BarkNotify(c, k, t, b) { for (let i = 0; i < 3; i++) { c.log(`🔷Bark notify >> Start push (${i + 1})`); const s = await new Promise((n) => { c.post({ url: 'https://api.day.app/push', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: t, body: b, device_key: k, ext_params: { group: t } }) }, (e, r, d) => r && r.status == 200 ? n(1) : n(d || e)) }); if (s === 1) { c.log('✅Push success!'); break } else { c.log(`❌Push failed! >> ${s.message || s}`) } } }; + +// https://github.com/chavyleung/scripts/blob/master/Env.min.js +function Env(e, t) { class s { constructor(e) { this.env = e } send(e, t = "GET") { e = "string" == typeof e ? { url: e } : e; let s = this.get; "POST" === t && (s = this.post); const i = new Promise(((t, i) => { s.call(this, e, ((e, s, o) => { e ? i(e) : t(s) })) })); return e.timeout ? ((e, t = 1e3) => Promise.race([e, new Promise(((e, s) => { setTimeout((() => { s(new Error("请求超时")) }), t) }))]))(i, e.timeout) : i } get(e) { return this.send.call(this.env, e) } post(e) { return this.send.call(this.env, e, "POST") } } return new class { constructor(e, t) { this.logLevels = { debug: 0, info: 1, warn: 2, error: 3 }, this.logLevelPrefixs = { debug: "[DEBUG] ", info: "[INFO] ", warn: "[WARN] ", error: "[ERROR] " }, this.logLevel = "info", this.name = e, this.http = new s(this), this.data = null, this.dataFile = "box.dat", this.logs = [], this.isMute = !1, this.isNeedRewrite = !1, this.logSeparator = "\n", this.encoding = "utf-8", this.startTime = (new Date).getTime(), Object.assign(this, t) } getEnv() { return "undefined" != typeof $environment && $environment["surge-version"] ? "Surge" : "undefined" != typeof $environment && $environment["stash-version"] ? "Stash" : "undefined" != typeof module && module.exports ? "Node.js" : "undefined" != typeof $task ? "Quantumult X" : "undefined" != typeof $loon ? "Loon" : "undefined" != typeof $rocket ? "Shadowrocket" : void 0 } isNode() { return "Node.js" === this.getEnv() } isQuanX() { return "Quantumult X" === this.getEnv() } isSurge() { return "Surge" === this.getEnv() } isLoon() { return "Loon" === this.getEnv() } isShadowrocket() { return "Shadowrocket" === this.getEnv() } isStash() { return "Stash" === this.getEnv() } toObj(e, t = null) { try { return JSON.parse(e) } catch { return t } } toStr(e, t = null, ...s) { try { return JSON.stringify(e, ...s) } catch { return t } } getjson(e, t) { let s = t; if (this.getdata(e)) try { s = JSON.parse(this.getdata(e)) } catch { } return s } setjson(e, t) { try { return this.setdata(JSON.stringify(e), t) } catch { return !1 } } getScript(e) { return new Promise((t => { this.get({ url: e }, ((e, s, i) => t(i))) })) } runScript(e, t) { return new Promise((s => { let i = this.getdata("@chavy_boxjs_userCfgs.httpapi"); i = i ? i.replace(/\n/g, "").trim() : i; let o = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout"); o = o ? 1 * o : 20, o = t && t.timeout ? t.timeout : o; const [r, a] = i.split("@"), n = { url: `http://${a}/v1/scripting/evaluate`, body: { script_text: e, mock_type: "cron", timeout: o }, headers: { "X-Key": r, Accept: "*/*" }, policy: "DIRECT", timeout: o }; this.post(n, ((e, t, i) => s(i))) })).catch((e => this.logErr(e))) } loaddata() { if (!this.isNode()) return {}; { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const e = this.path.resolve(this.dataFile), t = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(e), i = !s && this.fs.existsSync(t); if (!s && !i) return {}; { const i = s ? e : t; try { return JSON.parse(this.fs.readFileSync(i)) } catch (e) { return {} } } } } writedata() { if (this.isNode()) { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const e = this.path.resolve(this.dataFile), t = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(e), i = !s && this.fs.existsSync(t), o = JSON.stringify(this.data); s ? this.fs.writeFileSync(e, o) : i ? this.fs.writeFileSync(t, o) : this.fs.writeFileSync(e, o) } } lodash_get(e, t, s) { const i = t.replace(/\[(\d+)\]/g, ".$1").split("."); let o = e; for (const e of i) if (o = Object(o)[e], void 0 === o) return s; return o } lodash_set(e, t, s) { return Object(e) !== e || (Array.isArray(t) || (t = t.toString().match(/[^.[\]]+/g) || []), t.slice(0, -1).reduce(((e, s, i) => Object(e[s]) === e[s] ? e[s] : e[s] = Math.abs(t[i + 1]) >> 0 == +t[i + 1] ? [] : {}), e)[t[t.length - 1]] = s), e } getdata(e) { let t = this.getval(e); if (/^@/.test(e)) { const [, s, i] = /^@(.*?)\.(.*?)$/.exec(e), o = s ? this.getval(s) : ""; if (o) try { const e = JSON.parse(o); t = e ? this.lodash_get(e, i, "") : t } catch (e) { t = "" } } return t } setdata(e, t) { let s = !1; if (/^@/.test(t)) { const [, i, o] = /^@(.*?)\.(.*?)$/.exec(t), r = this.getval(i), a = i ? "null" === r ? null : r || "{}" : "{}"; try { const t = JSON.parse(a); this.lodash_set(t, o, e), s = this.setval(JSON.stringify(t), i) } catch (t) { const r = {}; this.lodash_set(r, o, e), s = this.setval(JSON.stringify(r), i) } } else s = this.setval(e, t); return s } getval(e) { switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": return $persistentStore.read(e); case "Quantumult X": return $prefs.valueForKey(e); case "Node.js": return this.data = this.loaddata(), this.data[e]; default: return this.data && this.data[e] || null } } setval(e, t) { switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": return $persistentStore.write(e, t); case "Quantumult X": return $prefs.setValueForKey(e, t); case "Node.js": return this.data = this.loaddata(), this.data[t] = e, this.writedata(), !0; default: return this.data && this.data[t] || null } } initGotEnv(e) { this.got = this.got ? this.got : require("got"), this.cktough = this.cktough ? this.cktough : require("tough-cookie"), this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar, e && (e.headers = e.headers ? e.headers : {}, e && (e.headers = e.headers ? e.headers : {}, void 0 === e.headers.cookie && void 0 === e.headers.Cookie && void 0 === e.cookieJar && (e.cookieJar = this.ckjar))) } get(e, t = (() => { })) { switch (e.headers && (delete e.headers["Content-Type"], delete e.headers["Content-Length"], delete e.headers["content-type"], delete e.headers["content-length"]), e.params && (e.url += "?" + this.queryStr(e.params)), void 0 === e.followRedirect || e.followRedirect || ((this.isSurge() || this.isLoon()) && (e["auto-redirect"] = !1), this.isQuanX() && (e.opts ? e.opts.redirection = !1 : e.opts = { redirection: !1 })), this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": default: this.isSurge() && this.isNeedRewrite && (e.headers = e.headers || {}, Object.assign(e.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient.get(e, ((e, s, i) => { !e && s && (s.body = i, s.statusCode = s.status ? s.status : s.statusCode, s.status = s.statusCode), t(e, s, i) })); break; case "Quantumult X": this.isNeedRewrite && (e.opts = e.opts || {}, Object.assign(e.opts, { hints: !1 })), $task.fetch(e).then((e => { const { statusCode: s, statusCode: i, headers: o, body: r, bodyBytes: a } = e; t(null, { status: s, statusCode: i, headers: o, body: r, bodyBytes: a }, r, a) }), (e => t(e && e.error || "UndefinedError"))); break; case "Node.js": let s = require("iconv-lite"); this.initGotEnv(e), this.got(e).on("redirect", ((e, t) => { try { if (e.headers["set-cookie"]) { const s = e.headers["set-cookie"].map(this.cktough.Cookie.parse).toString(); s && this.ckjar.setCookieSync(s, null), t.cookieJar = this.ckjar } } catch (e) { this.logErr(e) } })).then((e => { const { statusCode: i, statusCode: o, headers: r, rawBody: a } = e, n = s.decode(a, this.encoding); t(null, { status: i, statusCode: o, headers: r, rawBody: a, body: n }, n) }), (e => { const { message: i, response: o } = e; t(i, o, o && s.decode(o.rawBody, this.encoding)) })); break } } post(e, t = (() => { })) { const s = e.method ? e.method.toLocaleLowerCase() : "post"; switch (e.body && e.headers && !e.headers["Content-Type"] && !e.headers["content-type"] && (e.headers["content-type"] = "application/x-www-form-urlencoded"), e.headers && (delete e.headers["Content-Length"], delete e.headers["content-length"]), void 0 === e.followRedirect || e.followRedirect || ((this.isSurge() || this.isLoon()) && (e["auto-redirect"] = !1), this.isQuanX() && (e.opts ? e.opts.redirection = !1 : e.opts = { redirection: !1 })), this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": default: this.isSurge() && this.isNeedRewrite && (e.headers = e.headers || {}, Object.assign(e.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient[s](e, ((e, s, i) => { !e && s && (s.body = i, s.statusCode = s.status ? s.status : s.statusCode, s.status = s.statusCode), t(e, s, i) })); break; case "Quantumult X": e.method = s, this.isNeedRewrite && (e.opts = e.opts || {}, Object.assign(e.opts, { hints: !1 })), $task.fetch(e).then((e => { const { statusCode: s, statusCode: i, headers: o, body: r, bodyBytes: a } = e; t(null, { status: s, statusCode: i, headers: o, body: r, bodyBytes: a }, r, a) }), (e => t(e && e.error || "UndefinedError"))); break; case "Node.js": let i = require("iconv-lite"); this.initGotEnv(e); const { url: o, ...r } = e; this.got[s](o, r).then((e => { const { statusCode: s, statusCode: o, headers: r, rawBody: a } = e, n = i.decode(a, this.encoding); t(null, { status: s, statusCode: o, headers: r, rawBody: a, body: n }, n) }), (e => { const { message: s, response: o } = e; t(s, o, o && i.decode(o.rawBody, this.encoding)) })); break } } time(e, t = null) { const s = t ? new Date(t) : new Date; let i = { "M+": s.getMonth() + 1, "d+": s.getDate(), "H+": s.getHours(), "m+": s.getMinutes(), "s+": s.getSeconds(), "q+": Math.floor((s.getMonth() + 3) / 3), S: s.getMilliseconds() }; /(y+)/.test(e) && (e = e.replace(RegExp.$1, (s.getFullYear() + "").substr(4 - RegExp.$1.length))); for (let t in i) new RegExp("(" + t + ")").test(e) && (e = e.replace(RegExp.$1, 1 == RegExp.$1.length ? i[t] : ("00" + i[t]).substr(("" + i[t]).length))); return e } queryStr(e) { let t = ""; for (const s in e) { let i = e[s]; null != i && "" !== i && ("object" == typeof i && (i = JSON.stringify(i)), t += `${s}=${i}&`) } return t = t.substring(0, t.length - 1), t } msg(t = e, s = "", i = "", o = {}) { const r = e => { const { $open: t, $copy: s, $media: i, $mediaMime: o } = e; switch (typeof e) { case void 0: return e; case "string": switch (this.getEnv()) { case "Surge": case "Stash": default: return { url: e }; case "Loon": case "Shadowrocket": return e; case "Quantumult X": return { "open-url": e }; case "Node.js": return }case "object": switch (this.getEnv()) { case "Surge": case "Stash": case "Shadowrocket": default: { const r = {}; let a = e.openUrl || e.url || e["open-url"] || t; a && Object.assign(r, { action: "open-url", url: a }); let n = e["update-pasteboard"] || e.updatePasteboard || s; n && Object.assign(r, { action: "clipboard", text: n }); let h = e.mediaUrl || e["media-url"] || i; if (h) { let e, t; if (h.startsWith("http")); else if (h.startsWith("data:")) { const [s] = h.split(";"), [, i] = h.split(","); e = i, t = s.replace("data:", "") } else { e = h, t = (e => { const t = { JVBERi0: "application/pdf", R0lGODdh: "image/gif", R0lGODlh: "image/gif", iVBORw0KGgo: "image/png", "/9j/": "image/jpg" }; for (var s in t) if (0 === e.indexOf(s)) return t[s]; return null })(h) } Object.assign(r, { "media-url": h, "media-base64": e, "media-base64-mime": o ?? t }) } return Object.assign(r, { "auto-dismiss": e["auto-dismiss"], sound: e.sound }), r } case "Loon": { const s = {}; let o = e.openUrl || e.url || e["open-url"] || t; o && Object.assign(s, { openUrl: o }); let r = e.mediaUrl || e["media-url"] || i; return r && Object.assign(s, { mediaUrl: r }), console.log(JSON.stringify(s)), s } case "Quantumult X": { const o = {}; let r = e["open-url"] || e.url || e.openUrl || t; r && Object.assign(o, { "open-url": r }); let a = e.mediaUrl || e["media-url"] || i; a && Object.assign(o, { "media-url": a }); let n = e["update-pasteboard"] || e.updatePasteboard || s; return n && Object.assign(o, { "update-pasteboard": n }), console.log(JSON.stringify(o)), o } case "Node.js": return }default: return } }; if (!this.isMute) switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": default: $notification.post(t, s, i, r(o)); break; case "Quantumult X": $notify(t, s, i, r(o)); break; case "Node.js": break }if (!this.isMuteLog) { let e = ["", "============================"]; e.push(t), s && e.push(s), i && e.push(i), console.log(e.join("\n")), this.logs = this.logs.concat(e) } } debug(...e) { this.logLevels[this.logLevel] <= this.logLevels.debug && (e.length > 0 && (this.logs = [...this.logs, ...e]), console.log(`${this.logLevelPrefixs.debug}${e.map((e => e ?? String(e))).join(this.logSeparator)}`)) } info(...e) { this.logLevels[this.logLevel] <= this.logLevels.info && (e.length > 0 && (this.logs = [...this.logs, ...e]), console.log(`${this.logLevelPrefixs.info}${e.map((e => e ?? String(e))).join(this.logSeparator)}`)) } warn(...e) { this.logLevels[this.logLevel] <= this.logLevels.warn && (e.length > 0 && (this.logs = [...this.logs, ...e]), console.log(`${this.logLevelPrefixs.warn}${e.map((e => e ?? String(e))).join(this.logSeparator)}`)) } error(...e) { this.logLevels[this.logLevel] <= this.logLevels.error && (e.length > 0 && (this.logs = [...this.logs, ...e]), console.log(`${this.logLevelPrefixs.error}${e.map((e => e ?? String(e))).join(this.logSeparator)}`)) } log(...e) { e.length > 0 && (this.logs = [...this.logs, ...e]), console.log(e.map((e => e ?? String(e))).join(this.logSeparator)) } logErr(e, t) { switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": case "Quantumult X": default: this.log("", `❗️${this.name}, 错误!`, t, e); break; case "Node.js": this.log("", `❗️${this.name}, 错误!`, t, void 0 !== e.message ? e.message : e, e.stack); break } } wait(e) { return new Promise((t => setTimeout(t, e))) } done(e = {}) { const t = ((new Date).getTime() - this.startTime) / 1e3; switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": case "Quantumult X": default: $done(e); break; case "Node.js": process.exit(1) } } }(e, t) } diff --git a/Bilibili-DailyBonus/Manga.js b/Bilibili-DailyBonus/Manga.js index 44afbfc9a8..45a06ceb9d 100644 --- a/Bilibili-DailyBonus/Manga.js +++ b/Bilibili-DailyBonus/Manga.js @@ -1,117 +1,143 @@ -/* -哔哩哔哩漫画签到 +/******************************** +哔哩哔哩漫画签到脚本 -脚本兼容: QuantumultX, Surge, Loon -电报频道:@NobyDa -问题反馈:@NobyDa_bot -如果转载,请注明出处 +支持多账号,支持Node.js,支持Bark推送。 +打开哔哩哔哩/漫画后 (AppStore中国区),单击"我的", 即可获取cookie -说明: -打开哔哩哔哩漫画后 (AppStore中国区),单击"我的", 如果通知获取cookie成功, 则可以使用此脚本. +脚本作者:@NobyDa +更新时间:2025/12/19 +平台兼容:Surge / QuantumultX / Loon / Stash / Node.js +模块依赖(Node.js):iconv-lite / got / tough-cookie +环境变量(Node.js):BILI_COMIC_DAILY_BONUS / BM_BARK_KEY -脚本将在每天上午9点执行。 您可以修改执行时间。 +********************************* +Surge(iOS 5.9.0+/macOS 5.5.0+)模块: +********************************* -~~~~~~~~~~~~~~~~ -Surge 4.2.0+ : +https://raw.githubusercontent.com/NobyDa/Script/refs/heads/master/Surge/Module/BiliComicsDailyBonus.sgmodule -[Script] -Bili漫画签到 = type=cron,cronexp=0 9 * * *,wake-system=1,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js +********************************* +QuantumultX 任务仓库(Gallery)订阅: +********************************* -Bili漫画Cookie = type=http-request,pattern=^https:\/\/app\.bilibili\.com\/x\/v2\/account\/myinfo,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js - -[MITM] -hostname = app.bilibili.com -~~~~~~~~~~~~~~~~ -QX 1.0.10+ : +https://raw.githubusercontent.com/NobyDa/Script/master/NobyDa_BoxJs.json +工具&分析->HTTP请求->右上角添加任务仓库->选择相关脚本添加定时任务和附加组件 +或者添加QuantumultX配置: [task_local] -0 9 * * * https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js, tag=Bili漫画签到 +0 9 * * * https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js, tag=哔哩哔哩漫画签到 [rewrite_local] -#获取Bili漫画Cookie ^https:\/\/app\.bilibili\.com\/x\/v2\/account\/myinfo url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js [mitm] hostname = app.bilibili.com -~~~~~~~~~~~~~~~~ -*/ - -const $ = new Env(`哔哩哔哩漫画`); - -const cookie = $.getdata("CookieBM") || ''; // 哔哩哔哩漫画Cookie - -const barkKey = ''; //Bark APP 通知推送Key - -if (typeof $request !== 'undefined') { - GetCookie() -} else { - checkin() -} +*********************************/ + +const $ = new Env('BILI_COMICS_CHECKIN'); +const barkKey = $.isNode() && process.env['BM_BARK_KEY'] || ''; // bark key +const notifyMsg = []; +const auth = ''; // '{"account":{"user1":{"cookie":"xxx","access_key":"xxx"},"user2":{"cookie":"xxx","access_key":"xxx"}}}' + +!(async () => { + $.logLevel = $.getdata(`@${$.name}.Debug`) == 'true' && 'debug' || 'info'; + const user = JSON.parse(auth || $.getdata($.name) || ($.isNode() && process.env[$.name]) || '{}'); + const userNum = Object.keys(user.account || {}).length; + if (typeof $request !== 'undefined') { + return GetAuth($request, user); + } + if (userNum) { + const invalidUser = []; + for (const i in user.account) { + const text = [ + userNum > 1 && `[账号${notifyMsg.length + 1}(${i})]`, + await Checkin(user.account[i], i), + ].filter((v) => v).join(' '); + if (text.includes('登陆失效')) { + invalidUser.push(i) + } + $.info(text); + notifyMsg.push(text); + } + invalidUser.forEach((i) => delete user.account[i] && !$.isNode() && $.setjson(user, $.name)); + } else { + notifyMsg.push(`签到Cookie失效/未获取 ⚠️`); + } +})() + .catch((err) => notifyMsg.push(`错误: ${err}`) && $.error(err)) + .finally(async () => { + const finalContent = notifyMsg.filter((v) => !v.includes('已签过')); + if (finalContent.length) { + if (barkKey) { + await BarkNotify($, barkKey, `哔哩哔哩漫画`, finalContent.join('\n')); + } + $.msg(`哔哩哔哩漫画`, ``, finalContent.join('\n')) + } + $.done({}); + }); -function checkin() { - const bilibili = { - url: 'https://manga.bilibili.com/twirp/activity.v1.Activity/ClockIn', +function Checkin(key) { + const opts = { + url: `https://manga.bilibili.com/twirp/activity.v1.Activity/ClockIn?platform=ios`, headers: { - Cookie: cookie, + "User-Agent": "comic-universal/3412 CFNetwork/1410.0.3 Darwin/22.6.0 os/ios model/iPhone 12 mobi_app/iphone_comic build/3412 osVer/16.6 network/2 channel/AppStore" }, - body: "platform=ios" + throwHttpErrors: false // a fucking legacy in Env.js }; - $.post(bilibili, async function(error, response, data) { - if (error && !data) { - $.msgBody = `请求失败!\n${error}`; - } else if (parseInt(response.status) == 200) { - $.msgBody = "签到成功!🎉"; - } else if (/duplicate/.test(data)) { - $.msgBody = "今日已签过 ⚠️"; - } else if (/uid must/.test(data)) { - $.msgBody = "Cookie失效 ‼️‼️"; - } else { - $.msgBody = `签到失败 ‼️\n${data}`; - } - if (barkKey) { - await BarkNotify($, barkKey, $.name, $.msgBody); - } - $.msg($.name, ``, $.msgBody); - $.done(); - }) -} - -function GetCookie() { - var CookieName = "B站漫画"; - var CookieKey = "CookieBM"; - var regex = /SESSDATA=.+?;/; - if ($request.headers) { - var header = $request.headers['Cookie'] ? $request.headers['Cookie'] : ""; - if (header.indexOf("SESSDATA=") != -1) { - var CookieValue = regex.exec(header)[0]; - if ($.getdata(CookieKey)) { - if ($.getdata(CookieKey) != CookieValue) { - var cookie = $.setdata(CookieValue, CookieKey); - if (!cookie) { - $.msg("更新" + CookieName + "Cookie失败‼️", "", ""); - } else { - $.msg("更新" + CookieName + "Cookie成功 🎉", "", ""); - } - } + if (key.cookie) { opts.headers.Cookie = key.cookie } + if (key.access_key) { opts.url = `${opts.url}&access_key=${key.access_key}` } + $.debug(`Send checkin request:`, $.toStr(opts, null, null, 1)); + return $.http.post(opts) + .then((resp) => { + $.debug(`Receive checkin request response:`, $.toStr(resp, null, null, 1)) + resp.body = JSON.parse((resp.body?.startsWith('{') && resp.body) || '{}'); + if (resp.body.code == 0) { + return '签到成功!🎉' + } else if (resp.body.code == 1) { + return '今日已签过 ⚠️' + } else if (resp.body.msg == 'uid must > 0') { + return '签到失败, 登陆失效 ⚠️' } else { - var cookie = $.setdata(CookieValue, CookieKey); - if (!cookie) { - $.msg("首次写入" + CookieName + "Cookie失败‼️", "", ""); - } else { - $.msg("首次写入" + CookieName + "Cookie成功 🎉", "", ""); - } + return `签到失败(${resp.body.msg})` } + }) + .catch((err) => { + $.error(`Send checkin request error:`, err); + return `签到错误 ⚠️` + }) +} + +function GetAuth(raw, data) { + raw.headers = formatHeaders(raw.headers); + const uid = raw.headers['x-bili-mid']; + // cookies may not always be present in app. + const cookie = raw.headers.cookie?.split(/(SESSDATA=[a-zA-Z0-9%_-]+)/)[1]; + const access_key = raw.url.split(/access_key=([a-zA-Z0-9_-]+)/)[1]; + if (uid && (cookie?.includes('SESSDATA=') || access_key)) { + if (!data.account || !data.account[uid]) { + notifyMsg.push(`账号: ${uid} 写入鉴权成功!🎉`); } else { - $.msg("写入" + CookieName + "Cookie失败‼️", "", "Cookie关键值缺失"); + $.info(`账号: ${uid} 更新鉴权成功!🎉`); + } + data.account = { + ...data.account, [uid]: { + ...data.account?.[uid], + ...(cookie && { cookie }), + ...(access_key && { access_key }) + } } } else { - $.msg("写入" + CookieName + "Cookie失败‼️", "", "配置错误, 无法读取请求头,"); + $.error(`写入授权失败, 数据缺失.`) } - $.done() + return $.setjson(data, $.name); +} + +function formatHeaders(h) { + return Object.keys(h).reduce((t, i) => (t[i.toLowerCase()] = h[i], t), {}) } //Bark APP notify -async function BarkNotify(c,k,t,b){for(let i=0;i<3;i++){console.log(`🔷Bark notify >> Start push (${i+1})`);const s=await new Promise((n)=>{c.post({url:'https://api.day.app/push',headers:{'Content-Type':'application/json'},body:JSON.stringify({title:t,body:b,device_key:k,ext_params:{group:t}})},(e,r,d)=>r&&r.status==200?n(1):n(d||e))});if(s===1){console.log('✅Push success!');break}else{console.log(`❌Push failed! >> ${s.message||s}`)}}}; +async function BarkNotify(c, k, t, b) { for (let i = 0; i < 3; i++) { c.log(`🔷Bark notify >> Start push (${i + 1})`); const s = await new Promise((n) => { c.post({ url: 'https://api.day.app/push', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: t, body: b, device_key: k, ext_params: { group: t } }) }, (e, r, d) => r && r.status == 200 ? n(1) : n(d || e)) }); if (s === 1) { c.log('✅Push success!'); break } else { c.log(`❌Push failed! >> ${s.message || s}`) } } }; // https://github.com/chavyleung/scripts/blob/master/Env.min.js -function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),a={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(a,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon()?(this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)})):this.isQuanX()?(this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t))):this.isNode()&&(this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>{const{message:s,response:i}=t;e(s,i,i&&i.body)}))}post(t,e=(()=>{})){if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.post(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method="POST",this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){this.initGotEnv(t);const{url:s,...i}=t;this.got.post(s,i).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>{const{message:s,response:i}=t;e(s,i,i&&i.body)})}}time(t){let e={"M+":(new Date).getMonth()+1,"d+":(new Date).getDate(),"H+":(new Date).getHours(),"m+":(new Date).getMinutes(),"s+":(new Date).getSeconds(),"q+":Math.floor(((new Date).getMonth()+3)/3),S:(new Date).getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,((new Date).getFullYear()+"").substr(4-RegExp.$1.length)));for(let s in e)new RegExp("("+s+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?e[s]:("00"+e[s]).substr((""+e[s]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl;return{"open-url":e,"media-url":s}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r)));let h=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];h.push(e),s&&h.push(s),i&&h.push(i),console.log(h.join("\n")),this.logs=this.logs.concat(h)}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)} \ No newline at end of file +function Env(e, t) { class s { constructor(e) { this.env = e } send(e, t = "GET") { e = "string" == typeof e ? { url: e } : e; let s = this.get; "POST" === t && (s = this.post); const i = new Promise(((t, i) => { s.call(this, e, ((e, s, o) => { e ? i(e) : t(s) })) })); return e.timeout ? ((e, t = 1e3) => Promise.race([e, new Promise(((e, s) => { setTimeout((() => { s(new Error("请求超时")) }), t) }))]))(i, e.timeout) : i } get(e) { return this.send.call(this.env, e) } post(e) { return this.send.call(this.env, e, "POST") } } return new class { constructor(e, t) { this.logLevels = { debug: 0, info: 1, warn: 2, error: 3 }, this.logLevelPrefixs = { debug: "[DEBUG] ", info: "[INFO] ", warn: "[WARN] ", error: "[ERROR] " }, this.logLevel = "info", this.name = e, this.http = new s(this), this.data = null, this.dataFile = "box.dat", this.logs = [], this.isMute = !1, this.isNeedRewrite = !1, this.logSeparator = "\n", this.encoding = "utf-8", this.startTime = (new Date).getTime(), Object.assign(this, t) } getEnv() { return "undefined" != typeof $environment && $environment["surge-version"] ? "Surge" : "undefined" != typeof $environment && $environment["stash-version"] ? "Stash" : "undefined" != typeof module && module.exports ? "Node.js" : "undefined" != typeof $task ? "Quantumult X" : "undefined" != typeof $loon ? "Loon" : "undefined" != typeof $rocket ? "Shadowrocket" : void 0 } isNode() { return "Node.js" === this.getEnv() } isQuanX() { return "Quantumult X" === this.getEnv() } isSurge() { return "Surge" === this.getEnv() } isLoon() { return "Loon" === this.getEnv() } isShadowrocket() { return "Shadowrocket" === this.getEnv() } isStash() { return "Stash" === this.getEnv() } toObj(e, t = null) { try { return JSON.parse(e) } catch { return t } } toStr(e, t = null, ...s) { try { return JSON.stringify(e, ...s) } catch { return t } } getjson(e, t) { let s = t; if (this.getdata(e)) try { s = JSON.parse(this.getdata(e)) } catch { } return s } setjson(e, t) { try { return this.setdata(JSON.stringify(e), t) } catch { return !1 } } getScript(e) { return new Promise((t => { this.get({ url: e }, ((e, s, i) => t(i))) })) } runScript(e, t) { return new Promise((s => { let i = this.getdata("@chavy_boxjs_userCfgs.httpapi"); i = i ? i.replace(/\n/g, "").trim() : i; let o = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout"); o = o ? 1 * o : 20, o = t && t.timeout ? t.timeout : o; const [r, a] = i.split("@"), n = { url: `http://${a}/v1/scripting/evaluate`, body: { script_text: e, mock_type: "cron", timeout: o }, headers: { "X-Key": r, Accept: "*/*" }, policy: "DIRECT", timeout: o }; this.post(n, ((e, t, i) => s(i))) })).catch((e => this.logErr(e))) } loaddata() { if (!this.isNode()) return {}; { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const e = this.path.resolve(this.dataFile), t = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(e), i = !s && this.fs.existsSync(t); if (!s && !i) return {}; { const i = s ? e : t; try { return JSON.parse(this.fs.readFileSync(i)) } catch (e) { return {} } } } } writedata() { if (this.isNode()) { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const e = this.path.resolve(this.dataFile), t = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(e), i = !s && this.fs.existsSync(t), o = JSON.stringify(this.data); s ? this.fs.writeFileSync(e, o) : i ? this.fs.writeFileSync(t, o) : this.fs.writeFileSync(e, o) } } lodash_get(e, t, s) { const i = t.replace(/\[(\d+)\]/g, ".$1").split("."); let o = e; for (const e of i) if (o = Object(o)[e], void 0 === o) return s; return o } lodash_set(e, t, s) { return Object(e) !== e || (Array.isArray(t) || (t = t.toString().match(/[^.[\]]+/g) || []), t.slice(0, -1).reduce(((e, s, i) => Object(e[s]) === e[s] ? e[s] : e[s] = Math.abs(t[i + 1]) >> 0 == +t[i + 1] ? [] : {}), e)[t[t.length - 1]] = s), e } getdata(e) { let t = this.getval(e); if (/^@/.test(e)) { const [, s, i] = /^@(.*?)\.(.*?)$/.exec(e), o = s ? this.getval(s) : ""; if (o) try { const e = JSON.parse(o); t = e ? this.lodash_get(e, i, "") : t } catch (e) { t = "" } } return t } setdata(e, t) { let s = !1; if (/^@/.test(t)) { const [, i, o] = /^@(.*?)\.(.*?)$/.exec(t), r = this.getval(i), a = i ? "null" === r ? null : r || "{}" : "{}"; try { const t = JSON.parse(a); this.lodash_set(t, o, e), s = this.setval(JSON.stringify(t), i) } catch (t) { const r = {}; this.lodash_set(r, o, e), s = this.setval(JSON.stringify(r), i) } } else s = this.setval(e, t); return s } getval(e) { switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": return $persistentStore.read(e); case "Quantumult X": return $prefs.valueForKey(e); case "Node.js": return this.data = this.loaddata(), this.data[e]; default: return this.data && this.data[e] || null } } setval(e, t) { switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": return $persistentStore.write(e, t); case "Quantumult X": return $prefs.setValueForKey(e, t); case "Node.js": return this.data = this.loaddata(), this.data[t] = e, this.writedata(), !0; default: return this.data && this.data[t] || null } } initGotEnv(e) { this.got = this.got ? this.got : require("got"), this.cktough = this.cktough ? this.cktough : require("tough-cookie"), this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar, e && (e.headers = e.headers ? e.headers : {}, e && (e.headers = e.headers ? e.headers : {}, void 0 === e.headers.cookie && void 0 === e.headers.Cookie && void 0 === e.cookieJar && (e.cookieJar = this.ckjar))) } get(e, t = (() => { })) { switch (e.headers && (delete e.headers["Content-Type"], delete e.headers["Content-Length"], delete e.headers["content-type"], delete e.headers["content-length"]), e.params && (e.url += "?" + this.queryStr(e.params)), void 0 === e.followRedirect || e.followRedirect || ((this.isSurge() || this.isLoon()) && (e["auto-redirect"] = !1), this.isQuanX() && (e.opts ? e.opts.redirection = !1 : e.opts = { redirection: !1 })), this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": default: this.isSurge() && this.isNeedRewrite && (e.headers = e.headers || {}, Object.assign(e.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient.get(e, ((e, s, i) => { !e && s && (s.body = i, s.statusCode = s.status ? s.status : s.statusCode, s.status = s.statusCode), t(e, s, i) })); break; case "Quantumult X": this.isNeedRewrite && (e.opts = e.opts || {}, Object.assign(e.opts, { hints: !1 })), $task.fetch(e).then((e => { const { statusCode: s, statusCode: i, headers: o, body: r, bodyBytes: a } = e; t(null, { status: s, statusCode: i, headers: o, body: r, bodyBytes: a }, r, a) }), (e => t(e && e.error || "UndefinedError"))); break; case "Node.js": let s = require("iconv-lite"); this.initGotEnv(e), this.got(e).on("redirect", ((e, t) => { try { if (e.headers["set-cookie"]) { const s = e.headers["set-cookie"].map(this.cktough.Cookie.parse).toString(); s && this.ckjar.setCookieSync(s, null), t.cookieJar = this.ckjar } } catch (e) { this.logErr(e) } })).then((e => { const { statusCode: i, statusCode: o, headers: r, rawBody: a } = e, n = s.decode(a, this.encoding); t(null, { status: i, statusCode: o, headers: r, rawBody: a, body: n }, n) }), (e => { const { message: i, response: o } = e; t(i, o, o && s.decode(o.rawBody, this.encoding)) })); break } } post(e, t = (() => { })) { const s = e.method ? e.method.toLocaleLowerCase() : "post"; switch (e.body && e.headers && !e.headers["Content-Type"] && !e.headers["content-type"] && (e.headers["content-type"] = "application/x-www-form-urlencoded"), e.headers && (delete e.headers["Content-Length"], delete e.headers["content-length"]), void 0 === e.followRedirect || e.followRedirect || ((this.isSurge() || this.isLoon()) && (e["auto-redirect"] = !1), this.isQuanX() && (e.opts ? e.opts.redirection = !1 : e.opts = { redirection: !1 })), this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": default: this.isSurge() && this.isNeedRewrite && (e.headers = e.headers || {}, Object.assign(e.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient[s](e, ((e, s, i) => { !e && s && (s.body = i, s.statusCode = s.status ? s.status : s.statusCode, s.status = s.statusCode), t(e, s, i) })); break; case "Quantumult X": e.method = s, this.isNeedRewrite && (e.opts = e.opts || {}, Object.assign(e.opts, { hints: !1 })), $task.fetch(e).then((e => { const { statusCode: s, statusCode: i, headers: o, body: r, bodyBytes: a } = e; t(null, { status: s, statusCode: i, headers: o, body: r, bodyBytes: a }, r, a) }), (e => t(e && e.error || "UndefinedError"))); break; case "Node.js": let i = require("iconv-lite"); this.initGotEnv(e); const { url: o, ...r } = e; this.got[s](o, r).then((e => { const { statusCode: s, statusCode: o, headers: r, rawBody: a } = e, n = i.decode(a, this.encoding); t(null, { status: s, statusCode: o, headers: r, rawBody: a, body: n }, n) }), (e => { const { message: s, response: o } = e; t(s, o, o && i.decode(o.rawBody, this.encoding)) })); break } } time(e, t = null) { const s = t ? new Date(t) : new Date; let i = { "M+": s.getMonth() + 1, "d+": s.getDate(), "H+": s.getHours(), "m+": s.getMinutes(), "s+": s.getSeconds(), "q+": Math.floor((s.getMonth() + 3) / 3), S: s.getMilliseconds() }; /(y+)/.test(e) && (e = e.replace(RegExp.$1, (s.getFullYear() + "").substr(4 - RegExp.$1.length))); for (let t in i) new RegExp("(" + t + ")").test(e) && (e = e.replace(RegExp.$1, 1 == RegExp.$1.length ? i[t] : ("00" + i[t]).substr(("" + i[t]).length))); return e } queryStr(e) { let t = ""; for (const s in e) { let i = e[s]; null != i && "" !== i && ("object" == typeof i && (i = JSON.stringify(i)), t += `${s}=${i}&`) } return t = t.substring(0, t.length - 1), t } msg(t = e, s = "", i = "", o = {}) { const r = e => { const { $open: t, $copy: s, $media: i, $mediaMime: o } = e; switch (typeof e) { case void 0: return e; case "string": switch (this.getEnv()) { case "Surge": case "Stash": default: return { url: e }; case "Loon": case "Shadowrocket": return e; case "Quantumult X": return { "open-url": e }; case "Node.js": return }case "object": switch (this.getEnv()) { case "Surge": case "Stash": case "Shadowrocket": default: { const r = {}; let a = e.openUrl || e.url || e["open-url"] || t; a && Object.assign(r, { action: "open-url", url: a }); let n = e["update-pasteboard"] || e.updatePasteboard || s; n && Object.assign(r, { action: "clipboard", text: n }); let h = e.mediaUrl || e["media-url"] || i; if (h) { let e, t; if (h.startsWith("http")); else if (h.startsWith("data:")) { const [s] = h.split(";"), [, i] = h.split(","); e = i, t = s.replace("data:", "") } else { e = h, t = (e => { const t = { JVBERi0: "application/pdf", R0lGODdh: "image/gif", R0lGODlh: "image/gif", iVBORw0KGgo: "image/png", "/9j/": "image/jpg" }; for (var s in t) if (0 === e.indexOf(s)) return t[s]; return null })(h) } Object.assign(r, { "media-url": h, "media-base64": e, "media-base64-mime": o ?? t }) } return Object.assign(r, { "auto-dismiss": e["auto-dismiss"], sound: e.sound }), r } case "Loon": { const s = {}; let o = e.openUrl || e.url || e["open-url"] || t; o && Object.assign(s, { openUrl: o }); let r = e.mediaUrl || e["media-url"] || i; return r && Object.assign(s, { mediaUrl: r }), console.log(JSON.stringify(s)), s } case "Quantumult X": { const o = {}; let r = e["open-url"] || e.url || e.openUrl || t; r && Object.assign(o, { "open-url": r }); let a = e.mediaUrl || e["media-url"] || i; a && Object.assign(o, { "media-url": a }); let n = e["update-pasteboard"] || e.updatePasteboard || s; return n && Object.assign(o, { "update-pasteboard": n }), console.log(JSON.stringify(o)), o } case "Node.js": return }default: return } }; if (!this.isMute) switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": default: $notification.post(t, s, i, r(o)); break; case "Quantumult X": $notify(t, s, i, r(o)); break; case "Node.js": break }if (!this.isMuteLog) { let e = ["", "============================"]; e.push(t), s && e.push(s), i && e.push(i), console.log(e.join("\n")), this.logs = this.logs.concat(e) } } debug(...e) { this.logLevels[this.logLevel] <= this.logLevels.debug && (e.length > 0 && (this.logs = [...this.logs, ...e]), console.log(`${this.logLevelPrefixs.debug}${e.map((e => e ?? String(e))).join(this.logSeparator)}`)) } info(...e) { this.logLevels[this.logLevel] <= this.logLevels.info && (e.length > 0 && (this.logs = [...this.logs, ...e]), console.log(`${this.logLevelPrefixs.info}${e.map((e => e ?? String(e))).join(this.logSeparator)}`)) } warn(...e) { this.logLevels[this.logLevel] <= this.logLevels.warn && (e.length > 0 && (this.logs = [...this.logs, ...e]), console.log(`${this.logLevelPrefixs.warn}${e.map((e => e ?? String(e))).join(this.logSeparator)}`)) } error(...e) { this.logLevels[this.logLevel] <= this.logLevels.error && (e.length > 0 && (this.logs = [...this.logs, ...e]), console.log(`${this.logLevelPrefixs.error}${e.map((e => e ?? String(e))).join(this.logSeparator)}`)) } log(...e) { e.length > 0 && (this.logs = [...this.logs, ...e]), console.log(e.map((e => e ?? String(e))).join(this.logSeparator)) } logErr(e, t) { switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": case "Quantumult X": default: this.log("", `❗️${this.name}, 错误!`, t, e); break; case "Node.js": this.log("", `❗️${this.name}, 错误!`, t, void 0 !== e.message ? e.message : e, e.stack); break } } wait(e) { return new Promise((t => setTimeout(t, e))) } done(e = {}) { const t = ((new Date).getTime() - this.startTime) / 1e3; switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": case "Quantumult X": default: $done(e); break; case "Node.js": process.exit(1) } } }(e, t) } \ No newline at end of file diff --git a/Ctrip-DailyBonus/Ctrip.js b/Ctrip-DailyBonus/Ctrip.js new file mode 100644 index 0000000000..b20a3ccdcb --- /dev/null +++ b/Ctrip-DailyBonus/Ctrip.js @@ -0,0 +1,140 @@ +/******************************** +携程旅行签到脚本 + +支持多账号,支持Node.js,支持Bark推送。 +配置脚本后登陆"携程旅行"微信小程序或"携程网页版"(https://m.ctrip.com/)即可获取账号授权。多账号请勿"退出登陆"。 + +脚本作者:@NobyDa +更新时间:2024/05/09 +平台兼容:Surge / QuantumultX / Loon / Stash / Node.js +模块依赖(Node.js):iconv-lite / got@11.8.3 / tough-cookie +环境变量(Node.js):CTRIP_AUTH / CTRIP_BARK_KEY + +********************************* +Surge(iOS 5.9.0+/macOS 5.5.0+)模块: +https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/CtripDailyBonus.sgmodule + +********************************* +QuantumultX 任务仓库(Gallery)订阅: +https://raw.githubusercontent.com/NobyDa/Script/master/NobyDa_BoxJs.json + +工具&分析->HTTP请求->右上角添加任务仓库->选择携程脚本添加定时任务和附加组件 + +*********************************/ + +const $ = new Env('CTRIP_DAILY_BONUS'); +const barkKey = $.isNode() && process.env['CTRIP_BARK_KEY'] || ''; // bark key +const notifyMsg = []; +const auth = ''; // '{"account":{"user1":{"auth":"xxx"},"user2":{"auth":"xxx"}}}' + +!(async () => { + $.logLevel = $.getdata(`@${$.name}.Debug`) == 'true' && 'debug' || 'info'; + const user = JSON.parse(auth || $.getdata($.name) || ($.isNode() && process.env['CTRIP_AUTH']) || '{}'); + const userNum = Object.keys(user.account || {}).length; + if (typeof $response !== 'undefined') { + const body = JSON.parse($response.body || '{}'); + return GetAuth(body, user); + } + if (userNum) { + const invalidUser = []; + for (const i in user.account) { + const text = [ + userNum > 1 && `[账号${notifyMsg.length + 1}(${i.slice(-4)})]`, + await Checkin(user.account[i].auth), + await Points(user.account[i].auth) + ].filter((v) => v).join(', '); + if (text.includes('登陆失效')) { + invalidUser.push(i) + } + $.info(text); + notifyMsg.push(text); + } + invalidUser.forEach((i) => delete user.account[i] && !$.isNode() && $.setjson(user, $.name)); + } else { + notifyMsg.push(`未获取授权!`); + } +})() + .catch((err) => notifyMsg.push(`错误: ${err}`) && $.error(err)) + .finally(async () => { + if (notifyMsg.length) { + $.msg(`携程旅行`, ``, notifyMsg.join('\n')) + } + if (barkKey) { + await BarkNotify($, barkKey, `携程旅行`, notifyMsg.join('\n')); + } + $.done({}); + }); + +function Checkin(key) { + const opts = { + url: 'https://m.ctrip.com/restapi/soa2/22769/signToday', + headers: { + "Content-Type": "application/json", + "User-Agent": 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/21E219 MicroMessenger/8.0.49' + }, + body: JSON.stringify({ head: { auth: key } }) + }; + $.debug(`Send checkin request:`, $.toStr(opts, 'error', null, 1)); + return $.http.post(opts) + .then((resp) => { + $.debug(`Receive checkin request response:`, $.toStr(resp)) + resp.body = JSON.parse(resp.body?.startsWith('{') && resp.body || '{}'); + if (resp.body.code == 0) { + return '签到成功' + } else if (resp.body.code == 400001) { + return '已签过' + } else if (resp.body.code == 404001) { + return '登陆失效, 尝试移除账号...' + } else { + return `签到失败(${resp.body.message})` + } + }) + .catch((err) => { + $.error(`Send checkin request error:`, err); + return `签到错误` + }) +} + +function Points(key) { + const opts = { + url: 'https://m.ctrip.com/restapi/soa2/15634/json/getPointsOrderUserInfo', + headers: { + "Content-Type": "application/json", + "User-Agent": 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/21E219 MicroMessenger/8.0.49' + }, + body: JSON.stringify({ needUserInfo: true, head: { auth: key } }) + }; + $.debug(`Send points request:`, $.toStr(opts, 'error', null, 1)); + return $.http.post(opts) + .then((resp) => { + $.debug(`Receive points request response:`, $.toStr(resp)) + resp.body = JSON.parse(resp.body?.startsWith('{') && resp.body || '{}'); + if (resp.body.isLogin) { + return `总积分: ${resp.body.availableCredits || 0}` + } + }) + .catch((err) => { + $.error(`Send points request error:`, err) + return `总积分: 查询错误` + }) +} + +function GetAuth(body, data) { + if (body.ticket && body.uid) { + if (!data.account || !data.account[body.uid]) { + notifyMsg.push(`账号: ${body.uid}\n写入授权成功!`); + } else { + $.info(`账号: ${body.uid}\n更新授权成功!`); + } + data.account = { ...data.account, ...{ [body.uid]: { auth: body.ticket } } }; + } else { + $.error(`写入授权失败, 授权值缺失.`) + } + return $.setjson(data, $.name); +} + +//Bark APP notify +async function BarkNotify(c, k, t, b) { for (let i = 0; i < 3; i++) { c.log(`🔷Bark notify >> Start push (${i + 1})`); const s = await new Promise((n) => { c.post({ url: 'https://api.day.app/push', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: t, body: b, device_key: k, ext_params: { group: t } }) }, (e, r, d) => r && r.status == 200 ? n(1) : n(d || e)) }); if (s === 1) { c.log('✅Push success!'); break } else { c.log(`❌Push failed! >> ${s.message || s}`) } } }; + +// https://github.com/chavyleung/scripts/blob/master/Env.min.js +function Env(t, e) { class s { constructor(t) { this.env = t } send(t, e = "GET") { t = "string" == typeof t ? { url: t } : t; let s = this.get; return "POST" === e && (s = this.post), new Promise(((e, i) => { s.call(this, t, ((t, s, o) => { t ? i(t) : e(s) })) })) } get(t) { return this.send.call(this.env, t) } post(t) { return this.send.call(this.env, t, "POST") } } return new class { constructor(t, e) { this.logLevels = { debug: 0, info: 1, warn: 2, error: 3 }, this.logLevelPrefixs = { debug: "[DEBUG] ", info: "[INFO] ", warn: "[WARN] ", error: "[ERROR] " }, this.logLevel = "info", this.name = t, this.http = new s(this), this.data = null, this.dataFile = "box.dat", this.logs = [], this.isMute = !1, this.isNeedRewrite = !1, this.logSeparator = "\n", this.encoding = "utf-8", this.startTime = (new Date).getTime(), Object.assign(this, e), this.log("", `🔔${this.name}, 开始!`) } getEnv() { return "undefined" != typeof $environment && $environment["surge-version"] ? "Surge" : "undefined" != typeof $environment && $environment["stash-version"] ? "Stash" : "undefined" != typeof module && module.exports ? "Node.js" : "undefined" != typeof $task ? "Quantumult X" : "undefined" != typeof $loon ? "Loon" : "undefined" != typeof $rocket ? "Shadowrocket" : void 0 } isNode() { return "Node.js" === this.getEnv() } isQuanX() { return "Quantumult X" === this.getEnv() } isSurge() { return "Surge" === this.getEnv() } isLoon() { return "Loon" === this.getEnv() } isShadowrocket() { return "Shadowrocket" === this.getEnv() } isStash() { return "Stash" === this.getEnv() } toObj(t, e = null) { try { return JSON.parse(t) } catch { return e } } toStr(t, e = null, ...s) { try { return JSON.stringify(t, ...s) } catch { return e } } getjson(t, e) { let s = e; if (this.getdata(t)) try { s = JSON.parse(this.getdata(t)) } catch { } return s } setjson(t, e) { try { return this.setdata(JSON.stringify(t), e) } catch { return !1 } } getScript(t) { return new Promise((e => { this.get({ url: t }, ((t, s, i) => e(i))) })) } runScript(t, e) { return new Promise((s => { let i = this.getdata("@chavy_boxjs_userCfgs.httpapi"); i = i ? i.replace(/\n/g, "").trim() : i; let o = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout"); o = o ? 1 * o : 20, o = e && e.timeout ? e.timeout : o; const [r, a] = i.split("@"), n = { url: `http://${a}/v1/scripting/evaluate`, body: { script_text: t, mock_type: "cron", timeout: o }, headers: { "X-Key": r, Accept: "*/*" }, timeout: o }; this.post(n, ((t, e, i) => s(i))) })).catch((t => this.logErr(t))) } loaddata() { if (!this.isNode()) return {}; { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const t = this.path.resolve(this.dataFile), e = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(t), i = !s && this.fs.existsSync(e); if (!s && !i) return {}; { const i = s ? t : e; try { return JSON.parse(this.fs.readFileSync(i)) } catch (t) { return {} } } } } writedata() { if (this.isNode()) { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const t = this.path.resolve(this.dataFile), e = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(t), i = !s && this.fs.existsSync(e), o = JSON.stringify(this.data); s ? this.fs.writeFileSync(t, o) : i ? this.fs.writeFileSync(e, o) : this.fs.writeFileSync(t, o) } } lodash_get(t, e, s) { const i = e.replace(/\[(\d+)\]/g, ".$1").split("."); let o = t; for (const t of i) if (o = Object(o)[t], void 0 === o) return s; return o } lodash_set(t, e, s) { return Object(t) !== t || (Array.isArray(e) || (e = e.toString().match(/[^.[\]]+/g) || []), e.slice(0, -1).reduce(((t, s, i) => Object(t[s]) === t[s] ? t[s] : t[s] = Math.abs(e[i + 1]) >> 0 == +e[i + 1] ? [] : {}), t)[e[e.length - 1]] = s), t } getdata(t) { let e = this.getval(t); if (/^@/.test(t)) { const [, s, i] = /^@(.*?)\.(.*?)$/.exec(t), o = s ? this.getval(s) : ""; if (o) try { const t = JSON.parse(o); e = t ? this.lodash_get(t, i, "") : e } catch (t) { e = "" } } return e } setdata(t, e) { let s = !1; if (/^@/.test(e)) { const [, i, o] = /^@(.*?)\.(.*?)$/.exec(e), r = this.getval(i), a = i ? "null" === r ? null : r || "{}" : "{}"; try { const e = JSON.parse(a); this.lodash_set(e, o, t), s = this.setval(JSON.stringify(e), i) } catch (e) { const r = {}; this.lodash_set(r, o, t), s = this.setval(JSON.stringify(r), i) } } else s = this.setval(t, e); return s } getval(t) { switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": return $persistentStore.read(t); case "Quantumult X": return $prefs.valueForKey(t); case "Node.js": return this.data = this.loaddata(), this.data[t]; default: return this.data && this.data[t] || null } } setval(t, e) { switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": return $persistentStore.write(t, e); case "Quantumult X": return $prefs.setValueForKey(t, e); case "Node.js": return this.data = this.loaddata(), this.data[e] = t, this.writedata(), !0; default: return this.data && this.data[e] || null } } initGotEnv(t) { this.got = this.got ? this.got : require("got"), this.cktough = this.cktough ? this.cktough : require("tough-cookie"), this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar, t && (t.headers = t.headers ? t.headers : {}, t && (t.headers = t.headers ? t.headers : {}, void 0 === t.headers.cookie && void 0 === t.headers.Cookie && void 0 === t.cookieJar && (t.cookieJar = this.ckjar))) } get(t, e = (() => { })) { switch (t.headers && (delete t.headers["Content-Type"], delete t.headers["Content-Length"], delete t.headers["content-type"], delete t.headers["content-length"]), t.params && (t.url += "?" + this.queryStr(t.params)), void 0 === t.followRedirect || t.followRedirect || ((this.isSurge() || this.isLoon()) && (t["auto-redirect"] = !1), this.isQuanX() && (t.opts ? t.opts.redirection = !1 : t.opts = { redirection: !1 })), this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": default: this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient.get(t, ((t, s, i) => { !t && s && (s.body = i, s.statusCode = s.status ? s.status : s.statusCode, s.status = s.statusCode), e(t, s, i) })); break; case "Quantumult X": this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { hints: !1 })), $task.fetch(t).then((t => { const { statusCode: s, statusCode: i, headers: o, body: r, bodyBytes: a } = t; e(null, { status: s, statusCode: i, headers: o, body: r, bodyBytes: a }, r, a) }), (t => e(t && t.error || "UndefinedError"))); break; case "Node.js": let s = require("iconv-lite"); this.initGotEnv(t), this.got(t).on("redirect", ((t, e) => { try { if (t.headers["set-cookie"]) { const s = t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString(); s && this.ckjar.setCookieSync(s, null), e.cookieJar = this.ckjar } } catch (t) { this.logErr(t) } })).then((t => { const { statusCode: i, statusCode: o, headers: r, rawBody: a } = t, n = s.decode(a, this.encoding); e(null, { status: i, statusCode: o, headers: r, rawBody: a, body: n }, n) }), (t => { const { message: i, response: o } = t; e(i, o, o && s.decode(o.rawBody, this.encoding)) })); break } } post(t, e = (() => { })) { const s = t.method ? t.method.toLocaleLowerCase() : "post"; switch (t.body && t.headers && !t.headers["Content-Type"] && !t.headers["content-type"] && (t.headers["content-type"] = "application/x-www-form-urlencoded"), t.headers && (delete t.headers["Content-Length"], delete t.headers["content-length"]), void 0 === t.followRedirect || t.followRedirect || ((this.isSurge() || this.isLoon()) && (t["auto-redirect"] = !1), this.isQuanX() && (t.opts ? t.opts.redirection = !1 : t.opts = { redirection: !1 })), this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": default: this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient[s](t, ((t, s, i) => { !t && s && (s.body = i, s.statusCode = s.status ? s.status : s.statusCode, s.status = s.statusCode), e(t, s, i) })); break; case "Quantumult X": t.method = s, this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { hints: !1 })), $task.fetch(t).then((t => { const { statusCode: s, statusCode: i, headers: o, body: r, bodyBytes: a } = t; e(null, { status: s, statusCode: i, headers: o, body: r, bodyBytes: a }, r, a) }), (t => e(t && t.error || "UndefinedError"))); break; case "Node.js": let i = require("iconv-lite"); this.initGotEnv(t); const { url: o, ...r } = t; this.got[s](o, r).then((t => { const { statusCode: s, statusCode: o, headers: r, rawBody: a } = t, n = i.decode(a, this.encoding); e(null, { status: s, statusCode: o, headers: r, rawBody: a, body: n }, n) }), (t => { const { message: s, response: o } = t; e(s, o, o && i.decode(o.rawBody, this.encoding)) })); break } } time(t, e = null) { const s = e ? new Date(e) : new Date; let i = { "M+": s.getMonth() + 1, "d+": s.getDate(), "H+": s.getHours(), "m+": s.getMinutes(), "s+": s.getSeconds(), "q+": Math.floor((s.getMonth() + 3) / 3), S: s.getMilliseconds() }; /(y+)/.test(t) && (t = t.replace(RegExp.$1, (s.getFullYear() + "").substr(4 - RegExp.$1.length))); for (let e in i) new RegExp("(" + e + ")").test(t) && (t = t.replace(RegExp.$1, 1 == RegExp.$1.length ? i[e] : ("00" + i[e]).substr(("" + i[e]).length))); return t } queryStr(t) { let e = ""; for (const s in t) { let i = t[s]; null != i && "" !== i && ("object" == typeof i && (i = JSON.stringify(i)), e += `${s}=${i}&`) } return e = e.substring(0, e.length - 1), e } msg(e = t, s = "", i = "", o = {}) { const r = t => { const { $open: e, $copy: s, $media: i, $mediaMime: o } = t; switch (typeof t) { case void 0: return t; case "string": switch (this.getEnv()) { case "Surge": case "Stash": default: return { url: t }; case "Loon": case "Shadowrocket": return t; case "Quantumult X": return { "open-url": t }; case "Node.js": return }case "object": switch (this.getEnv()) { case "Surge": case "Stash": case "Shadowrocket": default: { const r = {}; let a = t.openUrl || t.url || t["open-url"] || e; a && Object.assign(r, { action: "open-url", url: a }); let n = t["update-pasteboard"] || t.updatePasteboard || s; if (n && Object.assign(r, { action: "clipboard", text: n }), i) { let t, e, s; if (i.startsWith("http")) t = i; else if (i.startsWith("data:")) { const [t] = i.split(";"), [, o] = i.split(","); e = o, s = t.replace("data:", "") } else { e = i, s = (t => { const e = { JVBERi0: "application/pdf", R0lGODdh: "image/gif", R0lGODlh: "image/gif", iVBORw0KGgo: "image/png", "/9j/": "image/jpg" }; for (var s in e) if (0 === t.indexOf(s)) return e[s]; return null })(i) } Object.assign(r, { "media-url": t, "media-base64": e, "media-base64-mime": o ?? s }) } return Object.assign(r, { "auto-dismiss": t["auto-dismiss"], sound: t.sound }), r } case "Loon": { const s = {}; let o = t.openUrl || t.url || t["open-url"] || e; o && Object.assign(s, { openUrl: o }); let r = t.mediaUrl || t["media-url"]; return i?.startsWith("http") && (r = i), r && Object.assign(s, { mediaUrl: r }), console.log(JSON.stringify(s)), s } case "Quantumult X": { const o = {}; let r = t["open-url"] || t.url || t.openUrl || e; r && Object.assign(o, { "open-url": r }); let a = t["media-url"] || t.mediaUrl; i?.startsWith("http") && (a = i), a && Object.assign(o, { "media-url": a }); let n = t["update-pasteboard"] || t.updatePasteboard || s; return n && Object.assign(o, { "update-pasteboard": n }), console.log(JSON.stringify(o)), o } case "Node.js": return }default: return } }; if (!this.isMute) switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": default: $notification.post(e, s, i, r(o)); break; case "Quantumult X": $notify(e, s, i, r(o)); break; case "Node.js": break }if (!this.isMuteLog) { let t = ["", "==============📣系统通知📣=============="]; t.push(e), s && t.push(s), i && t.push(i), console.log(t.join("\n")), this.logs = this.logs.concat(t) } } debug(...t) { this.logLevels[this.logLevel] <= this.logLevels.debug && (t.length > 0 && (this.logs = [...this.logs, ...t]), console.log(`${this.logLevelPrefixs.debug}${t.map((t => t ?? String(t))).join(this.logSeparator)}`)) } info(...t) { this.logLevels[this.logLevel] <= this.logLevels.info && (t.length > 0 && (this.logs = [...this.logs, ...t]), console.log(`${this.logLevelPrefixs.info}${t.map((t => t ?? String(t))).join(this.logSeparator)}`)) } warn(...t) { this.logLevels[this.logLevel] <= this.logLevels.warn && (t.length > 0 && (this.logs = [...this.logs, ...t]), console.log(`${this.logLevelPrefixs.warn}${t.map((t => t ?? String(t))).join(this.logSeparator)}`)) } error(...t) { this.logLevels[this.logLevel] <= this.logLevels.error && (t.length > 0 && (this.logs = [...this.logs, ...t]), console.log(`${this.logLevelPrefixs.error}${t.map((t => t ?? String(t))).join(this.logSeparator)}`)) } log(...t) { t.length > 0 && (this.logs = [...this.logs, ...t]), console.log(t.map((t => t ?? String(t))).join(this.logSeparator)) } logErr(t, e) { switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": case "Quantumult X": default: this.log("", `❗️${this.name}, 错误!`, e, t); break; case "Node.js": this.log("", `❗️${this.name}, 错误!`, e, void 0 !== t.message ? t.message : t, t.stack); break } } wait(t) { return new Promise((e => setTimeout(e, t))) } done(t = {}) { const e = ((new Date).getTime() - this.startTime) / 1e3; switch (this.log("", `🔔${this.name}, 结束! 🕛 ${e} 秒`), this.log(), this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": case "Quantumult X": default: $done(t); break; case "Node.js": process.exit(1) } } }(t, e) } \ No newline at end of file diff --git a/Debug/Real-time-debug.js b/Debug/Real-time-debug.js new file mode 100644 index 0000000000..7abff11a82 --- /dev/null +++ b/Debug/Real-time-debug.js @@ -0,0 +1,64 @@ +/* + * LAN script real-time debug + * + * PC: Use "Live Server" plugin in VSCode to create a LAN backend + * APP: After backend address is modified in script, use this script as script path + */ + +!async function() { + const _$ = new nobyda(); + const _r = await new Promise(e => { + _$.get({ + url: 'http://192.168.1.66:5500/debug.js' // LAN backend address + }, (t, c, o) => { + if (c && c.status == 200 && o) { + _$.write(o, 'Real-time-debug'); + e(o); + } + }); + setTimeout(e, 100); + }); + if (_r) { + console.log("🌐 Run local network script..."); + eval(_r); + } else { + console.log("⚠️ Run cache script..."); + eval(_$.read('Real-time-debug')) + } + + function nobyda() { + const isSurge = typeof $httpClient != "undefined"; + const isQuanX = typeof $task != "undefined"; + const adapterStatus = (response) => { + if (response) { + if (response.status) { + response["statusCode"] = response.status + } else if (response.statusCode) { + response["status"] = response.statusCode + } + } + return response + }; + this.write = (value, key) => { + if (isQuanX) return $prefs.setValueForKey(value, key); + if (isSurge) return $persistentStore.write(value, key); + }; + this.read = (key) => { + if (isQuanX) return $prefs.valueForKey(key); + if (isSurge) return $persistentStore.read(key); + }; + this.get = (options, callback) => { + if (isQuanX) { + $task.fetch(options).then(response => { + callback(null, adapterStatus(response), response.body) + }, reason => callback(reason.error, null, null)) + } + if (isSurge) { + $httpClient.get(options, (error, response, body) => { + callback(error, adapterStatus(response), body) + }) + } + }; + this.done = (value = {}) => $done(value) + } +}(); \ No newline at end of file diff --git a/Disney/DisneyRating.js b/Disney/DisneyRating.js new file mode 100644 index 0000000000..8ea74acf29 --- /dev/null +++ b/Disney/DisneyRating.js @@ -0,0 +1,253 @@ +/********************************* +Disney+ 显示IMDb评分 / 烂番茄评分 / 豆瓣评分 + +脚本作者: @NobyDa +脚本兼容: Surge、QuantumultX、Loon +系统兼容: iOS14+ +更新时间: 2024/05/04 +脚本参考: https://github.com/yichahucha/surge/blob/master/nf_rating.js + +Surge模块: +https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/DisneyRating.sgmodule + +QuantumultX重写引用: +https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/DisneyRating.snippet + +*********************************/ + +const $tool = new Tool(); +const consoleLog = false; +let obj = $response.body; +let IMDbApikeys = IMDbApikeyList(); +let IMDbApikey = $tool.read("ImdbApikeyCacheKey"); +if (!IMDbApikey) { + updateIMDbApikey(); +} + +const requestRatings = async () => { + if (consoleLog) console.log("Disney Original Body:\n" + obj); + obj = JSON.parse(obj); + const sliced = obj?.data?.page?.actions?.[0]?.internalTitle?.split(' - '); + let title = sliced?.[0] || obj?.data?.page?.visuals?.title; + if (title) { + title = title.replace(/.+?:\s|\s?\(.+?\)\s?/g,''); + } else { + throw 'NO TITLE'; + } + const year = obj?.data?.page?.visuals?.metastringParts?.releaseYearRange?.startYear; + const type = (sliced?.[1]?.startsWith('s') && 'series') || (sliced?.[1] == 'movie' && 'movie'); + const IMDb = await requestIMDbRating(title, year, type); + const Douban = await requestDoubanRating(IMDb.id); + const IMDbrating = IMDb.msg.rating; + const tomatoes = IMDb.msg.tomatoes; + const country = IMDb.msg.country; + // const awards = IMDb.msg.awards; + const doubanRating = Douban.rating; + // const message = `${awards.length > 0 ? awards + "\n" : ""}${country}\n${IMDbrating}\n${doubanRating}${tomatoes.length > 0 ? "\n" + tomatoes + "\n" : "\n"}`; + return { country, tomatoes, IMDbrating, doubanRating }; +} + +requestRatings() + .then(data => { + if (obj?.data?.page?.visuals) { + obj.data.page.visuals.promoLabel = { + promoLabelType: "generic", + header: `${data.country}${data.tomatoes ? `\n${data.tomatoes}` : ``}`, + subheader: `${data.IMDbrating}${data.doubanRating ? `\n${data.doubanRating}` : ``}` + } + } + if (consoleLog) console.log("Disney Modified Body:\n" + JSON.stringify(obj)); + }) + .catch(error => console.log(`ERROR: ${error}`)) + .finally(() => $done({ body: typeof obj == 'object' ? JSON.stringify(obj) : obj })); + +function requestDoubanRating(imdbId) { + return new Promise(function (resolve, reject) { + const url = `https://www.douban.com/search?cat=1002&q=${imdbId}`; + if (consoleLog) console.log("Disney Douban Rating URL:\n" + url); + $tool.get(url, function (error, response, data) { + if (!error) { + if (consoleLog) console.log("Disney Douban Rating Data:\n" + data); + if (response.status == 200) { + const rating = get_douban_rating_message(data); + resolve({ rating }); + } else { + resolve({}); + } + } else { + console.log("Disney Douban Rating Error: " + error); + resolve({}); + } + }); + }); +} + +function requestIMDbRating(title, year, type) { + return new Promise(function (resolve, reject) { + let url = "https://www.omdbapi.com/?t=" + encodeURIComponent(title) + "&apikey=" + IMDbApikey; + if (year) url += "&y=" + year; + if (type) url += "&type=" + type; + if (consoleLog) console.log("Disney IMDb Rating URL:\n" + url); + $tool.get(url, function (error, response, data) { + if (!error) { + if (consoleLog) console.log("Disney IMDb Rating Data:\n" + data); + if (response.status == 200) { + const obj = JSON.parse(data); + if (obj.Response == "True") { + const id = obj.imdbID; + const msg = get_IMDb_message(obj); + resolve({ id, msg }); + } else { + reject(`Title [${title}] IMDb data not found`); + } + } else if (response.status == 401) { + if (IMDbApikeys.length > 1) { + updateIMDbApikey(); + requestIMDbRating(title, year, type); + } else { + reject(`IMDb Key invalid`); + } + } else { + reject(`Unknown status: ${response.status}, Data: ${data}`); + } + } else { + reject(`IMDB data response failed: ${error}`); + } + }); + }); +} + +function updateIMDbApikey() { + if (IMDbApikey) IMDbApikeys.splice(IMDbApikeys.indexOf(IMDbApikey), 1); + const index = Math.floor(Math.random() * IMDbApikeys.length); + IMDbApikey = IMDbApikeys[index]; + $tool.write(IMDbApikey, "ImdbApikeyCacheKey"); +} + +function get_IMDb_message(data) { + let rating_message = "IMDb: ⭐️ N/A"; + let tomatoes_message = ""; + let country_message = ""; + let ratings = data.Ratings; + let awards_message = ""; + if (data.Awards && data.Awards != "N/A") { + awards_message = "🏆 " + data.Awards; + } + if (ratings.length > 0) { + const imdb_source = ratings[0]["Source"]; + if (imdb_source == "Internet Movie Database") { + const imdb_votes = data.imdbVotes; + const imdb_rating = ratings[0]["Value"]; + rating_message = "IMDb: ⭐️ " + imdb_rating + " " + imdb_votes; + if (data.Type == "movie") { + if (ratings.length > 1) { + const source = ratings[1]["Source"]; + if (source == "Rotten Tomatoes") { + const tomatoes = ratings[1]["Value"]; + tomatoes_message = "Tomatoes: 🍅 " + tomatoes; + } + } + } + } + } + country_message = get_country_message(data.Country); + return { rating: rating_message, tomatoes: tomatoes_message, country: country_message, awards: awards_message } +} + +function get_douban_rating_message(data) { + const s = data.replace(/\n| |&#\d{2}/g, '') + .match(/\[(\u7535\u5f71|\u7535\u89c6\u5267)\].+?subject-cast\">.+?<\/span>/g); + const average = s ? s[0].split(/">(\d\.\d) { + emoji_country += countryEmoji(item) + " " + item + ", "; + }); + return emoji_country.slice(0, -2); +} + +// function errorTip() { +// return { noData: "⭐️ N/A", error: "❌ N/A" } +// } + +function IMDbApikeyList() { + const apikeys = [ + "f75e0253", "d8bb2d6b", + "ae64ce8d", "7218d678", + "b2650e38", "8c4a29ab", + "9bd135c2", "953dbabe", + "1a66ef12", "3e7ea721", + "457fc4ff", "d2131426", + "9cc1a9b7", "e53c2c11", + "f6dfce0e", "b9db622f", + "e6bde2b9", "d324dbab", + "d7904fa3", "aeaf88b9", + "4e89234e",]; + return apikeys; +} + +function countryEmoji(name) { const emojiMap = { "Chequered": "🏁", "Triangular": "🚩", "Crossed": "🎌", "Black": "🏴", "White": "🏳", "Rainbow": "🏳️‍🌈", "Pirate": "🏴‍☠️", "Ascension Island": "🇦🇨", "Andorra": "🇦🇩", "United Arab Emirates": "🇦🇪", "Afghanistan": "🇦🇫", "Antigua & Barbuda": "🇦🇬", "Anguilla": "🇦🇮", "Albania": "🇦🇱", "Armenia": "🇦🇲", "Angola": "🇦🇴", "Antarctica": "🇦🇶", "Argentina": "🇦🇷", "American Samoa": "🇦🇸", "Austria": "🇦🇹", "Australia": "🇦🇺", "Aruba": "🇦🇼", "Åland Islands": "🇦🇽", "Azerbaijan": "🇦🇿", "Bosnia & Herzegovina": "🇧🇦", "Barbados": "🇧🇧", "Bangladesh": "🇧🇩", "Belgium": "🇧🇪", "Burkina Faso": "🇧🇫", "Bulgaria": "🇧🇬", "Bahrain": "🇧🇭", "Burundi": "🇧🇮", "Benin": "🇧🇯", "St. Barthélemy": "🇧🇱", "Bermuda": "🇧🇲", "Brunei": "🇧🇳", "Bolivia": "🇧🇴", "Caribbean Netherlands": "🇧🇶", "Brazil": "🇧🇷", "Bahamas": "🇧🇸", "Bhutan": "🇧🇹", "Bouvet Island": "🇧🇻", "Botswana": "🇧🇼", "Belarus": "🇧🇾", "Belize": "🇧🇿", "Canada": "🇨🇦", "Cocos (Keeling) Islands": "🇨🇨", "Congo - Kinshasa": "🇨🇩", "Congo": "🇨🇩", "Central African Republic": "🇨🇫", "Congo - Brazzaville": "🇨🇬", "Switzerland": "🇨🇭", "Côte d’Ivoire": "🇨🇮", "Cook Islands": "🇨🇰", "Chile": "🇨🇱", "Cameroon": "🇨🇲", "China": "🇨🇳", "Colombia": "🇨🇴", "Clipperton Island": "🇨🇵", "Costa Rica": "🇨🇷", "Cuba": "🇨🇺", "Cape Verde": "🇨🇻", "Curaçao": "🇨🇼", "Christmas Island": "🇨🇽", "Cyprus": "🇨🇾", "Czechia": "🇨🇿", "Czech Republic": "🇨🇿", "Germany": "🇩🇪", "Diego Garcia": "🇩🇬", "Djibouti": "🇩🇯", "Denmark": "🇩🇰", "Dominica": "🇩🇲", "Dominican Republic": "🇩🇴", "Algeria": "🇩🇿", "Ceuta & Melilla": "🇪🇦", "Ecuador": "🇪🇨", "Estonia": "🇪🇪", "Egypt": "🇪🇬", "Western Sahara": "🇪🇭", "Eritrea": "🇪🇷", "Spain": "🇪🇸", "Ethiopia": "🇪🇹", "European Union": "🇪🇺", "Finland": "🇫🇮", "Fiji": "🇫🇯", "Falkland Islands": "🇫🇰", "Micronesia": "🇫🇲", "Faroe Islands": "🇫🇴", "France": "🇫🇷", "Gabon": "🇬🇦", "United Kingdom": "🇬🇧", "UK": "🇬🇧", "Grenada": "🇬🇩", "Georgia": "🇬🇪", "French Guiana": "🇬🇫", "Guernsey": "🇬🇬", "Ghana": "🇬🇭", "Gibraltar": "🇬🇮", "Greenland": "🇬🇱", "Gambia": "🇬🇲", "Guinea": "🇬🇳", "Guadeloupe": "🇬🇵", "Equatorial Guinea": "🇬🇶", "Greece": "🇬🇷", "South Georgia & South Sandwich Is lands": "🇬🇸", "Guatemala": "🇬🇹", "Guam": "🇬🇺", "Guinea-Bissau": "🇬🇼", "Guyana": "🇬🇾", "Hong Kong SAR China": "🇭🇰", "Hong Kong": "🇭🇰", "Heard & McDonald Islands": "🇭🇲", "Honduras": "🇭🇳", "Croatia": "🇭🇷", "Haiti": "🇭🇹", "Hungary": "🇭🇺", "Canary Islands": "🇮🇨", "Indonesia": "🇮🇩", "Ireland": "🇮🇪", "Israel": "🇮🇱", "Isle of Man": "🇮🇲", "India": "🇮🇳", "British Indian Ocean Territory": "🇮🇴", "Iraq": "🇮🇶", "Iran": "🇮🇷", "Iceland": "🇮🇸", "Italy": "🇮🇹", "Jersey": "🇯🇪", "Jamaica": "🇯🇲", "Jordan": "🇯🇴", "Japan": "🇯🇵", "Kenya": "🇰🇪", "Kyrgyzstan": "🇰🇬", "Cambodia": "🇰🇭", "Kiribati": "🇰🇮", "Comoros": "🇰🇲", "St. Kitts & Nevis": "🇰🇳", "North Korea": "🇰🇵", "South Korea": "🇰🇷", "Kuwait": "🇰🇼", "Cayman Islands": "🇰🇾", "Kazakhstan": "🇰🇿", "Laos": "🇱🇦", "Lebanon": "🇱🇧", "St. Lucia": "🇱🇨", "Liechtenstein": "🇱🇮", "Sri Lanka": "🇱🇰", "Liberia": "🇱🇷", "Lesotho": "🇱🇸", "Lithuania": "🇱🇹", "Luxembourg": "🇱🇺", "Latvia": "🇱🇻", "Libya": "🇱🇾", "Morocco": "🇲🇦", "Monaco": "🇲🇨", "Moldova": "🇲🇩", "Montenegro": "🇲🇪", "St. Martin": "🇲🇫", "Madagascar": "🇲🇬", "Marshall Islands": "🇲🇭", "North Macedonia": "🇲🇰", "Mali": "🇲🇱", "Myanmar (Burma)": "🇲🇲", "Mongolia": "🇲🇳", "Macau Sar China": "🇲🇴", "Northern Mariana Islands": "🇲🇵", "Martinique": "🇲🇶", "Mauritania": "🇲🇷", "Montserrat": "🇲🇸", "Malta": "🇲🇹", "Mauritius": "🇲🇺", "Maldives": "🇲🇻", "Malawi": "🇲🇼", "Mexico": "🇲🇽", "Malaysia": "🇲🇾", "Mozambique": "🇲🇿", "Namibia": "🇳🇦", "New Caledonia": "🇳🇨", "Niger": "🇳🇪", "Norfolk Island": "🇳🇫", "Nigeria": "🇳🇬", "Nicaragua": "🇳🇮", "Netherlands": "🇳🇱", "Norway": "🇳🇴", "Nepal": "🇳🇵", "Nauru": "🇳🇷", "Niue": "🇳🇺", "New Zealand": "🇳🇿", "Oman": "🇴🇲", "Panama": "🇵🇦", "Peru": "🇵🇪", "French Polynesia": "🇵🇫", "Papua New Guinea": "🇵🇬", "Philippines": "🇵🇭", "Pakistan": "🇵🇰", "Poland": "🇵🇱", "St. Pierre & Miquelon": "🇵🇲", "Pitcairn Islands": "🇵🇳", "Puerto Rico": "🇵🇷", "Palestinian Territories": "🇵🇸", "Portugal": "🇵🇹", "Palau": "🇵🇼", "Paraguay": "🇵🇾", "Qatar": "🇶🇦", "Réunion": "🇷🇪", "Romania": "🇷🇴", "Serbia": "🇷🇸", "Russia": "🇷🇺", "Rwanda": "🇷🇼", "Saudi Arabia": "🇸🇦", "Solomon Islands": "🇸🇧", "Seychelles": "🇸🇨", "Sudan": "🇸🇩", "Sweden": "🇸🇪", "Singapore": "🇸🇬", "St. Helena": "🇸🇭", "Slovenia": "🇸🇮", "Svalbard & Jan Mayen": "🇸🇯", "Slovakia": "🇸🇰", "Sierra Leone": "🇸🇱", "San Marino": "🇸🇲", "Senegal": "🇸🇳", "Somalia": "🇸🇴", "Suriname": "🇸🇷", "South Sudan": "🇸🇸", "São Tomé & Príncipe": "🇸🇹", "El Salvador": "🇸🇻", "Sint Maarten": "🇸🇽", "Syria": "🇸🇾", "Swaziland": "🇸🇿", "Tristan Da Cunha": "🇹🇦", "Turks & Caicos Islands": "🇹🇨", "Chad": "🇹🇩", "French Southern Territories": "🇹🇫", "Togo": "🇹🇬", "Thailand": "🇹🇭", "Tajikistan": "🇹🇯", "Tokelau": "🇹🇰", "Timor-Leste": "🇹🇱", "Turkmenistan": "🇹🇲", "Tunisia": "🇹🇳", "Tonga": "🇹🇴", "Turkey": "🇹🇷", "Trinidad & Tobago": "🇹🇹", "Tuvalu": "🇹🇻", "Taiwan": "🇨🇳", "Tanzania": "🇹🇿", "Ukraine": "🇺🇦", "Uganda": "🇺🇬", "U.S. Outlying Islands": "🇺🇲", "United Nations": "🇺🇳", "United States": "🇺🇸", "USA": "🇺🇸", "Uruguay": "🇺🇾", "Uzbekistan": "🇺🇿", "Vatican City": "🇻🇦", "St. Vincent & Grenadines": "🇻🇨", "Venezuela": "🇻🇪", "British Virgin Islands": "🇻🇬", "U.S. Virgin Islands": "🇻🇮", "Vietnam": "🇻🇳", "Vanuatu": "🇻🇺", "Wallis & Futuna": "🇼🇫", "Samoa": "🇼🇸", "Kosovo": "🇽🇰", "Yemen": "🇾🇪", "Mayotte": "🇾🇹", "South Africa": "🇿🇦", "Zambia": "🇿🇲", "Zimbabwe": "🇿🇼", "England": "🏴󠁧󠁢󠁥󠁮󠁧󠁿", "Scotland": "🏴󠁧󠁢󠁳󠁣󠁴󠁿", "Wales": "🏴󠁧󠁢󠁷󠁬󠁳󠁿", }; return emojiMap[name] ? emojiMap[name] : emojiMap["Chequered"] } + +function Tool() { + _node = (() => { + if (typeof require == "function") { + const request = require('request') + return ({ request }) + } else { + return (null) + } + })() + _isSurge = typeof $httpClient != "undefined" + _isQuanX = typeof $task != "undefined" + this.isSurge = _isSurge + this.isQuanX = _isQuanX + this.isResponse = typeof $response != "undefined" + this.notify = (title, subtitle, message) => { + if (_isQuanX) $notify(title, subtitle, message) + if (_isSurge) $notification.post(title, subtitle, message) + if (_node) console.log(JSON.stringify({ title, subtitle, message })); + } + this.write = (value, key) => { + if (_isQuanX) return $prefs.setValueForKey(value, key) + if (_isSurge) return $persistentStore.write(value, key) + } + this.read = (key) => { + if (_isQuanX) return $prefs.valueForKey(key) + if (_isSurge) return $persistentStore.read(key) + } + this.get = (options, callback) => { + if (_isQuanX) { + if (typeof options == "string") options = { url: options } + options["method"] = "GET" + $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) + } + if (_isSurge) $httpClient.get(options, (error, response, body) => { callback(error, _status(response), body) }) + if (_node) _node.request(options, (error, response, body) => { callback(error, _status(response), body) }) + } + this.post = (options, callback) => { + if (_isQuanX) { + if (typeof options == "string") options = { url: options } + options["method"] = "POST" + $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) + } + if (_isSurge) $httpClient.post(options, (error, response, body) => { callback(error, _status(response), body) }) + if (_node) _node.request.post(options, (error, response, body) => { callback(error, _status(response), body) }) + } + _status = (response) => { + if (response) { + if (response.status) { + response["statusCode"] = response.status + } else if (response.statusCode) { + response["status"] = response.statusCode + } + } + return response + } +} diff --git a/IPA-Installer/IPA-Installer-JSBox.js b/IPA-Installer/IPA-Installer-JSBox.js new file mode 100644 index 0000000000..1284aaac21 --- /dev/null +++ b/IPA-Installer/IPA-Installer-JSBox.js @@ -0,0 +1,144 @@ +/* + * IPA-installer JSBox script. This script is not available stand alone, checkout the demo from TG channel @NobyDa + * + * Modified from https://github.com/axelburks/JSBox/blob/master/IPA%20Installer.js by @NobyDa + */ + +var port_number = 8070 +var plist_url = `itms-services://?action=download-manifest&url=https://nobyda.app/install%3Fclient%3Djsbox%26url%3Dhttp%253A%252F%252F127.0.0.1%253A${port_number}%252Fdownload%253Fpath%253D%25252Fapp.ipa` + +$app.strings = { + "en": { + "starterror": "Not support running in this way", + "ftypeerror": " is not ipa file", + "installtitle": "Installing...", + "installmsg": "\n\nYou can check on Homescreen.\nPlease tap \"Done\" button after finished", + "inerrtitle": "IPA file import error", + "inerrmsg": "Please rerun the script" + }, + "zh-Hans": { + "starterror": "不支持此方式运行!", + "ftypeerror": " 非 ipa 文件!", + "installtitle": "正在安装…", + "installmsg": "\n\n可前往桌面查看安装进度\n完成后请点击\"Done\"按钮", + "inerrtitle": "IPA文件导入失败", + "inerrmsg": "请重新运行此脚本" + } +} + +// 从应用内启动 +if ($app.env == $env.app) { + $drive.open({ + handler: function(data) { + fileCheck(data) + } + }) +} +// 从 Action Entension 启动 +else if ($app.env == $env.action) { + fileCheck($context.data) +} + +else { + $ui.error($l10n("starterror")) + delayClose(2) +} + + +function startServer(port) { + $http.startServer({ + port: port, + path: "", + handler: function(result) { + console.info(result.url) + } + }) +} + +function fileCheck(data) { + if (data && data.fileName) { + var fileName = data.fileName; + if (fileName.indexOf(".ipa") == -1) { + $ui.error(fileName + $l10n("ftypeerror")) + delayClose(2) + } else { + install(fileName, data); + } + } +} + +function install(fileName, file) { + var result = $file.write({ + data: file, + path: "app.ipa" + }) + if (result) { + startServer(port_number) + $location.startUpdates({ + handler: function(resp) { + console.info(resp.lat + " " + resp.lng + " " + resp.alt) + } + }) + var preResult = $app.openURL(plist_url); + if (preResult) { + $ui.alert({ + title: $l10n("installtitle"), + message: "\n" + fileName + $l10n("installmsg"), + actions: [{ + title: "Cancel", + style: "Cancel", + handler: function() { + $http.stopServer() + $file.delete("app.ipa") + delayClose(0.2) + } + }, + { + title: "Done", + handler: function() { + $http.stopServer() + $file.delete("app.ipa") + delayClose(0.2) + } + }] + }) + } else { + $ui.alert({ + title: "Open itms-services scheme failed", + message: "Please rerun the script or restart device", + actions: [ + { + title: "OK", + handler: function() { + delayClose(0.2) + } + }] + }) + } + } else { + $ui.alert({ + title: $l10n("inerrtitle"), + message: $l10n("inerrmsg"), + actions: [{ + title: "OK", + style: "Cancel", + handler: function() { + delayClose(0.2) + } + }] + }) + } +} + +function delayClose(time) { + $location.stopUpdates() + $thread.main({ + delay: time, + handler: function() { + if ($app.env == $env.action || $app.env == $env.safari) { + $context.close() + } + $app.close() + } + }) +} diff --git a/IPA-Installer/IPA-Installer-Pythonista.py b/IPA-Installer/IPA-Installer-Pythonista.py new file mode 100644 index 0000000000..a929058fe7 --- /dev/null +++ b/IPA-Installer/IPA-Installer-Pythonista.py @@ -0,0 +1,74 @@ +# IPA-installer pythonista script. This script is not available stand alone, checkout the demo from TG channel @NobyDa +# +# Modified from https://github.com/axelburks/Pythonista/blob/master/IPA%20Installer.py by @NobyDa + +import os, appex, console, shutil, http.server, webbrowser, time +from os import path +from threading import Thread + +port_number = 8090 +plist_url = f'itms-services://?action=download-manifest&url=https://nobyda.app/install%3Fclient%3Dpythonista%26url%3Dhttp%253A%252F%252F127.0.0.1%253A{port_number}%252Fipa%252Fapp.ipa' +save_dir = path.expanduser('./ipa') +if not path.exists(save_dir): + os.makedirs(save_dir) + +httpd = None +def startServer(port): + Handler = http.server.SimpleHTTPRequestHandler + + global httpd + httpd = http.server.HTTPServer(("", port), Handler) + + print("Start server at port", port) + httpd.serve_forever() + +def start(port): + thread = Thread(target=startServer, args=[port]) + thread.start() + + startTime = int(time.time()) + while not httpd: + if int(time.time()) > startTime + 60: + print("Time out") + break + return httpd + +def stop(): + if httpd: + httpd.shutdown() + +def main(): + if appex.is_running_extension(): + get_path = appex.get_file_path() + file_name = path.basename(get_path) + file_ext = path.splitext(file_name)[-1] + if file_ext == '.ipa': + dstpath = path.join(save_dir, 'app.ipa') + try: + shutil.copy(get_path, dstpath) + + except Exception as eer: + print(eer) + console.hud_alert('导入失败!','error',1) + start(port_number) + if httpd: + webbrowser.open(plist_url) + try: + finish = console.alert(file_name, '\n正在安装...请返回桌面查看进度...\n\n安装完成后请返回点击已完成','已完成', hide_cancel_button=False) + if finish == 1: + stop() + shutil.rmtree('./ipa') + print("Server stopped") + except: + stop() + shutil.rmtree('./ipa') + print("Cancelled") + appex.finish() + else: + console.hud_alert('非 ipa 文件无法导入安装', 'error', 2) + appex.finish() + else: + console.hud_alert('请在分享扩展中打开本脚本','error',2) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/IPA-Installer/IPA-Installer.js b/IPA-Installer/IPA-Installer.js new file mode 100644 index 0000000000..0592bed685 --- /dev/null +++ b/IPA-Installer/IPA-Installer.js @@ -0,0 +1,148 @@ +/* + * iOS IPA应用辅助安装脚本. + * + * 兼容: QuantumultX、Surge5,Loon、Shadowrocket、Stash + * 作者: @NobyDa + * + * 快捷指令 + Shu配合安装: + * 导入IPA文件至Shu -> Shu长按IPA文件 -> 导出文件 -> WiFi传输 -> 本机 -> 系统共享 -> 分享至IPA-Installer快捷指令 + * + * 快捷指令 + JSBox/Pythonista配合安装: + * IPA文件长按分享至IPA-Installer快捷指令(iOS14跳过),完成后再分享至Jsbox/pythonista分享扩展. + * + * + * QuanX重写: https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/IPA-Installer.snippet + * + * Surge模块: https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/IPA_install.sgmodule + * + * loon插件: https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_IPA_Installer.plugin + * + * Stash覆写: https://raw.githubusercontent.com/NobyDa/Script/master/Stash/IPA-Installer.stoverride + * + * 快捷指令(iOS15+): https://www.icloud.com/shortcuts/4a121aa54cae4619a952baa29e044e30 + * + * 快捷指令(iOS14): https://www.icloud.com/shortcuts/179dfcd7505e44f89207086d2b1a32ea + * + * JSBox脚本: https://xteko.com/redir?url=https%3A%2F%2Fraw.githubusercontent.com%2FNobyDa%2FScript%2Fmaster%2FIPA-Installer%2FIPA-Installer-JSBox.js&name=IPA%20Installer%20%28NobyDa%29 + * + * Pythonista脚本: https://github.com/NobyDa/Script/blob/master/IPA-Installer/IPA-Installer-Pythonista.py + */ + +const $ = new compatible_tool(); + +(async function () { + const args = urlArgs($request.url); + const plist = ` + + + + items + + + assets + + + kind + software-package + url + https://nobyda.app/download?url=${encodeURIComponent(args.url)} + + + metadata + + bundle-identifier + ${args.bundleId || $.read("nobyda_ipa_bundle_id") || "*"} + bundle-version + 1.0 + kind + software + title + IPA + + + + +`; + if ($request.url.includes("/install?")) { + if (args.bundleId) { + $.write(args.bundleId, "nobyda_ipa_bundle_id"); + }; + $.resp = { response: { status: 200, body: args.client && plist || "{}" } }; + } else { + if ($request.method == "GET") { + const size = await ipaSize(args.url); + $.notify(`IPA Installer`, ``, size && `Installing IPA, Size: ${size} MB` || `HTTP local server read failed!`); + } + $.resp = { response: { status: 307, headers: { Location: args.url }, body: "{}" } }; + } +})() + .catch((e) => $.notify(`IPA Installer`, ``, `ERROR: ${e.message || e}\nPATH: ${e.stack}`)) + .finally(() => $.done($.resp)) + + +function ipaSize(url) { + return new Promise((r, e) => { + $.http({ method: "head", url: url, policy: "DIRECT", }, (e, h, d) => { + r(h && h.status == 200 && `${((h.headers["Content-Length"] || 0) / 1000 / 1000).toFixed(2)}`) + }); + setTimeout(() => r(), 1000) + }); +} + +function urlArgs(str) { + return Object.fromEntries( + (str.startsWith("http") && str.split("?")[1] || str).split("&") + .map((item) => item.split("=")) + .map(([k, v]) => [k, decodeURIComponent(v)]) + ); +} + +function compatible_tool() { + const isSurge = typeof $httpClient != "undefined"; + const isQuanX = typeof $task != "undefined"; + const isStash = typeof $environment == "object" && $environment["stash-version"]; + const adapterStatus = (response) => { + if (response && response.statusCode) { + response.status = response.statusCode; + } + return response + }; + this.read = (key) => { + if (isQuanX) return $prefs.valueForKey(key); + if (isSurge) return $persistentStore.read(key); + }; + this.write = (value, key) => { + if (isQuanX) return $prefs.setValueForKey(value, key); + if (isSurge) return $persistentStore.write(value, key); + }; + this.notify = (title, subtitle, message) => { + if (isQuanX) $notify(title, subtitle, message); + if (isSurge) $notification.post(title, subtitle, message); + }; + this.http = (options, callback) => { + if (options.policy) { + options.node = options.policy; + options.opts = { policy: options.policy }; + if (isStash) options.headers = { + ...options.headers, + ...{ "X-Stash-Selected-Proxy": encodeURIComponent(options.policy) } + }; + } + if (isQuanX) { + $task.fetch(options).then(response => { + callback(null, adapterStatus(response), response.body) + }, reason => callback(reason.error, null, null)) + } + if (isSurge) { + $httpClient[options.method](options, (error, response, body) => { + callback(error, adapterStatus(response), body) + }) + } + }; + this.done = (value = {}) => { + if (value.response && isQuanX) { + value.response.status = `HTTP/1.1 ${value.response.status}`; + } + $done((value.response && isQuanX) ? value.response : value) + } +}; \ No newline at end of file diff --git a/KuaiKan-DailyBonus/KKMH.js b/KuaiKan-DailyBonus/KKMH.js index 8b60c637a7..c7a94517c6 100644 --- a/KuaiKan-DailyBonus/KKMH.js +++ b/KuaiKan-DailyBonus/KKMH.js @@ -1,7 +1,7 @@ /* 快看漫画签到脚本 -更新时间: 2021.9.22 +更新时间: 2022.06.18 脚本兼容: QuantumultX, Surge4, Loon, Node.js 电报频道: @NobyDa 问题反馈: @NobyDa_bot @@ -174,13 +174,14 @@ function GiftPack(type) { function GetCookie() { const RA = $.getdata("@KKMH.COOKIE") const TM = $.getdata("@KKMH.TIME") - if (JSON.stringify($request.headers).match(/session=/)) { - if (RA != $request.headers['Cookie']) { - if ($.setdata($request.headers['Cookie'], "@KKMH.COOKIE")) { + const CK = $request.headers['Cookie'] || $request.headers['cookie']; + if (JSON.stringify($request.headers).match(/session=/) && CK) { + if (RA != CK) { + if ($.setdata(CK, "@KKMH.COOKIE")) { $.setdata(JSON.stringify(Date.now()), "@KKMH.TIME") if (!TM || TM && (Date.now() - TM) / 1000 >= 21600) { $.msg(`${RA?`更新`:`首次写入`}${$.name}Cookie成功 🎉`, "", "", imgUrl) - } else if (RA.match(/uid=\d+/)[0] == $request.headers['Cookie'].match(/uid=\d+/)[0]) { + } else if (RA.match(/uid=\d+/)[0] == CK.match(/uid=\d+/)[0]) { $.log(`\n更新${$.name}Cookie成功! 🎉\n检测到频繁通知, 已转为输出日志`) } else { $.msg(`更新${$.name}Cookie成功 🎉`, "", "", imgUrl) diff --git a/Loon/Loon_Bahamut_ADS.plugin b/Loon/Loon_Bahamut_ADS.plugin new file mode 100644 index 0000000000..ca1888d4eb --- /dev/null +++ b/Loon/Loon_Bahamut_ADS.plugin @@ -0,0 +1,11 @@ +#!name= 巴哈姆特动画疯 +#!desc= 该Loon插件用以屏蔽动画疯播放广告 (由于强制验证观看广告时间,故以黑屏25秒的方式屏蔽) +#!author= NobyDa +#!homepage= https://github.com/NobyDa/Script/tree/master +#!icon= https://raw.githubusercontent.com/NobyDa/mini/master/Color/bahamutGame.png + +[Script] +http-response ^https:\/\/api\.gamer\.com\.tw\/mobile_app\/anime\/v\d/(token|m3u8).php\? requires-body=1,timeout=40,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bahamut/BahamutAnimeAds.js, tag=屏蔽动画疯广告 + +[MITM] +hostname = api.gamer.com.tw \ No newline at end of file diff --git a/Loon/Loon_Daily_bonus.plugin b/Loon/Loon_Daily_bonus.plugin new file mode 100644 index 0000000000..fb8a2f2a76 --- /dev/null +++ b/Loon/Loon_Daily_bonus.plugin @@ -0,0 +1,38 @@ +#!name= 🐻 NobyDa签到脚本 +#!desc= 包括哔哩漫画、贴吧、快看、爱奇艺,携程旅行、巴哈姆特。部分脚本获取Cookie方法请看脚本注释。注意,该Loon链接目前仅适用于"订阅脚本",非"插件"。添加脚本订阅后请按需启用脚本。 +#!author= NobyDa +#!homepage= https://github.com/NobyDa/Script/tree/master +#!icon= https://raw.githubusercontent.com/github/explore/80688e429a7d4ef2fca1e82350fe8e3517d3494d/topics/javascript/javascript.png + + +[Script] +cron "30 8 * * *" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Ctrip-DailyBonus/Ctrip.js, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/ctrip.png, timeout=300, enabled=false, tag=携程旅行 [签到] + +http-response ^https:\/\/m\.ctrip\.com\/restapi\/soa2\/\d+\/[a-zA-Z]+Login(?:$|\?) script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Ctrip-DailyBonus/Ctrip.js, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/ctrip.png, requires-body=true, enabled=false, tag=携程旅行 [Cookie] + + +cron "10 9 * * *" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/iQIYI.png, timeout=300, enabled=false, tag=爱奇艺 [会员签到] + +http-request ^https:\/\/passport\.iqiyi\.com\/apis\/user\/ script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/iQIYI.png, enabled=false, tag=爱奇艺 [Cookie] + + +cron "0 9 * * *" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/manga.png, timeout=300, enabled=false, tag=哔哩漫画 [签到] + +http-request ^https:\/\/app\.bilibili\.com\/x\/v2\/account\/myinfo script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/manga.png, enabled=false, tag=哔哩漫画 [Cookie] + + +cron "40 8 * * *" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/tieba.png, timeout=300, enabled=false, tag=百度贴吧 [签到] + +http-request ^https?:\/\/(c\.tieba|tiebac)\.baidu\.com\/c\/s\/login script-path=https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/tieba.png, enabled=false, tag=百度贴吧 [Cookie] + + +cron "10 9 * * *" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/KuaiKan.png, timeout=300, enabled=false, tag=快看漫画 [签到] + +http-request ^https?:\/\/api\.kkmh\.com\/v\d\/passport\/user script-path=https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/KuaiKan.png, enabled=false, tag=快看漫画 [Cookie] + + +cron "20 8 * * *" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bahamut/BahamutDailyBonus.js, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/bahamutGame.png, timeout=300, enabled=false, tag=巴哈姆特 [签到] + + +[MITM] +hostname = passport.iqiyi.com, app.bilibili.com, c.tieba.baidu.com, tiebac.baidu.com, api.kkmh.com, m.ctrip.com \ No newline at end of file diff --git a/Loon/Loon_GetCookie.conf b/Loon/Loon_GetCookie.conf deleted file mode 100644 index d8cbb77abe..0000000000 --- a/Loon/Loon_GetCookie.conf +++ /dev/null @@ -1,18 +0,0 @@ -# 该订阅仅适用于Loon, 用于解决任务脚本的Cookie获取, 具体获取方法请看相关脚本内注释. -# 您可在使用后手动将其禁用, 以避免无意义的MITM. -# URL : https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_GetCookie.conf - -http-request ^https:\/\/(api\.m|me-api|ms\.jr)\.jd\.com\/(client\.action\?functionId=signBean|user_new\/info\/GetJDUserInfoUnion\?|gw\/generic\/hy\/h5\/m\/appSign\?) script-path=https://raw.githubusercontent.com/NobyDa/Script/master/JD-DailyBonus/JD_DailyBonus.js, requires-body=1, tag=获取京东Cookie - -http-request ^https:\/\/passport\.iqiyi\.com\/apis\/user\/info\.action script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js, tag=爱奇艺Cookie - -http-request ^https:\/\/www\.52pojie\.cn\/home\.php\? script-path=https://raw.githubusercontent.com/NobyDa/Script/master/52pojie-DailyBonus/52pojie.js, tag=吾爱破解Cookie - -http-request ^https:\/\/passport\.biligame\.com\/api\/login\/sso.+?version%22%3A%22(3|4|5) script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js, tag=哔哩漫画Cookie - -http-request ^https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login script-path=https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js, tag=百度贴吧Cookie - -http-request ^https?:\/\/api\.kkmh\.com\/v\d\/passport\/user script-path=https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js, tag=快看漫画Cookie - -[MITM] -hostname = passport.iqiyi.com, www.52pojie.cn, api.m.jd.com, ms.jr.jd.com, me-api.jd.com, passport.biligame.com, c.tieba.baidu.com, api.kkmh.com \ No newline at end of file diff --git a/Loon/Loon_GetCookie.plugin b/Loon/Loon_GetCookie.plugin new file mode 100644 index 0000000000..078e52b0ee --- /dev/null +++ b/Loon/Loon_GetCookie.plugin @@ -0,0 +1,19 @@ +#!name= NobyDa签到脚本Cookie获取 +#!desc= 包括哔哩漫画、贴吧、快看、爱奇艺,携程旅行。获取方法请看脚本注释;建议使用后手动将该插件禁用, 以避免无意义的MITM。 +#!author= NobyDa +#!homepage= https://github.com/NobyDa/Script/tree/master +#!icon= https://raw.githubusercontent.com/github/explore/80688e429a7d4ef2fca1e82350fe8e3517d3494d/topics/javascript/javascript.png + +[Script] +http-request ^https:\/\/passport\.iqiyi\.com\/apis\/user\/ script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js, tag=爱奇艺Cookie + +http-request ^https:\/\/app\.bilibili\.com\/x\/v2\/account\/myinfo script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js, tag=哔哩漫画Cookie + +http-request ^https?:\/\/(c\.tieba|tiebac)\.baidu\.com\/c\/s\/login script-path=https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js, tag=百度贴吧Cookie + +http-request ^https?:\/\/api\.kkmh\.com\/v\d\/passport\/user script-path=https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js, tag=快看漫画Cookie + +http-response ^https:\/\/m\.ctrip\.com\/restapi\/soa2\/\d+\/[a-zA-Z]+Login(?:$|\?) script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Ctrip-DailyBonus/Ctrip.js, requires-body=true, tag=携程旅行Cookie + +[MITM] +hostname = passport.iqiyi.com, app.bilibili.com, c.tieba.baidu.com, tiebac.baidu.com, api.kkmh.com, m.ctrip.com \ No newline at end of file diff --git a/Loon/Loon_GetTask.conf b/Loon/Loon_GetTask.conf deleted file mode 100644 index 33b9548895..0000000000 --- a/Loon/Loon_GetTask.conf +++ /dev/null @@ -1,17 +0,0 @@ -# 该签到脚本订阅仅适用于Loon, 您需要获取Cookie后方可使用. -# URL : https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_GetTask.conf - -# 京东签到, 执行时间: 0:05 -cron "5 0 * * *" ,timeout=30, script-path=https://raw.githubusercontent.com/NobyDa/Script/master/JD-DailyBonus/JD_DailyBonus.js,tag=京东签到 - -# 爱奇艺, 执行时间: 08:00 -cron "0 8 * * *" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js,tag=爱奇艺 - -# 哔哩哔哩漫画, 执行时间: 08:02 -cron "2 8 * * *" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js,tag=哔哩哔哩漫画 - -# 百度贴吧, 执行时间: 08:03-08:05 (3次) -cron "3,4,5 8 * * *" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js,tag=百度贴吧(客户端) - -# 快看漫画, 执行时间: 08:06 -cron "6 8 * * *" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js, tag=快看漫画 \ No newline at end of file diff --git a/Loon/Loon_Google_CAPTCHA.plugin b/Loon/Loon_Google_CAPTCHA.plugin new file mode 100644 index 0000000000..7baec65ae4 --- /dev/null +++ b/Loon/Loon_Google_CAPTCHA.plugin @@ -0,0 +1,14 @@ +#!name = Google人机验证 +#!desc = Google搜索内容时并发使用多个策略/策略组,以避免可能出现的人机验证。注意:需要在插件参数填写策略/策略组名的正则表达式。 +#!author = NobyDa +#!input = GOOGLE_CAPTCHA_REGEX +#!homepage = https://github.com/NobyDa/Script/tree/master +#!icon = https://cdn.jsdelivr.net/gh/NobyDa/mini@master/Color/Google.png +#!date = 2024-05-19 12:00:00 + + +[Script] +http-response ^https:\/\/www\.google\.com(?:\.[a-z]+|)\/(?:search\?(?:|.+?&)q=|$) requires-body=1,timeout=30,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Google_CAPTCHA.js,tag=Google人机验证 + +[MITM] +hostname = www.google.com* \ No newline at end of file diff --git a/Loon/Loon_IPA_Installer.plugin b/Loon/Loon_IPA_Installer.plugin new file mode 100644 index 0000000000..47c5531465 --- /dev/null +++ b/Loon/Loon_IPA_Installer.plugin @@ -0,0 +1,12 @@ +#!name=IPA应用辅助安装器 +#!desc=该模块可在iOS端辅助安装商店版或已签名IPA(需使用快捷指令 + Shu/Jsbox/pythonista), 查看脚本注释以了解具体方法; 安装演示可查看TG频道 @NobyDa +#!author=NobyDa +#!homepage=https://github.com/NobyDa/Script/tree/master +#!icon=https://cdn.jsdelivr.net/gh/NobyDa/mini@master/Color/Apple.png + + +[Script] +http-request ^https:\/\/nobyda.app/(install|download) requires-body=true, script-path=https://raw.githubusercontent.com/NobyDa/Script/master/IPA-Installer/IPA-Installer.js, timeout=10, tag=IPA-Installer + +[MITM] +hostname = nobyda.app \ No newline at end of file diff --git a/Loon/Loon_TF_Account.plugin b/Loon/Loon_TF_Account.plugin new file mode 100644 index 0000000000..7f1aca81f0 --- /dev/null +++ b/Loon/Loon_TF_Account.plugin @@ -0,0 +1,14 @@ +#!name=TestFlight账户管理 +#!desc=自动存储/合并多个TestFlight账户列表, 并可分享/导出TestFlight APP. +#!author= NobyDa +#!homepage= https://github.com/NobyDa/Script/tree/master +#!icon= https://cdn.jsdelivr.net/gh/NobyDa/mini@master/Color/testflight.png + +[General] +skip-proxy = iosapps.itunes.apple.com + +[Script] +http-request ^https:\/\/testflight\.apple\.com\/v\d\/(app|account|invite)s\/ requires-body=1,timeout=120,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/TestFlight/TestFlightAccount.js,tag=TestFlight账户管理 + +[MITM] +hostname = testflight.apple.com \ No newline at end of file diff --git a/Loon/Loon_TF_Download.conf b/Loon/Loon_TF_Download.conf deleted file mode 100644 index a89e06614a..0000000000 --- a/Loon/Loon_TF_Download.conf +++ /dev/null @@ -1,6 +0,0 @@ -# 该脚本订阅仅适用于Loon, 用于更新TestFlight App时, 提示"APP不可用"问题. 解除区域限制. - -http-request ^https?:\/\/testflight\.apple\.com\/v\d\/accounts\/.+?\/install$ requires-body=1,max-size=0,script-path=https://gist.githubusercontent.com/NobyDa/9be418b93afc5e9c8a8f4d28ae403cf2/raw/TF_Download.js, tag=TF区域限制解除 - -[MITM] -hostname = testflight.apple.com \ No newline at end of file diff --git a/Loon/Loon_TF_Download.plugin b/Loon/Loon_TF_Download.plugin new file mode 100644 index 0000000000..628dde3490 --- /dev/null +++ b/Loon/Loon_TF_Download.plugin @@ -0,0 +1,14 @@ +#!name= TestFlight区域限制解除 +#!desc= 该Loon插件用以解决更新TestFlight App时, 提示"APP不可用"问题. +#!author= NobyDa +#!homepage= https://github.com/NobyDa/Script/tree/master +#!icon= https://cdn.jsdelivr.net/gh/NobyDa/mini@master/Color/testflight.png + +[General] +skip-proxy = iosapps.itunes.apple.com + +[Script] +http-request ^https?:\/\/testflight\.apple\.com\/v\d\/accounts\/.+?\/install$ requires-body=1,max-size=0,script-path=https://gist.githubusercontent.com/NobyDa/9be418b93afc5e9c8a8f4d28ae403cf2/raw/TF_Download.js, tag=TF区域限制解除 + +[MITM] +hostname = testflight.apple.com diff --git a/NobyDa_BoxJs.json b/NobyDa_BoxJs.json index 8eccecae21..0a5d5e8aa9 100644 --- a/NobyDa_BoxJs.json +++ b/NobyDa_BoxJs.json @@ -1,464 +1,738 @@ { - "id": "NobyDa.app.sub", - "name": "NobyDa 脚本订阅", - "description": "该订阅兼容BoxJs以及QX Gallery", - "author": "@NobyDa", - "icon": "https://avatars2.githubusercontent.com/u/53217160", - "repo": "https://github.com/NobyDa/Script/tree/master", - "apps": [{ - "id": "多合一签到", - "name": "京东", - "keys": ["CookiesJD"], - "descs_html": [ - "

获取Cookie以及脚本配置请查看脚本注释

", - "

如需修改Cookie列表请严格按照JSON格式修改

", - "

建议通过脚本获取Cookie

", - "
", - "

签到相关教程

", - "

" - ], - "settings": [{ - "id": "JD_DailyBonusLog", - "name": "详细响应日志", - "val": false, - "type": "boolean", - "desc": "打印原始签到结果, 用于调试脚本, 一般用户建议关闭." - }, { - "id": "JD_Crash_disable", - "name": "崩溃自动禁用", - "val": true, - "type": "boolean", - "desc": "脚本运行崩溃时(如VPN断连), 下次运行时将自动禁用相关崩溃接口(仅部分接口启用), 注: 崩溃时可能会误禁用正常接口." - }, { - "id": "JD_Retry_disable", - "name": "签到接口增强", - "val": true, - "type": "boolean", - "desc": "用于部分接口提示\"不含活动数据\"问题, 开启后会进行二次查询, 注: 可能会导致崩溃(小概率)." - }, { - "id": "JD_Follow_disable", - "name": "自动关注店铺", - "val": true, - "type": "boolean", - "desc": "部分接口签到过程可能需要关注店铺, 如介意可选择关闭." - }, { - "id": "JD_DailyBonusDisables", - "name": "签到接口禁用", - "val": "", - "type": "checkboxes", - "desc": "", - "items": [{ - "key": "JDBean", - "label": "京东京豆" - }, { - "key": "JRSteel", - "label": "金融钢镚" - }, { - "key": "JDTurn", - "label": "京东转盘" - }, { - "key": "JDGStore", - "label": "京东超市" - }, { - "key": "JDCard", - "label": "京东卡包" - }, { - "key": "JD3C", - "label": "京东数码" - }, { - "key": "JDSuitcase", - "label": "京东箱包" - }, { - "key": "JDChild", - "label": "京东童装" - }, { - "key": "JDBaby", - "label": "京东母婴" - }, { - "key": "JDCash", - "label": "京东红包" - }, { - "key": "JDFSale", - "label": "京东闪购" - }, { - "key": "JDBook", - "label": "京东图书" - }, { - "key": "JDStory", - "label": "失眠补贴" - }, { - "key": "JDPhone", - "label": "手机小时达" - }, { - "key": "JDSchool", - "label": "京东校园" - }, { - "key": "JDUndies", - "label": "京东内衣" - }, { - "key": "JDShoes", - "label": "京东鞋靴" - }, { - "key": "JDShand", - "label": "京东二手" - }, { - "key": "JDHealth", - "label": "京东健康" - }, { - "key": "JDWomen", - "label": "京东女装" - }, { - "key": "JDSecKill", - "label": "京东秒杀" - }, { - "key": "JTDouble", - "label": "金贴双签" - }, { - "key": "JDVege", - "label": "京东菜场" - }, { - "key": "JDClean", - "label": "京东清洁" - }, { - "key": "JDCare", - "label": "京东个护" - }, { - "key": "JDaccompany", - "label": "京东陪伴" - }, { - "key": "JDCube", - "label": "京东魔方" - }, { - "key": "JDJiaDian", - "label": "京东家电" - }, { - "key": "JDDouble", - "label": "京豆双签" - }, { - "key": "subsidy", - "label": "京东金贴" - }, { - "key": "JDGetCash", - "label": "京东现金" - }, { - "key": "JDShake", - "label": "京东摇一摇" - }, { - "key": "Qbear", - "label": "总京豆查询" - }, { - "key": "TCash", - "label": "总红包查询" - }, { - "key": "TSteel", - "label": "总钢镚查询" - }, { - "key": "TotalSubsidy", - "label": "总金贴查询" - }, { - "key": "TotalMoney", - "label": "总现金查询" - }] - }, { - "id": "JD_DailyBonusTimeOut", - "name": "超时退出 (毫秒)", - "val": "", - "type": "number", - "placeholder": "默认无超时 (点击以展开说明)", - "desc": "按需填写, 用于由网络不稳定引起的脚本中断, 正常或越狱用户建议留空. 如QX日志出现大量\"JS Context timeout\"后脚本中断时, 建议填写6000" - }, { - "id": "JD_DailyBonusDelay", - "name": "接口延迟 (毫秒)", - "val": "", - "type": "number", - "placeholder": "默认并发无延迟 (点击以展开说明)", - "desc": "延迟作用于每个签到接口, 该参数接受随机或指定延迟(例: '2000'则表示延迟2秒; '2000-5000'则表示延迟最小2秒,最大5秒内的随机延迟), 如填入延迟则切换顺序签到(耗时较长); VPN重启或越狱用户建议填写1(顺序执行), Surge用户请注意在SurgeUI界面调整脚本超时." - }, { - "id": "CookiesJD", - "name": "Cookie列表", - "val": "", - "type": "textarea", - "autoGrow": false, - "rows": 9, - "val": "[\n {\n \"cookie\": \"此处填写账号1 Cookie\"\n },\n {\n \"cookie\": \"此处填写账号2 Cookie\",\n \"jrBody\": \"此处填写账号2 钢镚Body\"\n }\n]", - "placeholder": "[ {\"cookie\": \"pt_key=xxx;pt_pin=yyy;\", \"jrBody\": \"reqData=zzz\"} ]", - "desc": "Cookie和钢镚签到Body列表, 如需修改请严格按照JSON格式填写; \"cookie\"为必须, 其他为可选." - }], - "scripts": [{ - "name": "京东签到", - "script": "https://raw.githubusercontent.com/NobyDa/Script/master/JD-DailyBonus/JD_DailyBonus.js" - }, { - "name": "初始化设置", - "script": "https://gist.githubusercontent.com/NobyDa/91cbe57dd50b3588a975af8922507a72/raw/JD_initial.js" - }], - "author": "@NobyDa", - "repo": "https://github.com/NobyDa/Script/tree/master/JD-DailyBonus", - "icons": ["https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/jd.png", "https://raw.githubusercontent.com/NobyDa/mini/master/Color/jd.png"] - }, { - "id": "iQIYI", - "name": "爱奇艺", - "keys": ["CookieQY"], - "descs_html": [ - "

获取Cookie以及脚本配置请查看脚本注释

" - ], - "settings": [{ - "id": "iQIYI_LogDetails", - "name": "响应日志", - "val": false, - "type": "boolean", - "desc": "" - }], - "script": "https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js", - "author": "@NobyDa", - "repo": "https://github.com/NobyDa/Script/blob/master/iQIYI-DailyBonus/iQIYI.js", - "icons": ["https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/iQIYI.png", "https://raw.githubusercontent.com/NobyDa/mini/master/Color/iQIYI.png"] - }, { - "id": "BiliManga", - "name": "哔哩漫画", - "keys": ["CookieBM"], - "descs_html": [ - "

获取Cookie以及脚本配置请查看脚本注释

" - ], - "script": "https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js", - "author": "@NobyDa", - "repo": "https://github.com/NobyDa/Script/blob/master/Bilibili-DailyBonus/Manga.js", - "icons": ["https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/manga.png", "https://raw.githubusercontent.com/NobyDa/mini/master/Color/manga.png"] - }, { - "id": "BiliMangaPoints", - "name": "哔哩漫画抢券", - "descs_html": [ - "

脚本配置请查看脚本注释

" - ], - "keys": ["BM_ProductName", "BM_ProductNum", "BM_ExchangeNum"], - "settings": [{ - "id": "BM_ProductName", - "name": "商品名", - "val": "积分兑换", - "type": "text", - "placeholder": "(点击以展开说明)", - "desc": "要抢购的积分商城商品名" - }, { - "id": "BM_ProductNum", - "name": "兑换数量", - "val": "", - "type": "text", - "placeholder": "(点击以展开说明)", - "desc": "要兑换的数量, 默认为积分可兑换的最大值" - }, { - "id": "BM_ExchangeNum", - "name": "抢购次数", - "val": "", - "type": "text", - "placeholder": "(点击以展开说明)", - "desc": "默认暴力抢购100次" - }], - "script": "https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/ExchangePoints.js", + "id": "NobyDa.app.sub", + "name": "NobyDa 脚本订阅", + "description": "该订阅兼容BoxJs以及QX Gallery", "author": "@NobyDa", - "repo": "https://github.com/NobyDa/Script/blob/master/Bilibili-DailyBonus/ExchangePoints.js", - "icons": ["https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/manga.png", "https://raw.githubusercontent.com/NobyDa/mini/master/Color/manga.png"] - }, { - "id": "BaiduTB", - "name": "百度贴吧", - "keys": ["CookieTB"], - "descs_html": [ - "

获取Cookie以及脚本配置请查看脚本注释

" - ], - "settings": [{ - "id": "BDTB_DailyBonus_Mode", - "name": "签到模式", - "val": "0", - "type": "radios", - "desc": "", - "items": [{ - "key": "0", - "label": "自动切换" - }, { - "key": "1", - "label": "顺序执行" - }, { - "key": "2", - "label": "并发执行" - }] - }, { - "id": "BDTB_DailyBonus_notify", - "name": "通知汇总", - "val": "", - "type": "number", - "placeholder": "默认20 (点击以展开说明)", - "desc": "想签到几个汇总到一个通知里, 这里就填几个(比如我有13个要签到的, 这里填了5, 就会分三次推送通知)" - }], - "script": "https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js", - "author": "@sazs34, @NobyDa", - "repo": "https://github.com/sazs34/TaskConfig/blob/master/task/sign_baidu_tieba_v2.js", - "icons": ["https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/tieba.png", "https://raw.githubusercontent.com/NobyDa/mini/master/Color/tieba.png"] - }, { - "id": "52poje", - "name": "吾爱破解", - "keys": ["CookieWA"], - "descs_html": [ - "

获取Cookie以及脚本配置请查看脚本注释

" + "icon": "https://avatars2.githubusercontent.com/u/53217160", + "repo": "https://github.com/NobyDa/Script/tree/master", + "apps": [ + { + "id": "多合一签到", + "name": "京东", + "keys": [ + "CookiesJD" + ], + "descs_html": [ + "

获取Cookie以及脚本配置请查看脚本注释

", + "

如需修改Cookie列表请严格按照JSON格式修改

", + "

建议通过脚本获取Cookie

", + "
", + "

签到相关教程

", + "

" + ], + "settings": [ + { + "id": "JD_DailyBonusLog", + "name": "详细响应日志", + "val": false, + "type": "boolean", + "desc": "打印原始签到结果, 用于调试脚本, 一般用户建议关闭." + }, + { + "id": "JD_Crash_disable", + "name": "崩溃自动禁用", + "val": true, + "type": "boolean", + "desc": "脚本运行崩溃时(如VPN断连), 下次运行时将自动禁用相关崩溃接口(仅部分接口启用), 注: 崩溃时可能会误禁用正常接口." + }, + { + "id": "JD_Retry_disable", + "name": "签到接口增强", + "val": true, + "type": "boolean", + "desc": "用于部分接口提示\"不含活动数据\"问题, 开启后会进行二次查询, 注: 可能会导致崩溃(小概率)." + }, + { + "id": "JD_Follow_disable", + "name": "自动关注店铺", + "val": true, + "type": "boolean", + "desc": "部分接口签到过程可能需要关注店铺, 如介意可选择关闭." + }, + { + "id": "JD_DailyBonusDisables", + "name": "签到接口禁用", + "val": "", + "type": "checkboxes", + "desc": "", + "items": [ + { + "key": "JDBean", + "label": "京东京豆" + }, + { + "key": "JRSteel", + "label": "金融钢镚" + }, + { + "key": "JDTurn", + "label": "京东转盘" + }, + { + "key": "JDGStore", + "label": "京东超市" + }, + { + "key": "JDCard", + "label": "京东卡包" + }, + { + "key": "JD3C", + "label": "京东数码" + }, + { + "key": "JDSuitcase", + "label": "京东箱包" + }, + { + "key": "JDChild", + "label": "京东童装" + }, + { + "key": "JDBaby", + "label": "京东母婴" + }, + { + "key": "JDCash", + "label": "京东红包" + }, + { + "key": "JDFSale", + "label": "京东闪购" + }, + { + "key": "JDBook", + "label": "京东图书" + }, + { + "key": "JDStory", + "label": "失眠补贴" + }, + { + "key": "JDPhone", + "label": "手机小时达" + }, + { + "key": "JDSchool", + "label": "京东校园" + }, + { + "key": "JDUndies", + "label": "京东内衣" + }, + { + "key": "JDShoes", + "label": "京东鞋靴" + }, + { + "key": "JDShand", + "label": "京东二手" + }, + { + "key": "JDHealth", + "label": "京东健康" + }, + { + "key": "JDWomen", + "label": "京东女装" + }, + { + "key": "JDSecKill", + "label": "京东秒杀" + }, + { + "key": "JTDouble", + "label": "金贴双签" + }, + { + "key": "JDVege", + "label": "京东菜场" + }, + { + "key": "JDClean", + "label": "京东清洁" + }, + { + "key": "JDCare", + "label": "京东个护" + }, + { + "key": "JDaccompany", + "label": "京东陪伴" + }, + { + "key": "JDCube", + "label": "京东魔方" + }, + { + "key": "JDJiaDian", + "label": "京东家电" + }, + { + "key": "JDDouble", + "label": "京豆双签" + }, + { + "key": "subsidy", + "label": "京东金贴" + }, + { + "key": "JDGetCash", + "label": "京东现金" + }, + { + "key": "JDShake", + "label": "京东摇一摇" + }, + { + "key": "Qbear", + "label": "总京豆查询" + }, + { + "key": "TCash", + "label": "总红包查询" + }, + { + "key": "TSteel", + "label": "总钢镚查询" + }, + { + "key": "TotalSubsidy", + "label": "总金贴查询" + }, + { + "key": "TotalMoney", + "label": "总现金查询" + } + ] + }, + { + "id": "JD_DailyBonusTimeOut", + "name": "超时退出 (毫秒)", + "val": "", + "type": "number", + "placeholder": "默认无超时 (点击以展开说明)", + "desc": "按需填写, 用于由网络不稳定引起的脚本中断, 正常或越狱用户建议留空. 如QX日志出现大量\"JS Context timeout\"后脚本中断时, 建议填写6000" + }, + { + "id": "JD_DailyBonusDelay", + "name": "接口延迟 (毫秒)", + "val": "", + "type": "number", + "placeholder": "默认并发无延迟 (点击以展开说明)", + "desc": "延迟作用于每个签到接口, 该参数接受随机或指定延迟(例: '2000'则表示延迟2秒; '2000-5000'则表示延迟最小2秒,最大5秒内的随机延迟), 如填入延迟则切换顺序签到(耗时较长); VPN重启或越狱用户建议填写1(顺序执行), Surge用户请注意在SurgeUI界面调整脚本超时." + }, + { + "id": "CookiesJD", + "name": "Cookie列表", + "type": "textarea", + "autoGrow": false, + "rows": 9, + "val": "[\n {\n \"cookie\": \"此处填写账号1 Cookie\"\n },\n {\n \"cookie\": \"此处填写账号2 Cookie\",\n \"jrBody\": \"此处填写账号2 钢镚Body\"\n }\n]", + "placeholder": "[ {\"cookie\": \"pt_key=xxx;pt_pin=yyy;\", \"jrBody\": \"reqData=zzz\"} ]", + "desc": "Cookie和钢镚签到Body列表, 如需修改请严格按照JSON格式填写; \"cookie\"为必须, 其他为可选." + } + ], + "scripts": [ + { + "name": "京东签到", + "script": "https://raw.githubusercontent.com/NobyDa/Script/master/JD-DailyBonus/JD_DailyBonus.js" + }, + { + "name": "初始化设置", + "script": "https://gist.githubusercontent.com/NobyDa/91cbe57dd50b3588a975af8922507a72/raw/JD_initial.js" + } + ], + "author": "@NobyDa", + "repo": "https://github.com/NobyDa/Script/tree/master/JD-DailyBonus", + "icons": [ + "https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/jd.png", + "https://raw.githubusercontent.com/NobyDa/mini/master/Color/jd.png" + ] + }, + { + "id": "iQIYI", + "name": "爱奇艺", + "keys": [ + "CookieQY" + ], + "descs_html": [ + "

获取Cookie以及脚本配置请查看脚本注释

" + ], + "settings": [ + { + "id": "iQIYI_LogDetails", + "name": "响应日志", + "val": false, + "type": "boolean", + "desc": "" + } + ], + "script": "https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js", + "author": "@NobyDa", + "repo": "https://github.com/NobyDa/Script/blob/master/iQIYI-DailyBonus/iQIYI.js", + "icons": [ + "https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/iQIYI.png", + "https://raw.githubusercontent.com/NobyDa/mini/master/Color/iQIYI.png" + ] + }, + { + "id": "BiliManga", + "name": "哔哩漫画", + "keys": [ + "BILI_COMICS_CHECKIN" + ], + "descs_html": [ + "

获取Cookie以及脚本配置请查看脚本注释

" + ], + "script": "https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js", + "author": "@NobyDa", + "repo": "https://github.com/NobyDa/Script/blob/master/Bilibili-DailyBonus/Manga.js", + "icons": [ + "https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/manga.png", + "https://raw.githubusercontent.com/NobyDa/mini/master/Color/manga.png" + ] + }, + { + "id": "BiliMangaPoints", + "name": "哔哩漫画抢券", + "descs_html": [ + "

脚本配置请查看脚本注释

" + ], + "keys": [ + "BM_ProductName", + "BM_ProductNum", + "BM_ExchangeNum" + ], + "settings": [ + { + "id": "@BILI_COMICS_CHECKIN.ProductName", + "name": "商品名", + "val": "积分兑换", + "type": "text", + "placeholder": "(点击以展开说明)", + "desc": "要抢购的积分商城商品名" + }, + { + "id": "@BILI_COMICS_CHECKIN.ProductNum", + "name": "兑换数量", + "val": "", + "type": "text", + "placeholder": "(点击以展开说明)", + "desc": "要兑换的数量, 默认为积分可兑换的最大值" + }, + { + "id": "@BILI_COMICS_CHECKIN.ExchangeNum", + "name": "抢购次数", + "val": "", + "type": "text", + "placeholder": "(点击以展开说明)", + "desc": "默认暴力抢购100次" + } + ], + "script": "https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/ExchangePoints.js", + "author": "@NobyDa", + "repo": "https://github.com/NobyDa/Script/blob/master/Bilibili-DailyBonus/ExchangePoints.js", + "icons": [ + "https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/manga.png", + "https://raw.githubusercontent.com/NobyDa/mini/master/Color/manga.png" + ] + }, + { + "id": "BaiduTB", + "name": "百度贴吧", + "keys": [ + "CookieTB" + ], + "descs_html": [ + "

获取Cookie以及脚本配置请查看脚本注释

" + ], + "settings": [ + { + "id": "BDTB_DailyBonus_Mode", + "name": "签到模式", + "val": "0", + "type": "radios", + "desc": "", + "items": [ + { + "key": "0", + "label": "自动切换" + }, + { + "key": "1", + "label": "顺序执行" + }, + { + "key": "2", + "label": "并发执行" + } + ] + }, + { + "id": "BDTB_DailyBonus_notify", + "name": "通知汇总", + "val": "", + "type": "number", + "placeholder": "默认20 (点击以展开说明)", + "desc": "想签到几个汇总到一个通知里, 这里就填几个(比如我有13个要签到的, 这里填了5, 就会分三次推送通知)" + } + ], + "script": "https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js", + "author": "@sazs34, @NobyDa", + "repo": "https://github.com/sazs34/TaskConfig/blob/master/task/sign_baidu_tieba_v2.js", + "icons": [ + "https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/tieba.png", + "https://raw.githubusercontent.com/NobyDa/mini/master/Color/tieba.png" + ] + }, + { + "id": "52poje", + "name": "吾爱破解", + "keys": [ + "nobyda_52pojie" + ], + "descs_html": [ + "

获取Cookie以及脚本配置请查看脚本注释

" + ], + "script": "https://raw.githubusercontent.com/NobyDa/Script/master/52pojie-DailyBonus/52pojie.js", + "author": "@NobyDa", + "repo": "https://github.com/NobyDa/Script/blob/master/52pojie-DailyBonus/52pojie.js", + "icons": [ + "https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/52pj.png", + "https://raw.githubusercontent.com/NobyDa/mini/master/Color/52pj.png" + ] + }, + { + "id": "KuaiKan", + "name": "快看漫画", + "keys": [ + "@KKMH.COOKIE", + "@KKMH.TIME", + "@KKMH.UID", + "@KKMH.DATE" + ], + "descs_html": [ + "

获取Cookie以及脚本配置请查看脚本注释

" + ], + "settings": [ + { + "id": "@KKMH.LOG", + "name": "响应日志", + "val": false, + "type": "boolean", + "desc": "打印原始签到结果, 用于调试脚本, 一般用户建议关闭." + } + ], + "script": "https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js", + "author": "@NobyDa", + "repo": "https://github.com/NobyDa/Script/blob/master/KuaiKan-DailyBonus/KKMH.js", + "icons": [ + "https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/KuaiKan.png", + "https://raw.githubusercontent.com/NobyDa/mini/master/Color/KuaiKan.png" + ] + }, + { + "id": "Bahamut", + "name": "巴哈姆特", + "keys": [ + "@ND_BAHA.ID", + "@ND_BAHA.PW", + "@ND_BAHA.TOTP", + "@ND_BAHA.GUILD", + "@ND_BAHA.ANSWER", + "@ND_BAHA.ADS" + ], + "descs_html": [ + "

脚本配置请查看脚本注释

" + ], + "settings": [ + { + "id": "@ND_BAHA.ADS", + "name": "签到广告", + "val": false, + "type": "boolean", + "desc": "开启后将签到双倍巴币奖励, 默认关闭. 请注意, 此功能耗时过长(30秒以上), 如果使用Surge请调整该脚本超时为300秒" + }, + { + "id": "@ND_BAHA.GUILD", + "name": "签到公会", + "val": true, + "type": "boolean", + "desc": "开启后将自动签到公会" + }, + { + "id": "@ND_BAHA.ANSWER", + "name": "动画疯答题", + "val": true, + "type": "boolean", + "desc": "开启后将自动答题" + }, + { + "id": "@ND_BAHA.ID", + "name": "用户名", + "val": "", + "type": "text", + "placeholder": "(点击以展开说明)", + "desc": "输入用户名(账号)" + }, + { + "id": "@ND_BAHA.PW", + "name": "用户密码", + "val": "", + "type": "text", + "placeholder": "", + "desc": "输入用户密码" + }, + { + "id": "@ND_BAHA.TOTP", + "name": "两步验证令牌", + "val": "", + "type": "text", + "placeholder": "(点击以展开说明)", + "desc": "输入网站生成的16位令牌, 如未设置两步验证, 请留空" + } + ], + "script": "https://raw.githubusercontent.com/NobyDa/Script/master/Bahamut/BahamutDailyBonus.js", + "author": "@NobyDa", + "repo": "https://github.com/NobyDa/Script/blob/master/Bahamut/BahamutDailyBonus.js", + "icons": [ + "https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/bahamutGame.png", + "https://raw.githubusercontent.com/NobyDa/mini/master/Color/bahamutGame.png" + ] + }, + { + "id": "BiliRegion", + "name": "哔哩番剧自动地区", + "descs_html": [ + "

脚本配置请查看脚本注释

" + ], + "keys": [ + "BiliArea_Policy", + "BiliArea_CN", + "BiliArea_HK", + "BiliArea_TW", + "BiliArea_DF", + "BiliArea_disabled" + ], + "settings": [ + { + "id": "BiliAreaNotify", + "name": "静默运行", + "val": false, + "type": "boolean", + "desc": "开启后将不再发出切换策略通知" + }, + { + "id": "BiliDoubanRating", + "name": "豆瓣评分", + "val": true, + "type": "boolean", + "desc": "关闭后将不再查询豆瓣评分, 可显著提高相关页面载入速度" + }, + { + "id": "BiliArea_Policy", + "name": "策略组名", + "val": "", + "type": "text", + "placeholder": "(点击以展开说明)", + "desc": "哔哩哔哩分流的策略组名" + }, + { + "id": "BiliArea_CN", + "name": "中国大陆-子策略名", + "val": "DIRECT", + "type": "text", + "placeholder": "(点击以展开说明)", + "desc": "哔哩哔哩分流策略组里的中国大陆子策略名" + }, + { + "id": "BiliArea_HK", + "name": "中国香港-子策略名", + "val": "", + "type": "text", + "placeholder": "(点击以展开说明)", + "desc": "哔哩哔哩分流策略组里的香港子策略名" + }, + { + "id": "BiliArea_TW", + "name": "中国台湾-子策略名", + "val": "", + "type": "text", + "placeholder": "(点击以展开说明)", + "desc": "哔哩哔哩分流策略组里的台湾子策略名" + }, + { + "id": "BiliArea_DF", + "name": "后备-子策略名", + "val": "", + "type": "text", + "placeholder": "(点击以展开说明)", + "desc": "部分番剧可能会被屏蔽, 使用该策略以避免页面加载失败. 建议填写台湾子策略" + }, + { + "id": "BiliArea_disabled", + "name": "WiFi黑名单", + "val": "", + "type": "text", + "placeholder": "(点击以展开说明)", + "desc": "WiFi名称以逗号分隔, 名单内将跳过策略切换" + } + ], + "author": "@NobyDa", + "repo": "https://github.com/NobyDa/Script/blob/master/Surge/JS/Bili_Auto_Regions.js", + "icons": [ + "https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/bilibili.png", + "https://raw.githubusercontent.com/NobyDa/mini/master/Color/bilibili.png" + ] + }, + { + "id": "TestFlightAccount", + "name": "TestFlight账户管理", + "keys": [ + "TESTFLIGHT-ACCOUNT" + ], + "descs_html": [ + "

脚本说明以及配置请查看脚本注释

" + ], + "settings": [ + { + "id": "@TESTFLIGHT-ACCOUNT.Debug", + "name": "开发者模式", + "val": false, + "type": "boolean", + "desc": "用于调试脚本, 一般用户请勿开启." + }, + { + "id": "@TESTFLIGHT-ACCOUNT.EnableCache", + "name": "启用缓存", + "val": true, + "type": "boolean", + "desc": "用于缓存APP列表, 改善列表页面加载过慢,需与\"请求超时\"配合使用。开启缓存并刷新列表后,可适当调小超时" + }, + { + "id": "@TESTFLIGHT-ACCOUNT.Timeout", + "name": "请求超时", + "val": "", + "type": "number", + "placeholder": "30", + "desc": "默认为30, 单位: 秒" + }, + { + "id": "@TESTFLIGHT-ACCOUNT.ForceIOSlist", + "name": "使用iOS应用列表", + "val": false, + "type": "boolean", + "desc": "强制使用iOS应用列表, 用于改善 macOS TestFlight 加载过慢, iOS用户无需开启" + } + ], + "scripts": [ + { + "name": "清除缓存", + "script": "https://gist.githubusercontent.com/NobyDa/d025c53d3922657f921b983ce129fc1d/raw/TestFlightAccountRemoveCache.js" + } + ], + "author": "@NobyDa", + "repo": "https://github.com/NobyDa/Script/blob/master/TestFlight/TestFlightAccount.js", + "icons": [ + "https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/testflight.png", + "https://raw.githubusercontent.com/NobyDa/mini/master/Color/testflight.png" + ] + }, + { + "id": "Ctrip", + "name": "携程旅行", + "keys": [ + "CTRIP_DAILY_BONUS" + ], + "descs_html": [ + "

脚本说明以及配置请查看脚本注释

" + ], + "settings": [ + { + "id": "@CTRIP_DAILY_BONUS.Debug", + "name": "开发者模式", + "val": false, + "type": "boolean", + "desc": "用于调试脚本, 一般用户请勿开启." + } + ], + "script": "https://raw.githubusercontent.com/NobyDa/Script/master/Ctrip-DailyBonus/Ctrip.js", + "author": "@NobyDa", + "repo": "https://github.com/NobyDa/Script/blob/master/Ctrip-DailyBonus/Ctrip.js", + "icons": [ + "https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/ctrip.png", + "https://raw.githubusercontent.com/NobyDa/mini/master/Color/ctrip.png" + ] + }, + { + "id": "GoogleCAPTCHA", + "name": "Google搜索人机验证", + "keys": [ + "GOOGLE_CAPTCHA" + ], + "descs_html": [ + "

脚本说明以及配置请查看脚本注释

" + ], + "settings": [ + { + "id": "@GOOGLE_CAPTCHA.Regex", + "name": "代理策略/策略组正则表达式", + "val": "", + "type": "text", + "placeholder": "^(🇸🇬|🇭🇰)\\s.*\\d+$", + "desc": "筛选的代理策略/策略组, 限制20个, 留空则表示随机使用。" + }, + { + "id": "@GOOGLE_CAPTCHA.RegexTest", + "name": "正则表达式测试", + "val": "", + "type": "text", + "placeholder": "(🇸🇬|🇭🇰)", + "desc": "填写并保存后可在右上角测试匹配的策略/策略组。" + } + ], + "scripts": [ + { + "name": "测试匹配的策略/策略组", + "script": "https://gist.githubusercontent.com/NobyDa/830932e4526c9c84169020a56c3ef199/raw/GOOGLE_CAPTCHA_TEST_POLICY.js" + } + ], + "author": "@NobyDa", + "repo": "https://github.com/NobyDa/Script/blob/master/Surge/JS/Google_CAPTCHA.js", + "icons": [ + "https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/Google.png", + "https://raw.githubusercontent.com/NobyDa/mini/master/Color/Google.png" + ] + } ], - "script": "https://raw.githubusercontent.com/NobyDa/Script/master/52pojie-DailyBonus/52pojie.js", - "author": "@NobyDa", - "repo": "https://github.com/NobyDa/Script/blob/master/52pojie-DailyBonus/52pojie.js", - "icons": ["https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/52pj.png", "https://raw.githubusercontent.com/NobyDa/mini/master/Color/52pj.png"] - }, { - "id": "KuaiKan", - "name": "快看漫画", - "keys": ["@KKMH.COOKIE", "@KKMH.TIME", "@KKMH.UID", "@KKMH.DATE"], - "descs_html": [ - "

获取Cookie以及脚本配置请查看脚本注释

" - ], - "settings": [{ - "id": "@KKMH.LOG", - "name": "响应日志", - "val": false, - "type": "boolean", - "desc": "打印原始签到结果, 用于调试脚本, 一般用户建议关闭." - }], - "script": "https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js", - "author": "@NobyDa", - "repo": "https://github.com/NobyDa/Script/blob/master/KuaiKan-DailyBonus/KKMH.js", - "icons": ["https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/KuaiKan.png", "https://raw.githubusercontent.com/NobyDa/mini/master/Color/KuaiKan.png"] - }, { - "id": "Bahamut", - "name": "巴哈姆特", - "keys": ["@ND_BAHA.ID", "@ND_BAHA.PW", "@ND_BAHA.TOTP", "@ND_BAHA.GUILD", "@ND_BAHA.ANSWER", "@ND_BAHA.ADS"], - "descs_html": [ - "

获取Cookie以及脚本配置请查看脚本注释

" - ], - "settings": [{ - "id": "@ND_BAHA.ADS", - "name": "签到广告", - "val": false, - "type": "boolean", - "desc": "开启后将签到双倍巴币奖励, 默认关闭. 请注意, 此功能耗时过长(30秒以上), 如果使用Surge请调整该脚本超时为300秒" - }, { - "id": "@ND_BAHA.GUILD", - "name": "签到公会", - "val": true, - "type": "boolean", - "desc": "开启后将自动签到公会" - }, { - "id": "@ND_BAHA.ANSWER", - "name": "动画疯答题", - "val": true, - "type": "boolean", - "desc": "开启后将自动答题" - }, { - "id": "@ND_BAHA.ID", - "name": "用户名", - "val": "", - "type": "text", - "placeholder": "(点击以展开说明)", - "desc": "输入用户名(账号)" - }, { - "id": "@ND_BAHA.PW", - "name": "用户密码", - "val": "", - "type": "text", - "placeholder": "", - "desc": "输入用户密码" - }, { - "id": "@ND_BAHA.TOTP", - "name": "两步验证令牌", - "val": "", - "type": "text", - "placeholder": "(点击以展开说明)", - "desc": "输入网站生成的16位令牌, 如未设置两步验证, 请留空" - }], - "script": "https://raw.githubusercontent.com/NobyDa/Script/master/Bahamut/BahamutDailyBonus.js", - "author": "@NobyDa", - "repo": "https://github.com/NobyDa/Script/blob/master/Bahamut/BahamutDailyBonus.js", - "icons": ["https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/bahamutGame.png", "https://raw.githubusercontent.com/NobyDa/mini/master/Color/bahamutGame.png"] - }, { - "id": "BiliRegion", - "name": "哔哩番剧自动地区", - "descs_html": [ - "

脚本配置请查看脚本注释

" - ], - "keys": ["BiliArea_Policy", "BiliArea_CN", "BiliArea_HK", "BiliArea_TW", "BiliArea_DF", "BiliArea_disabled"], - "settings": [{ - "id": "BiliAreaNotify", - "name": "静默运行", - "val": false, - "type": "boolean", - "desc": "开启后将不再发出切换策略通知" - }, { - "id": "BiliDoubanRating", - "name": "豆瓣评分", - "val": true, - "type": "boolean", - "desc": "关闭后将不再查询豆瓣评分, 可显著提高相关页面载入速度" - }, { - "id": "BiliArea_Policy", - "name": "策略组名", - "val": "", - "type": "text", - "placeholder": "(点击以展开说明)", - "desc": "哔哩哔哩分流的策略组名" - }, { - "id": "BiliArea_CN", - "name": "中国大陆-子策略名", - "val": "DIRECT", - "type": "text", - "placeholder": "(点击以展开说明)", - "desc": "哔哩哔哩分流策略组里的中国大陆子策略名" - }, { - "id": "BiliArea_HK", - "name": "中国香港-子策略名", - "val": "", - "type": "text", - "placeholder": "(点击以展开说明)", - "desc": "哔哩哔哩分流策略组里的香港子策略名" - }, { - "id": "BiliArea_TW", - "name": "中国台湾-子策略名", - "val": "", - "type": "text", - "placeholder": "(点击以展开说明)", - "desc": "哔哩哔哩分流策略组里的台湾子策略名" - }, { - "id": "BiliArea_DF", - "name": "后备-子策略名", - "val": "", - "type": "text", - "placeholder": "(点击以展开说明)", - "desc": "部分番剧可能会被屏蔽, 使用该策略以避免页面加载失败. 建议填写台湾子策略" - }, { - "id": "BiliArea_disabled", - "name": "WiFi黑名单", - "val": "", - "type": "text", - "placeholder": "(点击以展开说明)", - "desc": "WiFi名称以逗号分隔, 名单内将跳过策略切换" - }], - "author": "@NobyDa", - "repo": "https://github.com/NobyDa/Script/blob/master/Surge/JS/Bili_Auto_Regions.js", - "icons": ["https://raw.githubusercontent.com/NobyDa/mini/master/Alpha/bilibili.png", "https://raw.githubusercontent.com/NobyDa/mini/master/Color/bilibili.png"] - }], - "task": [{ - "config": "0 8 * * * https://raw.githubusercontent.com/NobyDa/Script/master/JD-DailyBonus/JD_DailyBonus.js, tag=京东签到, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/jd.png", - "addons": "https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Js_Remote_Cookie.conf, tag=NobyDa Cookie获取" - }, { - "config": "5 8 * * * https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js, tag=爱奇艺签到, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/iQIYI.png", - "addons": "https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Js_Remote_Cookie.conf, tag=NobyDa Cookie获取" - }, { - "config": "10 8 * * * https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js, tag=哔哩漫画签到, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/manga.png", - "addons": "https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Js_Remote_Cookie.conf, tag=NobyDa Cookie获取" - }, { - "config": "10,20,30 0 12 * * * https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/ExchangePoints.js, tag=哔哩漫画抢券, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/manga.png", - "addons": "https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Js_Remote_Cookie.conf, tag=NobyDa Cookie获取" - }, { - "config": "15 8 * * * https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js, tag=百度贴吧签到, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/tieba.png", - "addons": "https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Js_Remote_Cookie.conf, tag=NobyDa Cookie获取" - }, { - "config": "20 8 * * * https://raw.githubusercontent.com/NobyDa/Script/master/52pojie-DailyBonus/52pojie.js, tag=吾爱破解签到, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/52pj.png", - "addons": "https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Js_Remote_Cookie.conf, tag=NobyDa Cookie获取" - }, { - "config": "25 8 * * * https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js, tag=快看漫画签到, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/KuaiKan.png", - "addons": "https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Js_Remote_Cookie.conf, tag=NobyDa Cookie获取" - }, { - "config": "0 8 * * * https://raw.githubusercontent.com/NobyDa/Script/master/Bahamut/BahamutDailyBonus.js, tag=巴哈姆特签到, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/bahamutGame.png" - }] + "task": [ + { + "config": "30 8 * * * https://raw.githubusercontent.com/NobyDa/Script/master/Ctrip-DailyBonus/Ctrip.js, tag=携程旅行签到, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/ctrip.png", + "addons": "https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/CtripAuth.snippet, tag=携程旅行(获取授权)" + }, + { + "config": "5 8 * * * https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js, tag=爱奇艺签到, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/iQIYI.png", + "addons": "https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/iQiYiCookie.snippet, tag=爱奇艺(获取Cookie)" + }, + { + "config": "10 8 * * * https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js, tag=哔哩漫画签到, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/manga.png", + "addons": "https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/BiliComicCookie.snippet, tag=哔哩漫画(获取Cookie)" + }, + { + "config": "10,20,30 0 12 * * * https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/ExchangePoints.js, tag=哔哩漫画抢券, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/manga.png", + "addons": "https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/BiliComicCookie.snippet, tag=哔哩漫画(获取Cookie)" + }, + { + "config": "15 8 * * * https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js, tag=百度贴吧签到, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/tieba.png", + "addons": "https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/TieBaCookie.snippet, tag=百度贴吧(获取Cookie)" + }, + { + "config": "25 8 * * * https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js, tag=快看漫画签到, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/KuaiKan.png", + "addons": "https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/KuaiKanCookie.snippet, tag=快看漫画(获取Cookie)" + }, + { + "config": "0 8 * * * https://raw.githubusercontent.com/NobyDa/Script/master/Bahamut/BahamutDailyBonus.js, tag=巴哈姆特签到, img-url=https://raw.githubusercontent.com/NobyDa/mini/master/Color/bahamutGame.png" + } + ] } \ No newline at end of file diff --git a/QuantumultX/AdRule.list b/QuantumultX/AdRule.list index 982da34a0c..f077f195cb 100644 --- a/QuantumultX/AdRule.list +++ b/QuantumultX/AdRule.list @@ -1,4 +1,4 @@ -# Update > 2022.1.26 +# Update > 2023/12/23 DOMAIN-SUFFIX,api-access.pangolin-sdk-toutiao-b.com,REJECT DOMAIN-SUFFIX,apoll.m.taobao.com,REJECT DOMAIN-SUFFIX,comet.yahoo.com,REJECT @@ -135,7 +135,6 @@ DOMAIN-SUFFIX,m-78.jp,REJECT DOMAIN-SUFFIX,nichibenren.or.jp,REJECT DOMAIN-SUFFIX,nicorette.co.kr,REJECT DOMAIN-SUFFIX,adnet.sohu.com,REJECT -DOMAIN-SUFFIX,data.vod.itc.cn,REJECT DOMAIN-SUFFIX,epro.sogou.com,REJECT DOMAIN-SUFFIX,go.sohu.com,REJECT DOMAIN-SUFFIX,golden1.sogou.com,REJECT @@ -167,7 +166,6 @@ DOMAIN-SUFFIX,ad.video.51togic.com,REJECT DOMAIN-SUFFIX,biz5.kankan.com,REJECT DOMAIN-SUFFIX,c.algovid.com,REJECT DOMAIN-SUFFIX,cms.laifeng.com,REJECT -DOMAIN-SUFFIX,da.mmarket.com,REJECT DOMAIN-SUFFIX,dotcounter.douyutv.com,REJECT DOMAIN-SUFFIX,g.uusee.com,REJECT DOMAIN-SUFFIX,gcdn.2mdn.net,REJECT @@ -2012,7 +2010,6 @@ DOMAIN-SUFFIX,cc.yac8.com,REJECT DOMAIN-SUFFIX,cca.mob.com,REJECT DOMAIN-SUFFIX,ccb.uncle-ad.com,REJECT DOMAIN-SUFFIX,ccbaihehq.com,REJECT -DOMAIN-SUFFIX,ccclub.cmbchina.com,REJECT DOMAIN-SUFFIX,cccrir.com,REJECT DOMAIN-SUFFIX,ccr.yxdown.com,REJECT DOMAIN-SUFFIX,cctyly.com,REJECT @@ -2052,7 +2049,6 @@ DOMAIN-SUFFIX,cdn.mdotm.com,REJECT DOMAIN-SUFFIX,cdn.media.innity.net,REJECT DOMAIN-SUFFIX,cdn.millennialmedia.com,REJECT DOMAIN-SUFFIX,cdn.mingmingtehui.com,REJECT -DOMAIN-SUFFIX,cdn.moji.com,REJECT DOMAIN-SUFFIX,cdn.moji002.com,REJECT DOMAIN-SUFFIX,cdn.moogos.com,REJECT DOMAIN-SUFFIX,cdn.ndapp.com,REJECT diff --git a/QuantumultX/AdRuleTest.list b/QuantumultX/AdRuleTest.list index 9b228a8163..48b0903ea1 100644 --- a/QuantumultX/AdRuleTest.list +++ b/QuantumultX/AdRuleTest.list @@ -1190,7 +1190,6 @@ DOMAIN-SUFFIX,video.c-ctrip.com,REJECT DOMAIN-SUFFIX,agn.aty.sohu.com,REJECT DOMAIN-SUFFIX,map-mobile-opnimg.cdn.bcebos.com,REJECT DOMAIN-SUFFIX,app.adjust.com,REJECT -DOMAIN-SUFFIX,mob.com,REJECT DOMAIN-SUFFIX,adthor.com,REJECT DOMAIN-SUFFIX,pubnative.net,REJECT DOMAIN-SUFFIX,flurry.com,REJECT diff --git a/QuantumultX/Bilibili.list b/QuantumultX/Bilibili.list new file mode 100644 index 0000000000..fee8848e83 --- /dev/null +++ b/QuantumultX/Bilibili.list @@ -0,0 +1,13 @@ +# 该规则集用于配合bilibili自动地区脚本使用。 +host,api.biliapi.com,Bilibili +host,api.biliapi.net,Bilibili +host,api.bilibili.com,Bilibili +host,app.biliapi.com,Bilibili +host,app.biliapi.net,Bilibili +host,app.bilibili.com,Bilibili +host,grpc.biliapi.net,Bilibili +host,m.bilibili.com,Bilibili +host,upos-hz-mirrorakam.akamaized.net,Bilibili +host,www.bilibili.com,Bilibili +host-keyword,cn-hk-eq-bcache-,Bilibili +ip-cidr,121.11.192.0/24,Bilibili \ No newline at end of file diff --git a/QuantumultX/DisneyRating.snippet b/QuantumultX/DisneyRating.snippet new file mode 100644 index 0000000000..5ae613e3d9 --- /dev/null +++ b/QuantumultX/DisneyRating.snippet @@ -0,0 +1,7 @@ +# Disney+剧集页显示IMDb / 烂番茄 / 豆瓣评分 +# https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/DisneyRating.snippet + + +^https:\/\/disney\.api\.edge\.bamgrid\.com\/explore\/v\d\.\d+\/page\/entity- url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Disney/DisneyRating.js + +hostname = disney.api.edge.bamgrid.com \ No newline at end of file diff --git a/QuantumultX/File/Zymh.js b/QuantumultX/File/Zymh.js index 60ea25badc..ea44395072 100644 --- a/QuantumultX/File/Zymh.js +++ b/QuantumultX/File/Zymh.js @@ -5,19 +5,19 @@ QuantumultX: [rewrite_local] -^https:\/\/(userpurchased|user-api)\.zymk\.cn\/v\d\/(userpurchased\/paychapters|getuserinfo)\/ url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/Zymh.js +^https:\/\/apigate\.kaimanhua\.com\/(zymk-getuserinfo-api\/v1\/getuserinfo|zymk-userpurchased-api\/v1\/userpurchased\/paychapters)\/ url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/Zymh.js [mitm] -hostname = user*.zymk.cn +hostname = apigate.kaimanhua.com *************************** Surge4 or Loon: [Script] -http-response ^https:\/\/(userpurchased|user-api)\.zymk\.cn\/v\d\/(userpurchased\/paychapters|getuserinfo)\/ requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/Zymh.js +http-response ^https:\/\/apigate\.kaimanhua\.com\/(zymk-getuserinfo-api\/v1\/getuserinfo|zymk-userpurchased-api\/v1\/userpurchased\/paychapters)\/ requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/Zymh.js [MITM] -hostname = user*.zymk.cn +hostname = apigate.kaimanhua.com **************************/ var obj = JSON.parse($response.body); @@ -25,4 +25,4 @@ obj.status = 0; obj.data.isvip = 1; obj.data.coins = 6666; obj.data.Cgold = 6666; -$done({body: JSON.stringify(obj)}); \ No newline at end of file +$done({body: JSON.stringify(obj)}); diff --git a/QuantumultX/File/aimeiju.js b/QuantumultX/File/aimeiju.js deleted file mode 100644 index 7ae00ccfcf..0000000000 --- a/QuantumultX/File/aimeiju.js +++ /dev/null @@ -1,77 +0,0 @@ -/* -爱美剧 解锁部分功能 -官网: https://www.mjapp.cc -脚本原作者: 灰灰 - -可自行添加启动广告/弹窗规则, REGEX: -^https?://api.bjxkhc.com/index.php/app/ios/ads/index -^https?://api.bjxkhc.com/index.php/app/ios/ver/index_ios$ -^https?://api.bjxkhc.com/index.php/app/ios/pay/ok$ - -*************************** -QuantumultX: - -[rewrite_local] -^https?:\/\/api.bjxkhc.com\/index\.php\/app\/ios\/(vod\/show|(user|vod|topic|type)\/index) url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/aimeiju.js - -[mitm] -hostname = api.bjxkhc.com - -*************************** -Surge4 or Loon: - -[Script] -http-response ^https?:\/\/api.bjxkhc.com\/index\.php\/app\/ios\/(vod\/show|(user|vod|topic|type)\/index) requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/aimeiju.js - -[MITM] -hostname = api.bjxkhc.com - -**************************/ - -var url = $request.url; -var obj = JSON.parse($response.body || '{}'); -const user = "/index.php/app/ios/user/index"; //用户信息 -const show = "/index.php/app/ios/vod/show"; //视频播放页面 -const banner = "/index.php/app/ios/vod/index";//首页轮播广告 -const topic = "/index.php/app/ios/topic/index";//豆瓣热榜中间广告 -const type = "/index.php/app/ios/type/index"//综合专区,美剧专区中间广告 - -if (obj.data && obj.data.user && url.indexOf(user) != -1) { - obj.data.user.viptime = "2088-08-08 08:08:08"; - obj.data.user.cion = "88888"; - obj.data.user.vip = "1"; -} - -if (obj.data && url.indexOf(show) != -1) { - obj.data.looktime = -1; - obj.data.vip = "4"; - delete obj.data.advertising;//视频下方轮播,删掉也不能清除广告占位 - obj.data.CT_App_Show_Pic1 = "";//联系客服图片 - obj.data.CT_App_Show_Url1 = "";//联系客服链接 - obj.data.CT_App_Show_Vod1 = "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1519044039,3175177225&fm=26&gp=0.jpg";//片头广告,留空的话不会自动播放 - obj.data.CT_App_Show_Vod_Time1 = "0";//片头广告显示时间(0秒也短暂显示) - obj.data.CT_App_Show_Vod_Url1 = "";//片头广告链接 - obj.data.CT_App_Show_Vod_Type1 = "2";//片头广告显示类型,0一直显示,1暂停播放显示,2显示后自动播放 - obj.data.CT_App_Show_Vod_must_Time1 = "0";//片头联系客服图片显示时间,前面改VIP这里自动变0 - obj.data.CT_Pic_url1_pause = "";//暂停联系客服图片 - obj.data.CT_Pic_url1_pause_skip = "";//暂停联系客服链接 -} - -if (obj.data && url.indexOf(banner) != -1) { - for (var i = obj.data.length - 1; i >= 0; i--) { - if (obj.data[i].ad == 1) { - obj.data.splice(i, 1) - } - } -} - -if (obj.data && (url.indexOf(topic) != -1 || url.indexOf(type) != -1)) { - for (var i = obj.data.length - 1; i >= 0; i--) { - if (obj.data[i].ad == 1) { - obj.data[i].ad = 0; - obj.data[i].pic = ""; - delete obj.data[i].url - } - } -} -$done({ body: JSON.stringify(obj) }); \ No newline at end of file diff --git a/QuantumultX/File/dapian.js b/QuantumultX/File/dapian.js deleted file mode 100644 index c066da7d41..0000000000 --- a/QuantumultX/File/dapian.js +++ /dev/null @@ -1,32 +0,0 @@ -/* -Bigshot 解锁高级特权(需登录) - -*************************** -QuantumultX: - -[rewrite_local] -^https:\/\/vni\.kwaiying\.com\/api\/v1\/user\/profile url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/dapian.js - -[mitm] -hostname = vni.kwaiying.com - -*************************** -Surge4 or Loon: - -[Script] -http-response ^https:\/\/vni\.kwaiying\.com\/api\/v1\/user\/profile requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/dapian.js - -[MITM] -hostname = vni.kwaiying.com -**************************/ - -var obj = JSON.parse($response.body); - -if (obj.data && obj.data.userInfo) { - obj.data.userInfo.isVip = 1; - obj.data.userInfo.memberId = 666 - obj.data.userInfo.vipStartTime = 1591430766000; - obj.data.userInfo.vipEndTime = 3043037166000; -} - -$done({ body: JSON.stringify(obj) }); \ No newline at end of file diff --git a/QuantumultX/File/vsco.js b/QuantumultX/File/vsco.js index d02b7872f9..c308e1dd1e 100644 --- a/QuantumultX/File/vsco.js +++ b/QuantumultX/File/vsco.js @@ -1,64 +1,53 @@ -/* -VSCO 解锁高级特权 +/******************************** +Membership unlock for VSCO & 1Blocker & HTTPBot +Please note that you may need to reinstall app for script to work. -*************************** -QuantumultX: +QuantumultX rewrite link: +https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/vsco.js -[rewrite_local] -^https:\/\/(api\.revenuecat\.com\/v\d\/subscribers|vsco\.co\/api\/subscriptions\/\d\.\d\/user-subscriptions)\/ url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/vsco.js +Please note that the above rewrite link requires open KOP-XIAO's resource parser -[mitm] -hostname = vsco.co, api.revenuecat.com - -*************************** -Surge4 or Loon: +********************************* +Surge4, Loon and Shadowrocket configuration: [Script] -http-response ^https:\/\/(api\.revenuecat\.com\/v\d\/subscribers|vsco\.co\/api\/subscriptions\/\d\.\d\/user-subscriptions)\/ requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/vsco.js +http-request ^https?:\/\/api\.revenuecat\.com\/v\d\/subscribers\/ script-path=https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/vsco.js +http-response ^https?:\/\/api\.revenuecat\.com\/v\d\/subscribers\/ requires-body=1,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/vsco.js [MITM] -hostname = vsco.co, api.revenuecat.com - -**************************/ - -let obj = JSON.parse($response.body || '{}'); - -if (obj.user_subscription) { - obj.user_subscription["expires_on_sec"] = 1655536094; - obj.user_subscription["expired"] = false; - obj.user_subscription["payment_type"] = 2; - obj.user_subscription["is_trial_period"] = true; - obj.user_subscription["starts_on_sec"] = 1560831070; - obj.user_subscription["is_active"] = true; - obj.user_subscription["auto_renew"] = true; - obj.user_subscription["last_verified_sec"] = 1560831070; - obj.user_subscription["subscription_code"] = "VSCOANNUAL"; - obj.user_subscription["user_id"] = 54624336; - obj.user_subscription["source"] = 1; -} - -if (obj.subscriber) { - obj.subscriber.subscriptions = { - "com.circles.fin.premium.yearly": { - "billing_issues_detected_at": null, - "expires_date": "2030-02-18T07:52:54Z", - "is_sandbox": false, - "original_purchase_date": "2020-02-11T07:52:55Z", - "period_type": "normal", - "purchase_date": "2020-02-11T07:52:54Z", - "store": "app_store", - "unsubscribe_detected_at": null - } - }; - obj.subscriber.entitlements = { - "membership": { - "expires_date": "2030-02-18T07:52:54Z", - "product_identifier": "com.circles.fin.premium.yearly", - "purchase_date": "2020-02-11T07:52:54Z" +hostname = api.revenuecat.com +********************************/ + +const resp = {}; +const obj = JSON.parse(typeof $response != "undefined" && $response.body || null); +const ua = $request.headers['User-Agent'] || $request.headers['user-agent']; +const list = { + 'HTTPBot': { name: 'rc_lifetime', id: 'com.behindtechlines.HTTPBot.prounlock' }, + 'VSCO': { name: 'membership', id: 'com.circles.fin.premium.yearly' }, + '1Blocker': { name: 'premium', id: 'blocker.ios.subscription.yearly' } +}; +const data = { + "expires_date": "2030-02-18T07:52:54Z", + "original_purchase_date": "2020-02-11T07:52:55Z", + "purchase_date": "2020-02-11T07:52:54Z" +}; + +if (typeof $response == "undefined") { + delete $request.headers["x-revenuecat-etag"]; // prevent 304 issues + delete $request.headers["X-RevenueCat-ETag"]; + resp.headers = $request.headers; +} else if (obj && obj.subscriber) { + obj.subscriber.subscriptions = obj.subscriber.subscriptions || {}; + obj.subscriber.entitlement = obj.subscriber.entitlement || {}; + for (const i in list) { + if (new RegExp(`^${i}`, `i`).test(ua)) { + obj.subscriber.subscriptions[list[i].id] = data; + obj.subscriber.entitlements[list[i].name] = JSON.parse(JSON.stringify(data)); + obj.subscriber.entitlements[list[i].name].product_identifier = list[i].id; + break; } - }; + } + resp.body = JSON.stringify(obj); } -$done({ - body: JSON.stringify(obj) -}); \ No newline at end of file +$done(resp); diff --git a/QuantumultX/File/wnyd.js b/QuantumultX/File/wnyd.js index c40f1c7bc4..c0f0673276 100644 --- a/QuantumultX/File/wnyd.js +++ b/QuantumultX/File/wnyd.js @@ -24,6 +24,6 @@ hostname = p.du.163.com var body = $response.body; var obj = JSON.parse(body); -obj.tradeEndTime = 1679685290000; +obj.tradeEndTime = 1879685290000; body = JSON.stringify(obj); $done({body}); diff --git a/QuantumultX/IPA-Installer.snippet b/QuantumultX/IPA-Installer.snippet new file mode 100644 index 0000000000..d8a3b125a3 --- /dev/null +++ b/QuantumultX/IPA-Installer.snippet @@ -0,0 +1,6 @@ +# 该文件为 "IPA应用辅助安装脚本" QuantumultX远端重写资源. +# 该资源可在iOS端辅助安装商店版或已签名IPA(需使用快捷指令 + Shu/Jsbox/pythonista), 查看脚本注释以了解具体方法; 安装演示可查看TG频道 @NobyDa + +^https:\/\/nobyda.app/(install|download) url script-analyze-echo-response https://raw.githubusercontent.com/NobyDa/Script/master/IPA-Installer/IPA-Installer.js + +hostname = nobyda.app \ No newline at end of file diff --git a/QuantumultX/Js.conf b/QuantumultX/Js.conf index 8a7767145c..d998a771f9 100644 --- a/QuantumultX/Js.conf +++ b/QuantumultX/Js.conf @@ -1,33 +1,18 @@ -hostname = api.weibo.cn, mapi.weibo.com, *.uve.weibo.com, mp.weixin.qq.com, www.zhihu.com, api.zhihu.com, link.zhihu.com, vip1.kuwo.cn, p.du.163.com, vsco.co, user*.zymk.cn, vni.kwaiying.com, *.my10api.com, www.luqijianggushi.com, account.wps.cn, origin-prod-phoenix.jibjab.com, api.bjxkhc.com, xy-viva.kakalili.com, ap*.intsig.net, m*.bybutter.com, api.vuevideo.net, api.picsart.c*, ios.fuliapps.com, apple.fuliapps.com, *.pipiapps.com, ios.xiangjiaoapps.com, apple.xiangjiaoapps.com, *.xiangxiangapps.com, api.meiease.c*, trade-acs.m.taobao.com, api.m.jd.com, ios*.prod.ftl.netflix.com, api.revenuecat.com, pan.baidu.com, bmall.camera360.com, api.polaxiong.com +hostname = api.weibo.cn, mapi.weibo.com, *.uve.weibo.com, mp.weixin.qq.com, api.zhihu.com, p.du.163.com, apigate.zymk.cn, www.luqijianggushi.com, origin-prod-phoenix.jibjab.com, xy-viva.kakalili.com, ap*.intsig.net, ios.fuliapps.com, apple.fuliapps.com, *.pipiapps.com, ios.xiangjiaoapps.com, apple.xiangjiaoapps.com, *.xiangxiangapps.com, api.m.jd.com, ios*.prod.ftl.netflix.com, api.revenuecat.com, pan.baidu.com, bmall.camera360.com, api-chn.rthdo.com # 去微信公众号广告 (By Choler) ^https?:\/\/mp\.weixin\.qq\.com\/mp\/getappmsgad url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/Wechat.js -# 酷我音乐SVIP (By yxiaocai) -^https?:\/\/vip1\.kuwo\.cn\/(vip\/v2\/user\/vip|vip\/spi/mservice) url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Kuwo.js - -# 爱美剧Vip (by huihui)(官网:app.meiju2018.com) -^https?:\/\/api.bjxkhc.com\/index\.php\/app\/ios\/(vod\/show|(user|vod|topic|type)\/index) url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/aimeiju.js -# 广告 -^https?://api.bjxkhc.com/index.php/app/ios/ads/index url reject-dict -^https?://api.bjxkhc.com/index.php/app/ios/ver/index_ios$ url reject -^https?://api.bjxkhc.com/index.php/app/ios/pay/ok$ url reject-dict - # 网易蜗牛读书VIP (By yxiaocai and JO2EY) ^https?://p\.du\.163\.com/readtime/info.json url reject ^https?:\/\/p\.du\.163\.com\/gain\/readtime\/info\.json url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/wnyd.js # 知音漫客VIP -^https:\/\/(userpurchased|user-api)\.zymk\.cn\/v\d\/(userpurchased\/paychapters|getuserinfo)\/ url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/Zymh.js - -# VSCO滤镜VIP -^https:\/\/(api\.revenuecat\.com\/v\d\/subscribers|vsco\.co\/api\/subscriptions\/\d\.\d\/user-subscriptions)\/ url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/vsco.js +^https:\/\/apigate\.zymk\.cn\/(zymk-getuserinfo-api\/v1\/getuserinfo|zymk-userpurchased-api\/v1\/userpurchased\/paychapters)\/ url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/Zymh.js -# 大片(Bigshot) 视频编辑器 VIP -^https:\/\/vni\.kwaiying\.com\/api\/v1\/user\/profile url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/dapian.js - -# 91短视频 -^https?:\/\/.+?\.(my10api|(.*91.*))\.(com|tips|app|xyz)(:\d{2,5}|)\/api.php$ url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/91.js +# VSCO & 1Blocker +^https?:\/\/api\.revenuecat\.com\/v\d\/subscribers\/ url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/vsco.js +^https?:\/\/api\.revenuecat\.com\/v\d\/subscribers\/ url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/vsco.js # 香蕉视频VIP ^https?:\/\/.+?\.(pipi|fuli|xiang(jiao|xiang))apps\.com\/(ucp\/index|getGlobalData|(\/|)vod\/reqplay\/) url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/xjsp.js @@ -35,36 +20,21 @@ # 陆琪讲故事 ^https:\/\/www\.luqijianggushi\.com\/api\/v2\/user\/get url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/luqi.js -# WPS (By eHpo) -^https://account.wps.cn/api/users/ url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Wps.js - # JibJab解锁pro ^https:\/\/origin-prod-phoenix\.jibjab\.com\/v1\/user url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/jibjab.js # 小影 解锁Vip -^https:\/\/xy-viva\.kakalili\.com\/api\/rest\/u\/vipVerifyReceipt url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/vivavideo.js +^https:\/\/(xy-viva\.kakalili|api-chn.rthdo)\.com\/api\/rest\/u\/vipVerifyReceipt url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/vivavideo.js # 扫描全能王 pro ^https:\/\/(api|api-cs)\.intsig\.net\/purchase\/cs\/query_property\? url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/CamScanner.js -# VUE pro -^https:\/\/api\.vuevideo\.net\/api\/v1\/(users\/.+\/profile|subtitle\/prepare) url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/VUE.js - -# NiChi 解锁素材 -^https?:\/\/m(p|ini-hk)\.bybutter\.com\/mood\/(official-templates|privileges) url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/NiChi.js - -# PicsArt美易 pro -^https:\/\/api\.(picsart|meiease)\.c(n|om)\/users\/show\/me\.json url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/PicsArt.js - # 百度网盘 解除在线视频倍率/清晰度 ^https:\/\/pan\.baidu\.com\/rest\/\d\.\d\/membership\/user url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/BaiduCloud.js # MIX 解锁高级特权 (需恢复购买) ^https?:\/\/bmall\.camera360\.com\/api\/mix\/recovery url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/MIX.js -# 泼辣修图 解锁高级特权 (需恢复购买) -^https:\/\/api\.polaxiong\.com\/v1\/payments\/appleiap\/receipts\/confirmation url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Polarr.js - ################################# ###########其他仓库引用########### ################################# @@ -76,17 +46,9 @@ # 知乎去广告 (onewayticket255) https://api.zhihu.com/(ad|drama|fringe|commercial|market/popover|search/(top|preset|tab)|.*featured-comment-ad) url reject-200 -# 哔哩哔哩动画去广告 (onewayticket255) -https://app.bilibili.com/x/v2/(splash|search/square) url reject-200 -https://api.bilibili.com/x/v2/dm/ad url reject-200 - -# 京东比价 (yichahucha) +# 京东比价 ^https?://api\.m\.jd\.com/client\.action\?functionId=(wareBusiness|serverConfig|basicConfig) url script-response-body https://service.2ti.st/QuanX/Script/jd_tb_price/main.js -# 淘宝比价 (yichahucha) -^http://.+/amdc/mobileDispatch url script-request-body https://service.2ti.st/QuanX/Script/jd_tb_price/main.js -^https?://trade-acs\.m\.taobao\.com/gw/mtop\.taobao\.detail\.getdetail url script-response-body https://service.2ti.st/QuanX/Script/jd_tb_price/main.js - # Netflix评分 (yichahucha) ^https?://ios[-\w]*\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D url script-request-header https://raw.githubusercontent.com/yichahucha/surge/master/nf_rating.js ^https?://ios[-\w]*\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D url script-response-body https://raw.githubusercontent.com/yichahucha/surge/master/nf_rating.js diff --git a/QuantumultX/Js_Remote_Cookie.conf b/QuantumultX/Js_Remote_Cookie.conf deleted file mode 100644 index 4031559cc4..0000000000 --- a/QuantumultX/Js_Remote_Cookie.conf +++ /dev/null @@ -1,22 +0,0 @@ -# 此远程订阅用于解决QX任务脚本的cookie获取,仅适用于QX 1.0.10及更高版本,您可在使用后手动将其禁用,以避免无意义的MITM。 - -hostname = passport.iqiyi.com, www.52pojie.cn, c.tieba.baidu.com, api.m.jd.com, ms.jr.jd.com, me-api.jd.com, passport.biligame.com, api.kkmh.com - -# 爱奇艺 cookie -^https:\/\/passport\.iqiyi\.com\/apis\/user\/info\.action url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js - -# 吾爱破解 cookie -https:\/\/www\.52pojie\.cn\/home\.php\?mod=space url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/52pojie-DailyBonus/52pojie.js - -# 百度贴吧 cookie -https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js - -# 京东 cookie -^https:\/\/(api\.m|me-api)\.jd\.com\/(client\.action\?functionId=signBean|user_new\/info\/GetJDUserInfoUnion\?) url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/JD-DailyBonus/JD_DailyBonus.js -^https:\/\/ms\.jr\.jd\.com\/gw\/generic\/hy\/h5\/m\/appSign\? url script-request-body https://raw.githubusercontent.com/NobyDa/Script/master/JD-DailyBonus/JD_DailyBonus.js - -# 哔哩哔哩漫画 Get cookie -^https:\/\/passport\.biligame\.com\/api\/login\/sso.+?version%22%3A%22(3|4|5) url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js - -# 快看漫画 cookie -^https:\/\/api\.kkmh\.com\/v\d\/passport\/user url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js \ No newline at end of file diff --git a/QuantumultX/Snippet/BiliComicCookie.snippet b/QuantumultX/Snippet/BiliComicCookie.snippet new file mode 100644 index 0000000000..d3d5bdb494 --- /dev/null +++ b/QuantumultX/Snippet/BiliComicCookie.snippet @@ -0,0 +1,8 @@ +# 该 QuantumultX 远程重写配置片段用于获取"哔哩哔哩漫画签到"账号Cookie +# 配置脚本后打开哔哩哔哩漫画(AppStore中国区),点击"我的"可完成获取 +# https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/BiliComicCookie.snippet + + +^https:\/\/app\.bilibili\.com\/x\/v2\/account\/myinfo url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js + +hostname = app.bilibili.com \ No newline at end of file diff --git a/QuantumultX/Snippet/CtripAuth.snippet b/QuantumultX/Snippet/CtripAuth.snippet new file mode 100644 index 0000000000..78327113a7 --- /dev/null +++ b/QuantumultX/Snippet/CtripAuth.snippet @@ -0,0 +1,8 @@ +# 该 QuantumultX 远程重写配置片段用于获取"携程签到"账号授权 +# 配置脚本后登陆"携程旅行"微信小程序或"携程网页版"(https://m.ctrip.com/)即可完成获取 +# https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/CtripAuth.snippet + + +^https:\/\/m\.ctrip\.com\/restapi\/soa2\/\d+\/[a-zA-Z]+Login(?:$|\?) url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Ctrip-DailyBonus/Ctrip.js + +hostname = m.ctrip.com \ No newline at end of file diff --git a/QuantumultX/Snippet/GoogleCAPTCHA.snippet b/QuantumultX/Snippet/GoogleCAPTCHA.snippet new file mode 100644 index 0000000000..0f7e985912 --- /dev/null +++ b/QuantumultX/Snippet/GoogleCAPTCHA.snippet @@ -0,0 +1,12 @@ +# QuantumultX 远程重写配置片段 + +# Google搜索人机验证解决方案 +# Google搜索内容时并发使用多个代理策略、策略组尝试搜索内容,并返回最优结果。具体细节可查看脚本注释。 + +# 脚本:https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Google_CAPTCHA.js +# 片段:https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/GoogleCAPTCHA.snippet + + +^https:\/\/www\.google\.com(?:\.[a-z]+|)\/(?:search\?(?:|.+?&)q=|$) url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Google_CAPTCHA.js + +hostname = www.google.com* \ No newline at end of file diff --git a/QuantumultX/Snippet/KuaiKanCookie.snippet b/QuantumultX/Snippet/KuaiKanCookie.snippet new file mode 100644 index 0000000000..2cd8e0eaa4 --- /dev/null +++ b/QuantumultX/Snippet/KuaiKanCookie.snippet @@ -0,0 +1,8 @@ +# 该 QuantumultX 远程重写配置片段用于获取"快看漫画签到"账号Cookie +# 配置脚本后打开快看漫画(AppStore中国区),点击"我的"可完成获取 +# https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/KuaiKanCookie.snippet + + +^https:\/\/api\.kkmh\.com\/v\d\/passport\/user url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js + +hostname = api.kkmh.com \ No newline at end of file diff --git a/QuantumultX/Snippet/TieBaCookie.snippet b/QuantumultX/Snippet/TieBaCookie.snippet new file mode 100644 index 0000000000..1a5e923ce0 --- /dev/null +++ b/QuantumultX/Snippet/TieBaCookie.snippet @@ -0,0 +1,8 @@ +# 该 QuantumultX 远程重写配置片段用于获取"百度贴吧签到"账号Cookie +# 配置脚本后打开百度贴吧App(AppStore中国区, 非内部版),点击"我的"可完成获取 +# https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/TieBaCookie.snippet + + +https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js + +hostname = c.tieba.baidu.com \ No newline at end of file diff --git a/QuantumultX/Snippet/iQiYiCookie.snippet b/QuantumultX/Snippet/iQiYiCookie.snippet new file mode 100644 index 0000000000..0c77dbc4b3 --- /dev/null +++ b/QuantumultX/Snippet/iQiYiCookie.snippet @@ -0,0 +1,8 @@ +# 该 QuantumultX 远程重写配置片段用于获取"爱奇艺签到"账号Cookie +# 配置脚本后 Safari 浏览器打开 https://m.iqiyi.com/user.html 使用密码登录可完成获取 +# https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/iQiYiCookie.snippet + + +^https:\/\/passport\.iqiyi\.com\/apis\/user\/ url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js + +hostname = passport.iqiyi.com \ No newline at end of file diff --git a/README.md b/README.md old mode 100644 new mode 100755 index a6746ec153..dee52ced84 --- a/README.md +++ b/README.md @@ -1,140 +1,127 @@ ## TOC -- [Script desc](#script-desc) - - [Daily bonus scripts](#daily-bonus-scripts) - - [Functionality-enhancing scripts](#functionality-enhancing-scripts) - - [Other scripts](#other-scripts) -- [Surge file desc](#surge-file-desc) - - [Surge ruleset](#surge-ruleset) - - [Surge module](#surge-module) -- [QuantumultX file desc](#quantumultx--file-desc) -- [Loon file desc](#loon-file-desc) +- [TOC](#toc) +- [Script Overview](#script-overview) + - [Daily-Bonus Script](#daily-bonus-script) + - [Functionality-enhancing Script](#functionality-enhancing-script) + - [Other Script](#other-script) +- [Surge File Overview](#surge-file-overview) +- [QuantumultX File Overview](#quantumultx-file-overview) +- [Loon File Overview](#loon-file-overview) +- [Stash File Overview](#stash-file-overview) - [Disclaimer](#disclaimer) - [Decrypt](#decrypt) - [Privacy](#privacy) - [Commercial](#commercial) - - [Nfringement](#nfringement) + - [Infringement](#infringement) - [Liability](#liability) - [Change](#change) -- [Special thanks to](#special-thanks-to) +- [Acknowledgment](#acknowledgment) - [License](#license) +> **The scripts or rewrite rules described below may require enabling MITM. Additionally, the generated root certificate must be installed and trusted manually in the system.** -> **Please note that the scripts or rewrite rules described below need to open MITM and trust the certificate.** +## Script Overview -## Script desc +### Daily-Bonus Script -### Daily bonus scripts - -| Application | Script name | Available | Maintenance | -| :-----------------------------------------------------: | :----------------------------------------------------------: | :----------: | :---------: | -| [京东商城](https://apps.apple.com/app/id414245413) | [JD_DailyBonus.js](https://github.com/NobyDa/Script/blob/master/JD-DailyBonus/JD_DailyBonus.js) | ✅(2021.7.4) | ✅ | -| [百度贴吧](https://apps.apple.com/app/id477927812) | [TieBa.js](https://github.com/NobyDa/Script/blob/master/BDTieBa-DailyBonus/TieBa.js) | ✅(2021.7.4) | ❌ | -| [吾爱破解](https://www.52pojie.cn/) | [52pojie.js](https://github.com/NobyDa/Script/blob/master/52pojie-DailyBonus/52pojie.js) | ❌(2021.11) | ❌ | -| [爱奇艺](https://apps.apple.com/cn/app/id393765873) | [iQIYI.js](https://github.com/NobyDa/Script/blob/master/iQIYI-DailyBonus/iQIYI.js) | ✅(2022.1.26) | ❌ | -| [快看漫画](https://apps.apple.com/app/id906936224) | [KKMH.js](https://github.com/NobyDa/Script/blob/master/KuaiKan-DailyBonus/KKMH.js) | ✅(2022.1.26) | ✅ | -| [哔哩哔哩漫画](https://apps.apple.com/app/id1426252715) | [Manga.js](https://github.com/NobyDa/Script/blob/master/Bilibili-DailyBonus/Manga.js) | ✅(2022.1.26) | ✅ | -| [巴哈姆特](https://www.gamer.com.tw/) | [BahamutDailyBonus.js](https://github.com/NobyDa/Script/blob/master/Bahamut/BahamutDailyBonus.js) | ✅(2022.1.26) | ✅ | +| Application | Script name | Available | Maintenance | +| :-----------------------------------------------------: | :----------------------------------------------------------: | :------------: | :---------: | +| [京东商城](https://apps.apple.com/app/id414245413) | [JD_DailyBonus.js](https://github.com/NobyDa/Script/blob/master/JD-DailyBonus/JD_DailyBonus.js) | ❌ | ⚠️ | +| [百度贴吧](https://apps.apple.com/app/id477927812) | [TieBa.js](https://github.com/NobyDa/Script/blob/master/BDTieBa-DailyBonus/TieBa.js) | ✅ (2023/08/17) | ❌ | +| [吾爱破解](https://www.52pojie.cn/) | [52pojie.js](https://github.com/NobyDa/Script/blob/master/52pojie-DailyBonus/52pojie.js) | ❌ | ❌ | +| [爱奇艺](https://apps.apple.com/cn/app/id393765873) | [iQIYI.js](https://github.com/NobyDa/Script/blob/master/iQIYI-DailyBonus/iQIYI.js) | ✅ (2023/08/17) | ✅ | +| [快看漫画](https://apps.apple.com/app/id906936224) | [KKMH.js](https://github.com/NobyDa/Script/blob/master/KuaiKan-DailyBonus/KKMH.js) | ✅ (2023/08/17) | ✅ | +| [哔哩哔哩漫画](https://apps.apple.com/app/id1426252715) | [Manga.js](https://github.com/NobyDa/Script/blob/master/Bilibili-DailyBonus/Manga.js) | ✅ (2023/08/17) | ✅ | +| [巴哈姆特](https://www.gamer.com.tw/) | [BahamutDailyBonus.js](https://github.com/NobyDa/Script/blob/master/Bahamut/BahamutDailyBonus.js) | ✅ (2023/08/17) | ✅ | ------ -### Functionality-enhancing scripts +### Functionality-enhancing Script -| Script name | Main Functions | Maintenance | -| :----------------------------------------------------------: | :----------------------------------------------------------: | :---------: | -| [PolicySwitch.js](https://github.com/NobyDa/Script/blob/master/Shortcuts/PolicySwitch.js) | Switch [QX](https://apps.apple.com/app/id1443988620),[Surge](https://apps.apple.com/app/id1442620678),[Loon](https://apps.apple.com/app/id1373567447) policy groups using ios [shortcut](https://apps.apple.com/app/id1462947752). | ✅ | -| [DataQuery.js](https://github.com/NobyDa/Script/blob/master/Sub-store-parser/DataQuery.js) | Server(VPN) traffic query based on [Sub-Store](https://github.com/Peng-YM/Sub-Store). | ✅ | -| [Bili_Auto_Regions.js](https://github.com/NobyDa/Script/blob/master/Surge/JS/Bili_Auto_Regions.js) | [Bilibili anime](https://apps.apple.com/cn/app/id736536022) auto switch region & show [douban](https://www.douban.com/) rating. | ✅ | -| [ExchangePoints.js](https://github.com/NobyDa/Script/blob/master/Bilibili-DailyBonus/ExchangePoints.js) | [Bilibili manga](https://apps.apple.com/app/id1426252715) points mall auto snap up. | ✅ | +| Script name | Description | +|:-------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| +| [PolicySwitch.js](https://github.com/NobyDa/Script/blob/master/Shortcuts/PolicySwitch.js) | Switch [QX](https://apps.apple.com/app/id1443988620),[Surge](https://apps.apple.com/app/id1442620678),[Loon](https://apps.apple.com/app/id1373567447) policy groups using ios [shortcut](https://apps.apple.com/app/id1462947752). | +| [DataQuery.js](https://github.com/NobyDa/Script/blob/master/Sub-store-parser/DataQuery.js) | Server(VPN) traffic query based on [Sub-Store](https://github.com/Peng-YM/Sub-Store). | +| [Bili_Auto_Regions.js](https://github.com/NobyDa/Script/blob/master/Surge/JS/Bili_Auto_Regions.js) | [Bilibili anime](https://apps.apple.com/cn/app/id736536022) auto switch region & show [douban](https://www.douban.com/) rating. | +| [ExchangePoints.js](https://github.com/NobyDa/Script/blob/master/Bilibili-DailyBonus/ExchangePoints.js) | [Bilibili Comics](https://apps.apple.com/app/id1426252715) points mall auto snap up. | +| [TestFlightAccount.js](https://github.com/NobyDa/Script/blob/master/TestFlight/TestFlightAccount.js) | Merge and share [TestFlight](https://apps.apple.com/app/id899247664) accounts | +| [Google_CAPTCHA.js](https://github.com/NobyDa/Script/blob/master/Surge/JS/Google_CAPTCHA.js) | Google CAPTCHA solution(Surge only) | --- - - -### Other scripts - -| Application | Script name | Main Functions | Available | Maintenance | -| :----------------------------------------------------------: | :----------------------------------------------------------: | :---------------------: | :---------: | :---------: | -| [Bigshot](https://apps.apple.com/app/id1274910157) | [dapian.js](https://github.com/NobyDa/Script/blob/master/QuantumultX/File/dapian.js) | Unlock membership | ✅(2021.7.3) | ❌ | -| [VSCO](https://apps.apple.com/app/id588013838) | [vsco.js](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/vsco.js) | Unlock membership | ✅(2021.7.3) | ✅ | -| [JibJab](https://apps.apple.com/app/id875561136) | [jibjab.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/jibjab.js) | Unlock membership | ✅(2021.7.3) | ❌ | -| [NiChi](https://apps.apple.com/app/id1442041390) | [NiChi.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/NiChi.js) | Unlock material pack | ✅(2021.7.3) | ❌ | -| [美易Picsart](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/PicsArt.js) | [PicsArt.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/PicsArt.js) | Unlock membership | ✅(2021.7.3) | ✅ | -| [MIX滤镜大师](https://apps.apple.com/app/id913947918) | [MIX.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/MIX.js) | Unlock in-app purchases | ✅(2021.7.6) | ❌ | -| [Polarr 泼辣](https://apps.apple.com/app/id988173374) | [Polarr.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Polarr.js) | Unlock in-app purchases | ✅(2021.7.6) | ❌ | -| [小影VivaVideo](https://apps.apple.com/app/id738897668) | [vivavideo.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/vivavideo.js) | Unlock membership | ✅(2021.7.3) | ❌ | -| [CamScanner](https://apps.apple.com/app/id388627783) | [CamScanner.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/CamScanner.js) | Unlock some benefits | ❌ | ❌ | -| [酷我音乐](https://apps.apple.com/cn/app/id588673713) | [Kuwo.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Kuwo.js) | Unlock vip listen | ✅(2021.7.3) | ❌ | -| [知音漫客](https://apps.apple.com/app/id1012491820) | [Zymh.js](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/Zymh.js) | Unlock vip chapters | ✅(2021.7.3) | ✅ | -| [91短视频](http://download.91porn.love/) | [91.js](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/91.js) | Unlock membership | ✅(2021.7.3) | ❌ | -| [香蕉视频](https://www.aa2.app) | [xjsp.js](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/xjsp.js) | Unlock membership | ✅(2021.7.3) | ❌ | -| [爱美剧](https://www.mjapp.cc) | [aimeiju.js](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/aimeiju.js) | Unlock membership | ✅(2021.7.3) | ❌ | -| [网易蜗牛读书](https://apps.apple.com/app/id1127249355) | [wnyd.js](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/wnyd.js) | Unlock membership | ✅(2021.7.3) | ❌ | -| [陆琪讲故事](https://apps.apple.com/app/id1435575842) | [luqi.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/luqi.js) | Unlock radio | ✅(2021.7.3) | ❌ | -| [WPS Office](https://apps.apple.com/app/id1491101673) | [Wps.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Wps.js) | Unlock membership | ✅(2021.7.3) | ❌ | -| [百度网盘](https://apps.apple.com/app/id547166701) | [BaiduCloud.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/BaiduCloud.js) | Unlock video speed | ✅(2021.7.6) | ❌ | -| [WeChat](https://apps.apple.com/app/id414478124) | [Wechat.js](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/Wechat.js) | Remove ads | ✅(2021.7.3) | ❌ | -| [皮皮虾](https://apps.apple.com/cn/app/id1393912676) | [Super.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Super.js) | Remove ads | ✅(2021.7.3) | ❌ | +### Other Script + +| Application | Script name | Description | Available | +| :----------------------------------------------------------: | :----------------------------------------------------------: | :---------------------: | :------------: | +| [HTTPBot](https://apps.apple.com/cn/app/id1232603544) | [vsco.js](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/vsco.js) | Unlock membership | ✅ (2023/08/17) | +| [VSCO](https://apps.apple.com/app/id588013838) | [vsco.js](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/vsco.js) | Unlock membership | ✅ (2023/08/17) | +| [1Blocker](https://apps.apple.com/app/id1365531024) | [vsco.js](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/vsco.js) | Unlock membership | ✅ (2023/08/17) | +| [JibJab](https://apps.apple.com/app/id875561136) | [jibjab.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/jibjab.js) | Unlock membership | ✅ (2023/08/17) | +| [美易Picsart](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/PicsArt.js) | [PicsArt.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/PicsArt.js) | Unlock membership | ✅ (2023/08/17) | +| [MIX滤镜大师](https://apps.apple.com/app/id913947918) | [MIX.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/MIX.js) | Unlock in-app purchases | ✅ (2023/08/17) | +| [Polarr 泼辣](https://apps.apple.com/app/id988173374) | [Polarr.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Polarr.js) | Unlock in-app purchases | ✅ (2023/08/17) | +| [小影VivaVideo](https://apps.apple.com/app/id738897668) | [vivavideo.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/vivavideo.js) | Unlock membership | ✅ (2023/08/17) | +| [CamScanner](https://apps.apple.com/app/id388627783) | [CamScanner.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/CamScanner.js) | Unlock some benefits | ✅ (2023/08/17) | +| [知音漫客](https://apps.apple.com/app/id1012491820) | [Zymh.js](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/Zymh.js) | Unlock vip chapters | ✅ (2023/08/17) | +| [香蕉视频](https://www.aa2.app) | [xjsp.js](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/xjsp.js) | Unlock membership | ✅ (2023/08/17) | +| [网易蜗牛读书](https://apps.apple.com/app/id1127249355) | [wnyd.js](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/wnyd.js) | Unlock membership | ✅ (2023/08/17) | +| [陆琪讲故事](https://apps.apple.com/app/id1435575842) | [luqi.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/luqi.js) | Unlock radio | ✅ (2023/08/17) | +| [百度网盘](https://apps.apple.com/app/id547166701) | [BaiduCloud.js](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/BaiduCloud.js) | Unlock video speed | ✅ (2023/08/17) | +| [WeChat](https://apps.apple.com/app/id414478124) | [Wechat.js](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/Wechat.js) | Remove Ads | ✅ (2023/08/17) | +| [動畫瘋](https://apps.apple.com/tw/app/id1102650114) | [BahamutAnimeAds.js](https://raw.githubusercontent.com/NobyDa/Script/master/Bahamut/BahamutAnimeAds.js) | Remove Ads | ✅ (2023/08/17) | --- +## Surge File Overview +| File name | Description | Type | +| :----------------------------------------------------------: | :----------------------------------------------------------: | ------ | +| [HuiJuDongManAds.sgmodule](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/HuiJuDongManAds.sgmodule) | Remove [APP](https://apps.apple.com/app/id1451949669) Ads | Module | +| [IPA_install.sgmodule](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/IPA_install.sgmodule) | Use Surge to assist in install IPA (signed version) | Module | +| [TestFlightDownload.sgmodule](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/TestFlightDownload.sgmodule) | Remove [TestFlight](https://apps.apple.com/app/id899247664) region restrictions | Module | +| [TestFlightAccount.sgmodule](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/TestFlightAccount.sgmodule) | Merge and share [TestFlight](https://apps.apple.com/app/id899247664) accounts | Module | +| [GetCookie.sgmodule](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/GetCookie.sgmodule) | Daily bonus script related | Module | +| [BahamutAnimeAds.sgmodule](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/BahamutAnimeAds.sgmodule) | Remove [Bahamut anime](https://apps.apple.com/tw/app/id1102650114) Ads | Module | -## Surge file desc +--- -### Surge ruleset +## QuantumultX File Overview -| File name | Number | Integrate | Desc | Maintenance | -| :----------------------------------------------------------: | :----: | :----------------------------------------------------------: | :-------------------------------: | :---------: | -| [AdRule.list](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/AdRule.list) | 8000+ | [lhie1](https://github.com/lhie1/Rules), [ConnersHua](https://github.com/ConnersHua/Profiles) | Private ad ruleset | ❌ | -| [AdRuleTest.list](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/AdRuleTest.list) | 1300+ | [Scomper](https://github.com/scomper/Surge) | Private ad ruleset (test only). | ❌ | -| [WeChat.list](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/WeChat.list) | 180+ | N/A | WeChat ruleset (china) | ✅ | -| [Apple.list](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Apple.list) | 60+ | N/A | Apple ruleset (global) | ✅ | -| [Download.list](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Download.list) | 15+ | N/A | Some BT, Thunder, download rules. | ❌ | +| File name | Description | Type | +|:---------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------:|:-----------------:| +| [Js.conf](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Js.conf) | Remote script subscription. | Rewrite Resources | +| [Js_Remote_Cookie.conf](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Js_Remote_Cookie.conf) | Daily bonus script related | Rewrite Resources | +| [TestFlightDownload.conf](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/TestFlightDownload.conf) | Remove [TestFlight](https://apps.apple.com/app/id899247664) region restrictions | Rewrite Resources | +| [IPA-Installer.snippet](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/IPA-Installer.snippe) | Use QX to assist in install IPA (signed version) | Rewrite Resources | -### Surge module +Rules of type "Rule" include only ad hosts. Please select the REJECT policy. -| Module name | Desc | Maintenance | -| :----------------------------------------------------------: | :----------------------------------------------------------: | :---------: | -| [RewriteRules.sgmodule](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/RewriteRules.sgmodule) | Private ad rewrite rules, integrate [lhie1](https://github.com/lhie1/Rules)、[ConnersHua](https://github.com/ConnersHua/Profiles)、[onewayticket255](https://github.com/onewayticket255/Surge-Script) and [Choler](https://github.com/Choler/Surge/tree/master/Ruleset). | ❌ | -| [HuiJuDongManAds.sgmodule](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/HuiJuDongManAds.sgmodule) | Please see the desc in module. | ✅ | -| [IPA_install.sgmodule](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/IPA_install.sgmodule) | Use Surge to assist in install IPA (signed version) | ❌ | -| [TestFlightDownload.sgmodule](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/TestFlightDownload.sgmodule) | Please see the desc in module. | ✅ | -| [GetCookie.sgmodule](https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/GetCookie.sgmodule) | Please see the desc in module. | ✅ | +
Difference between QuantumultX versions (Click to view) ---- +* AppStore version QX1.0.0 (120): This is the initial version, and JS functionality is unrestricted. -## QuantumultX file desc +* AppStore version QX1.0.1 (130): This version adds support for V2Ray protocols but restricts certain keywords for VIP-type scripts. -| Name | Integrate | Number | Desc | Type | Maintenance | -| :----------------------------------------------------------: | :----------------------------------------------------------: | :----: | :---------------------------: | :-----: | :---------: | -| [AdRule.list](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/AdRule.list) | [lhie1](https://github.com/lhie1/Rules) | 7000+ | Private ad rules. | Rule | ❌ | -| [AdRuleTest.list](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/AdRuleTest.list) | [Scomper](https://github.com/scomper/Surge) | 1300+ | Private ad rules (test only). | Rule | ❌ | -| [Rewrite_lhie1.conf](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Rewrite_lhie1.conf) | [lhie1](https://github.com/lhie1/Rules)、[onewayticket255](https://github.com/onewayticket255/Surge-Script)、[Choler](https://github.com/Choler/Surge/tree/master/Ruleset) | 400+ | Private rewrite rules. | Rewrite | ❌ | -| [Js.conf](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Js.conf) | N/A | N/A | Remote script subscription. | Rewrite | ✅ | -| [Js_Remote_Cookie.conf](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Js_Remote_Cookie.conf) | N/A | N/A | Please see the desc in file. | Rewrite | ✅ | -| [TestFlightDownload.conf](https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/TestFlightDownload.conf) | N/A | N/A | Please see the desc in file. | Rewrite | ✅ | +* AppStore version QX1.0.2 (136): This version adds support for HTTP protocols and relaxes certain script keyword restrictions but restricts remote script subscriptions. -Rules of type "Rule" include only ad hosts. Please select the REJECT policy. +* AppStore version QX1.0.3 (155): This version removes keyword restrictions and restores the script remote subscription functionality. However, the device ID must be commented out in the remote script before execution. +* AppStore version QX1.0.4 (164): This version completely restricts remote script subscriptions, requiring all scripts to use local paths. -
Difference between QuantumultX versions (Click to view) +* AppStore version QX1.0.5 (192): This version introduces a scheduled script task feature. -* AppStore version QX1.0.0 (120) This version is the initial version, JS function is unlimited. -* AppStore version QX1.0.1 (130) This version adds support V2Ray(protocols), but restricts the keywords of the script VIP type. +* AppStore version QX1.0.6 (212): This version supports modifying HTTP request body and replaying HTTP requests. + +* AppStore version QX1.0.7 (240): This version supports TLS 1.3 (TLS-based proxy protocol) and Trojan protocols. -* AppStore version QX1.0.2 (136) This version adds support HTTP(protocols) and relaxes certain script keyword restrictions, but restricts script remote subscriptions -* AppStore version QX1.0.3 (155) This version removes the keyword restriction and restores the script remote subscription, however, the remote script needs to comment the device ID before execution. -* AppStore version QX1.0.4 (164) This version completely restricts remote script subscriptions, meaning that all scripts can only use local paths. -* AppStore version QX1.0.5 (192) This version adds a timed script task function. -* AppStore version QX1.0.6 (212) This version supports modifying HTTP request body, and replaying HTTP request. -* AppStore version QX1.0.7 (240) This version supports TLS 1.3 (TLS-based proxy protocol), and Trojan(protocols). * ... -* AppStore version QX1.0.10 (313) In this version, script remote subscription has been restored. -QX1.0.3 add device ID, a simple example: +* AppStore version QX1.0.10 (313): This version restores remote script subscriptions. + +In QX1.0.3, the device ID feature was added. Here’s a simple example: -```ini +```javascript /** * @supported 23AD6B11CD4B */ @@ -144,65 +131,65 @@ obj["example"] = 0; $done({body:JSON.stringify(obj)}) ``` -The above random generated device ID can be found at the bottom of Quantumult X additional menu, and it may change after system restore. +The randomly generated device ID above is located at the bottom of the Quantumult X additional menu and may change after a system restore.
--- -## Loon file desc +## Loon File Overview -| File name | Desc | Type | Maintenance | -| :----------------------------------------------------------: | :-----------------------------: | :------------------: | :---------: | -| [Loon_GetCookie.conf](https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_GetCookie.conf) | Please see the desc in file. | Subscription scripts | ✅ | -| [Loon_GetTask.conf](https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_GetTask.conf) | Timed script task subscription. | Subscription scripts | ✅ | -| [Loon_TF_Download.conf](https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_TF_Download.conf) | Please see the desc in file. | Subscription scripts | ✅ | +| File name | Description | Type | +| :----------------------------------------------------------: | :----------------------------------------------------------: | :----: | +| [Loon_GetCookie.plugin](https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_GetCookie.plugin) | Daily bonus script related | Plugin | +| [Loon_TF_Download.plugin](https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_TF_Download.plugin) | Remove [TestFlight](https://apps.apple.com/app/id899247664) region restrictions | Plugin | +| [Loon_TF_Account.plugin](https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_TF_Account.plugin) | Merge and share [TestFlight](https://apps.apple.com/app/id899247664) accounts | Plugin | +| [Loon_Bahamut_ADS.plugin](https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_Bahamut_ADS.plugin) | Remove [Bahamut anime](https://apps.apple.com/tw/app/id1102650114) Ads | Plugin | +| [Loon_IPA_Installer.plugin](https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_IPA_Installer.plugin) | Use Loon to assist in install IPA (signed version) | Plugin | +--- +## Stash File Overview + +| File name | Description | Type | +|:-----------------------------------------------------------------------------------------------------------------:|:---------------------------------------------------:|:--------:| +| [IPA-Installer.stoverride](https://raw.githubusercontent.com/NobyDa/Script/master/Stash/IPA-Installer.stoverride) | Use Stash to assist in install IPA (signed version) | Override | --- ## Disclaimer -``` -In the following disclaimer : - -"Script project" specifically refers to the open source scripts and rules in https://github.com/NobyDa/Script/tree/master - -"NobyDa" specifically refers to the author and owner in https://github.com/NobyDa/Script/tree/master -``` +Please note that in the following disclaimer, the term "Script-project" specifically refers to the open source scripts and rules available at "https://github.com/NobyDa/Script", while the term "NobyDa" specifically refers to the author and owner of these scripts and rules. ### Decrypt -1. Any unlocking and decryption analysis scripts involved in the "Script project" are for resource sharing and study purposes only. - -2. Legality, accuracy, completeness, and validity cannot be guaranteed. **Please judge for yourself based on the actual situation.** +- Any scripts within the Script-project that involve unlocking and decrypting are intended for resource sharing and study purposes only. The legality, accuracy, completeness, and validity of these scripts cannot be guaranteed. **Therefore, please use your own judgment based on the actual situation.** -3. You must completely delete the scripts involving decryption from your computer or phone within **24 hours** of downloading. +- You are required to delete the decryption scripts from your computer or phone completely within **24 hours** of downloading them. ### Privacy -1. Any user who indirectly uses any of the scripts in the "Script project", including but not limited to violating relevant laws and regulations or establishing VPS to spread, **NobyDa is not responsible for any privacy leakage or other consequences caused by this.** +- NobyDa is not responsible for any privacy breaches or other consequences arising from the direct or indirect use of any of the scripts in the Script-project, including but not limited to violating relevant laws and regulations or establishing a VPS for distribution purposes. ### Commercial -1. Do not use any scripts of the "Script project" for commercial or illegal purposes, **otherwise you will be responsible for the consequences.** +- Do not use any scripts from the Script-project for commercial or illegal purposes, **or you will bear full responsibility for the consequences that may arise**. -### Nfringement +### Infringement -1. If any company or individual believes that a scripts from "Script project" may be infringe on rights, you should promptly notify and provide proof of **identity** and **ownership**, and we will delete the scripts after receiving the relevant documents. +- If any company or individual believes that any script in the Script-project may infringe on their rights, they should promptly notify us and provide proof of **ownership** and **identity**. We will delete the relevant scripts upon receipt of the necessary documents. ### Liability -1. NobyDa is not responsible for any scripts problems, **including but not limited to any loss or damage caused by any scripting errors.** +- NobyDa is not responsible for any problems with the Script-project, **including but not limited to any loss or damage caused by any scripting errors.** ### Change -1. Anyone viewing or using the scripts of the "Script project" in any way, directly or indirectly, should read this statement carefully. And NobyDa reserves the right to change or supplement this disclaimer at any time. +- Anyone who views or uses the scripts in the Script-project, whether directly or indirectly, should carefully read this disclaimer. NobyDa reserves the right to change or supplement this disclaimer at any time. -2. **Once you use or copy any related scripts of the "Script project", you will be deemed to have accepted this disclaimer.** +- **By viewing, using, or copying any of the related scripts in the Script-project, you will be deemed to have accepted this disclaimer.** -## Special thanks to +## Acknowledgment * [@sazs34](https://github.com/sazs34) * [@lhie1](https://github.com/lhie1) diff --git a/Rule-Storage/Include-Domain.txt b/Rule-Storage/Include-Domain.txt new file mode 100644 index 0000000000..e458138659 --- /dev/null +++ b/Rule-Storage/Include-Domain.txt @@ -0,0 +1,26 @@ +DOMAIN-KEYWORD,.a +DOMAIN-KEYWORD,.b +DOMAIN-KEYWORD,.c +DOMAIN-KEYWORD,.d +DOMAIN-KEYWORD,.e +DOMAIN-KEYWORD,.f +DOMAIN-KEYWORD,.g +DOMAIN-KEYWORD,.h +DOMAIN-KEYWORD,.i +DOMAIN-KEYWORD,.j +DOMAIN-KEYWORD,.k +DOMAIN-KEYWORD,.l +DOMAIN-KEYWORD,.m +DOMAIN-KEYWORD,.n +DOMAIN-KEYWORD,.o +DOMAIN-KEYWORD,.p +DOMAIN-KEYWORD,.q +DOMAIN-KEYWORD,.r +DOMAIN-KEYWORD,.s +DOMAIN-KEYWORD,.t +DOMAIN-KEYWORD,.u +DOMAIN-KEYWORD,.v +DOMAIN-KEYWORD,.w +DOMAIN-KEYWORD,.x +DOMAIN-KEYWORD,.y +DOMAIN-KEYWORD,.z \ No newline at end of file diff --git a/Rule-Storage/Rule-Storage.js b/Rule-Storage/Rule-Storage.js new file mode 100644 index 0000000000..56f56a3293 --- /dev/null +++ b/Rule-Storage/Rule-Storage.js @@ -0,0 +1,159 @@ +/* +Surge规则自动生成脚本 +更新时间:2024/08/11 + +需按照博客内教程配合使用: +https://nobyda.github.io/2024/02/24/Surge_Rule_Storage + +*/ + +const args = argsList(typeof $argument == "string" && $argument || 'region=debug'); +/* +When matching whitelist rules, skip generating suffix domain. Three ways to write: +Domain: example.com +Domain suffix: .example.com +Domain keyword: .example. +*/ +args.whitelist = args.whitelist || `[".mwcname.com", ".akadns.", ".akamai.", ".cloud.", ".cdn.", ".yun."]`; +args.key = args.key || 'Rule-Storage'; + +(async () => { + const host = $request.hostname.toLowerCase(); + const inHost = $request.listenPort == 6152 && !$request.sourcePort && !$request.processPath && /^[a-z0-9]{10}\.[a-z]+$/.test(host); //Prevent benchmark + if (['127.0.0.1', '0.0.0.0'].filter((v) => [...($request.dnsResult || {}).v4Addresses || []].includes(v)).length) { + // DNS poisoning + args.matched = false; + args.region = 'global'; + } + if (!/\d$|:/.test(host) && host.includes('.') && !inHost) { + const data = JSON.parse($persistentStore.read(args.key) || '{}'); + const saved_rules = $persistentStore.read(`${args.key}-${args.region}`); + if (!evalRules(host, saved_rules)) { + data[args.region] = saveDecision(host, data[args.region]); + if (data[args.region][host].quantity >= (args.quantity || 10)) { + const eTLDs = await eTLD(data.eTLD || JSON.parse($persistentStore.read(`${args.key}-eTLD`) || '{}')); + if (data.eTLD) { // legacy + $persistentStore.write(JSON.stringify(data.eTLD), `${args.key}-eTLD`); + delete data.eTLD; + } + const suffix = shortenDomain(host, eTLDs.public_suffix); + const domain = evalRules(host, JSON.parse(args.whitelist)) ? host : suffix; + const text = [...formatRules(saved_rules), ...formatRules(domain)].join('\n'); + delete data[args.region][host]; + $persistentStore.write(text, `${args.key}-${args.region}`) + } + } + return $persistentStore.write(JSON.stringify(data), args.key) + } +})().catch((e) => $notification.post(args.key, ``, e.message || e)) + .finally(() => $done({ matched: Boolean(args.matched) })); + +function saveDecision(host_name, content = {}) { + const count = []; + for (const i in content) { + if (Date.now() - content[i].update_time > 86400000 * (args.cacheDays || 30)) { + delete content[i]; + continue + } + count.push(content[i].update_time); + } + if (count.length > (args.cacheNumber || 1000)) { // limit amount to prevent NE memory issues. + const spill = count.sort((x, y) => x - y).slice(0, count.length - (args.cacheNumber || 1000)); + for (const is of spill) { + for (const ic in content) { + if (content[ic].update_time === is) { + delete content[ic]; + break + } + } + } + } + if (content[host_name]) { + if (Date.now() - content[host_name].update_time > ((args.interval || 30) * 1000)) { + content[host_name].update_time = Date.now(); + content[host_name].quantity++; + } + } else { + content[host_name] = { update_time: Date.now(), quantity: 1 } + } + return content +} + +function evalRules(host_name, rule_list) { + const host_suffix = host_name.split('.').reverse(); + rule_list = typeof rule_list == 'object' ? rule_list : formatRules(rule_list, 1); + for (const i in rule_list) { + if (rule_list[i].startsWith('.') && !rule_list[i].endsWith('.')) { + const rule_host_suffix = rule_list[i].split('.').reverse().filter((v) => v); + if (rule_host_suffix.filter((v, i) => host_suffix[i] === v).length === rule_host_suffix.length) { + return true + } + } else if (rule_list[i].startsWith('.') && rule_list[i].endsWith('.')) { + if (host_name.includes(rule_list[i].slice(1, -1))) { + return true + } + } else if (rule_list[i] === host_name) { + return true + } + } + return false +} + +function formatRules(list, type) { + return (list || '').replace(/\r|\ |(\/\/|#|;).*/g, '').split('\n').map((v) => { + if (v.startsWith('DOMAIN,')) { return type ? v.split(",")[1] : v } + if (v.startsWith('DOMAIN-SUFFIX,')) { return type ? `.${v.split(",")[1]}` : v } + if (v.startsWith('.')) { return type ? v : `DOMAIN-SUFFIX,${v.slice(1)}` } + if (v.includes('.')) { return type ? v : `DOMAIN,${v}` } + }).filter((v) => v); +} + +async function eTLD(content = {}) { + if (!content.update_time || (Date.now() - content.update_time > 86400000 * 30)) { + await new Promise(resolve => { + $httpClient.get({ + url: 'https://publicsuffix.org/list/public_suffix_list.dat' + }, (error, resp, body) => { + if (resp.status == 200 && !error && body) { + content.update_time = Date.now(); + content.public_suffix = body.replace(/\r|.*(\/\/|#|;).*|\n(\!|\*\.)/g, '\n').split('\n').filter((t) => t); + $persistentStore.write(JSON.stringify(content), `${args.key}-eTLD`); + resolve() + } else if (content.update_time) { + console.log(`Update eTLD list failed: ${error}`); + resolve() + } else { + throw new Error(`Download eTLD list failed: ${error}`) + } + }) + }) + } + return content +} + +/* +Shorten multi level domain: non-eTLD, full eTLD, second level domain will return original +Basic logic: www.abc.com -> .abc.com +*/ +function shortenDomain(host_name, eTLD_list) { + return host_name.split('.').reverse().reduce((t, v, i, c) => { + if (t === host_name || c.length == 2) { return host_name } + if (t.startsWith('.')) { return t } + const host_suffix = v + (t && `.${t}` || ''); + for (const ix in eTLD_list) { + if (eTLD_list[ix] === host_suffix) { + return host_suffix + } + } + return !i && host_name || `.${host_suffix}` + }, '') +} + +function argsList(data) { + return Array.from( + data.split("&") + .map((i) => i.split("=")) + .map(([k, v]) => [k, decodeURIComponent(v)]) + ) + .reduce((a, [k, v]) => Object.assign(a, { [k]: v }), {}) +} \ No newline at end of file diff --git a/Shortcuts/PolicySwitch.js b/Shortcuts/PolicySwitch.js index 05c41fa5d8..432e867398 100644 --- a/Shortcuts/PolicySwitch.js +++ b/Shortcuts/PolicySwitch.js @@ -36,7 +36,7 @@ const body = JSON.parse($request.body || '{}'); })() function nobyda() { - const isLoon = typeof($loon) !== "undefined" && $loon > 289; + const isLoon = typeof($loon) !== "undefined"; const isQuanX = typeof($configuration) !== 'undefined'; const isSurge = typeof($httpAPI) !== 'undefined'; const m = `不支持您的APP版本, 请等待APP更新 ⚠️`; diff --git a/Stash/IPA-Installer.stoverride b/Stash/IPA-Installer.stoverride new file mode 100644 index 0000000000..29dd32268c --- /dev/null +++ b/Stash/IPA-Installer.stoverride @@ -0,0 +1,16 @@ +name: IPA应用辅助安装器 +desc: 该模块可在iOS端辅助安装商店版或已签名IPA(需使用快捷指令 + Shu/Jsbox/pythonista), 查看脚本注释以了解具体方法; 安装演示可查看TG频道 @NobyDa + +http: + mitm: + - nobyda.app + script: + - match: ^https:\/\/nobyda.app/(install|download) + name: IPA-Installer + type: request + require-body: true + timeout: 10 +script-providers: + IPA-Installer: + url: https://raw.githubusercontent.com/NobyDa/Script/master/IPA-Installer/IPA-Installer.js + interval: 86400 \ No newline at end of file diff --git a/Sub-store-parser/DataQuery.js b/Sub-store-parser/DataQuery.js index a35b1dacfe..22e96bc1fc 100644 --- a/Sub-store-parser/DataQuery.js +++ b/Sub-store-parser/DataQuery.js @@ -5,6 +5,7 @@ Sub-Store外置流量查询脚本 该脚本基于Sub-Store, 可解决APP使用Sub-Store链接后, 没有流量通知的问题. 使用前需确认您的机场订阅是否支持流量信息. (注:节点名流量信息暂不支持) Sub-Store订阅管理器: https://github.com/Peng-YM/Sub-Store +最后更新: 2022.6.12 测试兼容: QuantumultX, Surge, Loon. 使用方法: 打开Sub-Store => 订阅 => 编辑 => 节点操作+ => 脚本操作 => 填入脚本链接或粘贴脚本 => 保存 @@ -14,50 +15,52 @@ Sub-Store订阅管理器: https://github.com/Peng-YM/Sub-Store ******************************/ -function operator(proxies) { - try { - if ($request.headers["User-Agent"].match(/Quantumult|Surge|Loon|Decar/) && !$.raw_Name) { - const rawInfo = $.read('subs'); - const readName = $.read('collections'); - const subtag = $request.url.match(/download\/(collection\/)?([\w-_]*)/)[2]; - if ($request.url.match(/\/collection\//)) { //collection subscription. - const isOpen = readName[subtag].process.map(o => o.type).indexOf("Script Operator") != -1; - for (var i = 0; i < readName[subtag].subscriptions.length; i++) { - $.raw_Name = readName[subtag].subscriptions[i]; - if (!isOpen) break; //prevent queries in certain cases. - AllSubs(rawInfo[$.raw_Name].url, $.raw_Name); +async function operator(proxies, client) { + if (['JSON', 'URI'].includes(client)) return proxies; + const $ = $substore; //OpenAPI in Sub-Store + const single = $.read('subs'); + const collection = $.read('collections'); + const subtag = decodeURIComponent($request.url.split(/download\/(collection\/|)(.*)/)[2]); + const group = []; + if ($request.url.includes('/collection/')) { //collection subscription. + const deployed = collection[subtag].process.filter((c) => c.type == 'Script Operator' && c.args.content.includes('/DataQuery.js')).length; + for (let i = 0; i < collection[subtag].subscriptions.length; i++) { + if (deployed) group.push({ + name: collection[subtag].subscriptions[i], url: single[collection[subtag].subscriptions[i]].url + }); } - } else { //single subscription. - $.raw_Name = rawInfo[subtag].name; - AllSubs(rawInfo[subtag].url, $.raw_Name); - } + } else { //single subscription. + group.push({ name: single[subtag].name, url: single[subtag].url }) } - } catch (err) { - $.error(`\n🔹 订阅昵称:「 ${$.raw_Name||'未知'} 」\n🔺 查询失败:「 ${err.message||err} 」`); - } finally { + await Promise.all( + group.map((c) => $.http.get(c.url) + .then((r) => { + const t = parseInfo(r); + $.notify( + `🔹 订阅昵称:「 ${c.name} 」`, + t.expire ? `🔹 过期时间:「 ${t.expire} 」` : ``, + `🔸 已用流量:「 ${t.used} GB 」\n🔸 剩余流量:「 ${t.free} GB 」` + ); + }) + .catch((e) => $.notify(`🔹 订阅昵称:「 ${c.name} 」`, ``, `🔺 查询失败:「 ${e.message || e} 」`)) + ) + ) return proxies; - } } -async function AllSubs(subsUrl, subsName) { - try { //reference to https://github.com/KOP-XIAO/QuantumultX/blob/master/Scripts/resource-parser.js - var resp = await $.http.get(subsUrl); +function parseInfo(resp) { //reference to https://github.com/KOP-XIAO/QuantumultX/blob/master/Scripts/resource-parser.js var sinfo = JSON.stringify(resp.headers || '').replace(/ /g, "").toLowerCase(); - if (sinfo.indexOf("total=") == -1 || sinfo.indexOf("download=") == -1) throw new Error('该订阅不包含流量信息'); - var total = (parseFloat(sinfo.split("total=")[1].split(",")[0]) / (1024 ** 3)).toFixed(0); + if (sinfo.indexOf("total=") == -1 && sinfo.indexOf("download=") == -1) + throw new Error('该订阅不包含流量信息'); + // var total = (parseFloat(sinfo.split("total=")[1].split(",")[0]) / (1024 ** 3)).toFixed(0); var usd = ((parseFloat(sinfo.indexOf("upload") != -1 ? sinfo.split("upload=")[1].split(",")[0] : "0") + parseFloat(sinfo.split("download=")[1].split(",")[0])) / (1024 ** 3)).toFixed(2); var left = ((parseFloat(sinfo.split("total=")[1].split(",")[0]) / (1024 ** 3)) - ((parseFloat(sinfo.indexOf("upload") != -1 ? sinfo.split("upload=")[1].split(",")[0] : "0") + parseFloat(sinfo.split("download=")[1].split(",")[0])) / (1024 ** 3))).toFixed(2); if (sinfo.indexOf("expire=") != -1) { - var epr = new Date(parseFloat(sinfo.split("expire=")[1].split(",")[0]) * 1000); - var year = epr.getFullYear(); - var mth = epr.getMonth() + 1 < 10 ? '0' + (epr.getMonth() + 1) : (epr.getMonth() + 1); - var day = epr.getDate() < 10 ? "0" + (epr.getDate()) : epr.getDate(); - var epr = `🔹 过期时间:「 ${year}-${mth}-${day} 」`; - } else { - var epr = ""; + var epr = new Date(parseFloat(sinfo.split("expire=")[1].split(",")[0]) * 1000); + var year = epr.getFullYear(); + var mth = epr.getMonth() + 1 < 10 ? '0' + (epr.getMonth() + 1) : (epr.getMonth() + 1); + var day = epr.getDate() < 10 ? "0" + (epr.getDate()) : epr.getDate(); + return { expire: `${year}-${mth}-${day}`, used: usd, free: left } } - $.notify(`🔹 订阅昵称:「 ${subsName} 」`, epr, `🔸 已用流量:「 ${usd} GB 」\n🔸 剩余流量:「 ${left} GB 」`); - } catch (er) { - $.error(`\n🔹 订阅昵称:「 ${subsName} 」\n🔺 查询失败:「 ${er.message||er} 」`); - } + return { used: usd, free: left } } \ No newline at end of file diff --git a/Surge/AdRule.list b/Surge/AdRule.list index f8649115d4..4f404985a6 100644 --- a/Surge/AdRule.list +++ b/Surge/AdRule.list @@ -1,4 +1,4 @@ -# Update > 2022.1.26 +# Update > 2023/12/23 DOMAIN-SUFFIX,api-access.pangolin-sdk-toutiao-b.com DOMAIN-SUFFIX,mcupdate.gstarcad.com DOMAIN-SUFFIX,adx.open-adx.com @@ -147,7 +147,6 @@ DOMAIN-SUFFIX,m-78.jp DOMAIN-SUFFIX,nichibenren.or.jp DOMAIN-SUFFIX,nicorette.co.kr DOMAIN-SUFFIX,adnet.sohu.com -DOMAIN-SUFFIX,data.vod.itc.cn DOMAIN-SUFFIX,epro.sogou.com DOMAIN-SUFFIX,go.sohu.com DOMAIN-SUFFIX,golden1.sogou.com @@ -179,7 +178,6 @@ DOMAIN-SUFFIX,ad.video.51togic.com DOMAIN-SUFFIX,biz5.kankan.com DOMAIN-SUFFIX,c.algovid.com DOMAIN-SUFFIX,cms.laifeng.com -DOMAIN-SUFFIX,da.mmarket.com DOMAIN-SUFFIX,dotcounter.douyutv.com DOMAIN-SUFFIX,g.uusee.com DOMAIN-SUFFIX,gcdn.2mdn.net @@ -2023,7 +2021,6 @@ DOMAIN-SUFFIX,cc.yac8.com DOMAIN-SUFFIX,cca.mob.com DOMAIN-SUFFIX,ccb.uncle-ad.com DOMAIN-SUFFIX,ccbaihehq.com -DOMAIN-SUFFIX,ccclub.cmbchina.com DOMAIN-SUFFIX,cccrir.com DOMAIN-SUFFIX,ccr.yxdown.com DOMAIN-SUFFIX,cctyly.com @@ -2063,7 +2060,6 @@ DOMAIN-SUFFIX,cdn.mdotm.com DOMAIN-SUFFIX,cdn.media.innity.net DOMAIN-SUFFIX,cdn.millennialmedia.com DOMAIN-SUFFIX,cdn.mingmingtehui.com -DOMAIN-SUFFIX,cdn.moji.com DOMAIN-SUFFIX,cdn.moji002.com DOMAIN-SUFFIX,cdn.moogos.com DOMAIN-SUFFIX,cdn.ndapp.com @@ -8356,7 +8352,6 @@ DOMAIN-SUFFIX,zunmi.cn DOMAIN-SUFFIX,zzd6.com DOMAIN-SUFFIX,mackeeper.com DOMAIN-SUFFIX,app-measurement.com -DOMAIN-SUFFIX,mob.com DOMAIN-SUFFIX,api.joybj.com DOMAIN-SUFFIX,api.whizzone.com DOMAIN-SUFFIX,mmstat.com diff --git a/Surge/Bilibili.list b/Surge/Bilibili.list new file mode 100644 index 0000000000..662803c9f0 --- /dev/null +++ b/Surge/Bilibili.list @@ -0,0 +1,13 @@ +# 该规则集用于配合bilibili自动地区脚本使用。 +DOMAIN,api.biliapi.com +DOMAIN,api.biliapi.net +DOMAIN,api.bilibili.com +DOMAIN,app.biliapi.com +DOMAIN,app.biliapi.net +DOMAIN,app.bilibili.com +DOMAIN,grpc.biliapi.net +DOMAIN,m.bilibili.com +DOMAIN,upos-hz-mirrorakam.akamaized.net +DOMAIN,www.bilibili.com +DOMAIN-KEYWORD,cn-hk-eq-bcache- +IP-CIDR,121.11.192.0/24,no-resolve \ No newline at end of file diff --git a/Surge/JS/BaiduCloud.js b/Surge/JS/BaiduCloud.js index 90004925ee..68cdcaa774 100644 --- a/Surge/JS/BaiduCloud.js +++ b/Surge/JS/BaiduCloud.js @@ -41,7 +41,7 @@ if ($response.body) { "buy_time": 0, "product_id": "1", "auto_upgrade_to_svip": 0, - "end_time": 1672502399, + "end_time": 1872502399, "cluster": "vip", "detail_cluster": "svip", "status": 0 diff --git a/Surge/JS/Bili_Auto_Regions.js b/Surge/JS/Bili_Auto_Regions.js index 2d6eb639a1..8f16333e47 100644 --- a/Surge/JS/Bili_Auto_Regions.js +++ b/Surge/JS/Bili_Auto_Regions.js @@ -1,11 +1,11 @@ /************************** -哔哩哔哩, 港澳台番剧自动切换地区 & 显示豆瓣评分 +哔哩哔哩(白图标外区版), 港澳台番剧自动切换地区 & 显示豆瓣评分 如需禁用豆瓣评分或策略通知, 可前往BoxJs设置. BoxJs订阅地址: https://raw.githubusercontent.com/NobyDa/Script/master/NobyDa_BoxJs.json -Update: 2022.01.26 +Update: 2023.02.11 Author: @NobyDa Use: Surge, QuanX, Loon @@ -18,10 +18,10 @@ Use: Surge, QuanX, Loon 您需要配置相关规则集: Surge、Loon: -https://raw.githubusercontent.com/DivineEngine/Profiles/master/Surge/Ruleset/StreamingMedia/StreamingSE.list +https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Bilibili.list QuanX: -https://raw.githubusercontent.com/DivineEngine/Profiles/master/Quantumult/Filter/StreamingMedia/StreamingSE.list +https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Bilibili.list 绑定相关select或static策略组,并且需要具有相关的区域代理服务器纳入您的子策略中,子策略可以是服务器也可以是其他区域策略组. 最后,您可以通过BoxJs设置策略名和子策略名,或者手动填入脚本. @@ -34,48 +34,48 @@ QX用户注: 使用切换地区功能请确保您的QX=>其他设置=>温和策 Surge 4.7+ 远程脚本配置 : **************************** [Script] -Bili Region = type=http-response,pattern=^https:\/\/ap(p|i)\.bili(bili|api)\.(com|net)\/(pgc\/view\/v\d\/app\/season|x\/v\d\/search\/defaultwords)\?access_key,requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Bili_Auto_Regions.js +Bili Region = type=http-response,pattern=^https:\/\/ap(p|i)\.bili(bili|api)\.(com|net)\/(pgc\/view\/v\d\/app\/season|x\/offline\/version)\?,requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Bili_Auto_Regions.js #可选, 适用于搜索指定地区的番剧 Bili Search = type=http-request,pattern=^https:\/\/ap(p|i)\.bili(bili|api)\.(com|net)\/x\/v\d\/search(\/type)?\?.+?%20(%E6%B8%AF|%E5%8F%B0|%E4%B8%AD)&,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Bili_Auto_Regions.js [MITM] -hostname = ap?.bilibili.com, ap?.biliapi.net +hostname = ap?.bili*i.com, ap?.bili*i.net **************************** Quantumult X 远程脚本配置 : **************************** [rewrite_local] -^https:\/\/ap(p|i)\.bili(bili|api)\.(com|net)\/(pgc\/view\/v\d\/app\/season|x\/v\d\/search\/defaultwords)\?access_key url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Bili_Auto_Regions.js +^https:\/\/ap(p|i)\.bili(bili|api)\.(com|net)\/(pgc\/view\/v\d\/app\/season|x\/offline\/version)\? url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Bili_Auto_Regions.js #可选, 适用于搜索指定地区的番剧 ^https:\/\/ap(p|i)\.bili(bili|api)\.(com|net)\/x\/v\d\/search(\/type)?\?.+?%20(%E6%B8%AF|%E5%8F%B0|%E4%B8%AD)& url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Bili_Auto_Regions.js [mitm] -hostname = ap?.bilibili.com, ap?.biliapi.net +hostname = ap?.bili*i.com, ap?.bili*i.net [filter_local] -#可选, 由于qx纯tun特性, 不添加规则可能会导致脚本失效. +#可选, 由于qx纯tun特性, 不添加规则可能会导致脚本失效. https://github.com/NobyDa/Script/issues/382 ip-cidr, 203.107.1.1/24, reject **************************** Loon 远程脚本配置 : **************************** [Script] -http-response ^https:\/\/ap(p|i)\.bili(bili|api)\.(com|net)\/(pgc\/view\/v\d\/app\/season|x\/v\d\/search\/defaultwords)\?access_key script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Bili_Auto_Regions.js, requires-body=true, tag=bili自动地区 +http-response ^https:\/\/ap(p|i)\.bili(bili|api)\.(com|net)\/(pgc\/view\/v\d\/app\/season|x\/offline\/version)\? script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Bili_Auto_Regions.js, requires-body=true, tag=bili自动地区 #可选, 适用于搜索指定地区的番剧 -http-request ^https:\/\/ap(p|i)\.bili(bili|api)\.(com|net)\/x\/v\d\/search(\/type)?\?.+?%20(%E6%B8%AF|%E5%8F%B0|%E4%B8%AD)& script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Bili_Auto_Regions.js, requires-body=true, tag=bili自动地区(搜索) +http-request ^https:\/\/ap(p|i)\.bili(bili|api)\.(com|net)\/x\/v\d\/search(\/type)?\?.+?%20(%E6%B8%AF|%E5%8F%B0|%E4%B8%AD)& script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Bili_Auto_Regions.js, tag=bili自动地区(搜索) [Mitm] -hostname = ap?.bilibili.com, ap?.biliapi.net +hostname = ap?.bili*i.com, ap?.bili*i.net ***************************/ let $ = nobyda(); let run = EnvInfo(); -async function SwitchRegion(play) { +async function SwitchRegion(title, url, body) { const Group = $.read('BiliArea_Policy') || '📺 DomesticMedia'; //Your blibli policy group name. const CN = $.read('BiliArea_CN') || 'DIRECT'; //Your China sub-policy name. const TW = $.read('BiliArea_TW') || '🇹🇼 sub-policy'; //Your Taiwan sub-policy name. @@ -84,31 +84,44 @@ async function SwitchRegion(play) { const off = $.read('BiliArea_disabled') || ''; //WiFi blacklist(disable region change), separated by commas. const current = await $.getPolicy(Group); const area = (() => { - let select; - if (/\u50c5[\u4e00-\u9fa5]+\u6e2f|%20%E6%B8%AF&/.test(play)) { - const test = /\u50c5[\u4e00-\u9fa5]+\u53f0/.test(play); - if (current != HK && (current == TW && test ? 0 : 1)) select = HK; - } else if (/\u50c5[\u4e00-\u9fa5]+\u53f0|%20%E5%8F%B0&/.test(play)) { - if (current != TW) select = TW; - } else if (play === -404) { - if (current != DF) select = DF; + let select = {}; + let chtMatch = title && title.split('').some(v => zhHans().includes(v)); + if (/\u6e2f[\u4e00-\u9fa5]+\u5340|%20%E6%B8%AF&/.test(title || url)) { + const test = /\u53f0[\u4e00-\u9fa5]+\u5340/.test(title); + if (current != HK && (current == TW && test ? 0 : 1)) + select = { policy: HK, mode: '香港' }; + } else if (/\u53f0[\u4e00-\u9fa5]+\u5340|%20%E5%8F%B0&/.test(title || url)) { + if (current != TW) select = { policy: TW, mode: '台湾' }; + } else if (body.code === -404 || chtMatch) { + if (current != DF) select = { policy: DF, mode: '后备' }; } else if (current != CN) { - select = CN; + select = { policy: CN, mode: '直连' }; } - if ($.isQuanX && current === 'direct' && select === 'DIRECT') { - select = null; //avoid loops in some cases + if ($.isQuanX && current === 'direct' && select.policy === 'DIRECT') { + select = {}; //prevent loopback in some cases } return select; })() - if (area && !off.includes($.ssid || undefined)) { - const change = await $.setPolicy(Group, area); - const notify = $.read('BiliAreaNotify') === 'true'; - const msg = SwitchStatus(change, current, area); - if (!notify) { - $.notify((/^(http|-404)/.test(play) || !play) ? `` : play, ``, msg); + if (area.policy && !off.includes($.ssid || undefined)) { + const change = await $.setPolicy(Group, area.policy); + const msg = (() => { + if (change && typeof current !== 'number') { + return `${current} ➤ ${area.policy}`; + } else if (current === 2) { + return `策略组名未填写或填写有误 ⚠️` + } else if (current === 3) { + return `不支持您的VPN应用版本 ⚠️` + } else if (change === 0) { + return `子策略名未填写或填写有误 ⚠️` + } else { + return `未知错误 ⚠️` + } + })() + if ($.read('BiliAreaNotify') === 'true') { + console.log(`${title || ''}\n模式: 策略组使用"${area.mode}"子策略\n走向: ${msg}`); } else { - console.log(`${(/^(http|-404)/.test(play)||!play)?``:play}\n${msg}`); + $.notify(title || '', ``, `模式: 策略组使用"${area.mode}"子策略\n走向: ${msg}`); } if (change) { return true; @@ -117,38 +130,26 @@ async function SwitchRegion(play) { return false; } -function SwitchStatus(status, original, newPolicy) { - if (status && typeof original !== 'number') { - return `${original} => ${newPolicy} => 🟢`; - } else if (original === 2) { - return `切换失败, 策略组名未填写或填写有误 ⚠️` - } else if (original === 3) { - return `切换失败, 不支持您的VPN应用版本 ⚠️` - } else if (status === 0) { - return `切换失败, 子策略名未填写或填写有误 ⚠️` - } else { - return `策略切换失败, 未知错误 ⚠️` - } -} - function EnvInfo() { - if (typeof($response) !== 'undefined') { - const raw = JSON.parse($response.body); + const url = $request.url; + if (typeof ($response) !== 'undefined') { + const raw = JSON.parse($response.body || "{}"); const data = raw.data || raw.result || {}; - SwitchRegion(data.title || (raw.code === -404 ? -404 : null)) + const title = [data.title, data.series && data.series.series_title, data.season_title] + .filter(c => /\u5340\uff09/.test(c))[0] || data.title; + SwitchRegion(title, null, raw) .then(s => s ? $done({ - status: $.isQuanX ? "HTTP/1.1 408 Request Timeout" : 408, + status: $.isQuanX ? "HTTP/1.1 307" : 307, headers: { - Connection: "close" + Location: url }, body: "{}" }) : QueryRating(raw, data)); } else { - const raw = $request.url; const res = { - url: raw.replace(/%20(%E6%B8%AF|%E5%8F%B0|%E4%B8%AD)&/g, '&') + url: url.replace(/%20(%E6%B8%AF|%E5%8F%B0|%E4%B8%AD)&/g, '&') }; - SwitchRegion(raw).then(() => $done(res)); + SwitchRegion(null, url, {}).then(() => $done(res)); } } @@ -157,7 +158,7 @@ async function QueryRating(body, play) { const ratingEnabled = $.read('BiliDoubanRating') === 'false'; if (!ratingEnabled && play.title && body.data && body.data.badge_info) { const [t1, t2] = await Promise.all([ - GetRawInfo(play.title), + GetRawInfo(play.title.replace(/\uff08[\u4e00-\u9fa5]+\u5340\uff09/, '')), GetRawInfo(play.origin_name) ]); const exYear = body.data.publish.release_date_show.split(/^(\d{4})/)[1]; @@ -170,12 +171,12 @@ async function QueryRating(body, play) { .replace(/"\u53d7\u9650"/g, `""`).replace(/("area_limit":)1/g, '$10'); body.data.modules = JSON.parse(limit); body.data.detail = body.data.new_ep.desc.replace(/连载中,/, ''); - body.data.badge_info.text = `⭐️ 豆瓣:${!$.is403?`${rating||'无评'}分 (${folk||'无评价'})`:`查询频繁!`}`; - body.data.evaluate = `${body.data.evaluate||''}\n\n豆瓣评分搜索结果: ${JSON.stringify(other,0,1)}`; + body.data.badge_info.text = `⭐️ 豆瓣:${!$.is403 ? `${rating || '无评'}分 (${folk || '无评价'})` : `查询频繁!`}`; + body.data.evaluate = `${body.data.evaluate || ''}\n\n豆瓣评分搜索结果: ${JSON.stringify(other, 0, 1)}`; body.data.new_ep.desc = name; body.data.styles.unshift({ name: "⭐️ 点击此处打开豆瓣剧集详情页", - url: `https://m.douban.com/${id?`movie/subject/${id}/`:`search/?query=${encodeURI(play.title)}`}` + url: `https://m.douban.com/${id ? `movie/subject/${id}/` : `search/?query=${encodeURI(play.title)}`}` }); } } catch (err) { @@ -229,7 +230,7 @@ function GetRawInfo(t) { } else { if (/\u767b\u5f55<\/a>\u540e\u91cd\u8bd5\u3002/.test(data)) $.is403 = true; let s = data.replace(/\n| |&#\d{2}/g, '') - .match(/\[\u7535\u5f71\].+?subject-cast\">.+?<\/span>/g) || []; + .match(/\[(\u7535\u5f71|\u7535\u89c6\u5267)\].+?subject-cast\">.+?<\/span>/g) || []; for (let i = 0; i < s.length; i++) { res.push({ name: s[i].split(/\}\)">(.+?)<\/a>/)[1], @@ -255,7 +256,7 @@ function nobyda() { const isQuanX = typeof $task != "undefined"; const isSurge = typeof $network != "undefined" && typeof $script != "undefined"; const ssid = (() => { - if (isQuanX && typeof($environment) !== 'undefined') { + if (isQuanX && typeof ($environment) !== 'undefined') { return $environment.ssid; } if (isSurge && $network.wifi) { @@ -285,7 +286,7 @@ function nobyda() { } const getPolicy = (groupName) => { if (isSurge) { - if (typeof($httpAPI) === 'undefined') return 3; + if (typeof ($httpAPI) === 'undefined') return 3; return new Promise((resolve) => { $httpAPI("GET", "v1/policy_groups/select", { group_name: encodeURIComponent(groupName) @@ -293,12 +294,12 @@ function nobyda() { }) } if (isLoon) { - if (typeof($config.getPolicy) === 'undefined') return 3; + if (typeof ($config.getPolicy) === 'undefined') return 3; const getName = $config.getPolicy(groupName); return getName || 2; } if (isQuanX) { - if (typeof($configuration) === 'undefined') return 3; + if (typeof ($configuration) === 'undefined') return 3; return new Promise((resolve) => { $configuration.sendMessage({ action: "get_policy_state" @@ -311,7 +312,7 @@ function nobyda() { } } const setPolicy = (group, policy) => { - if (isSurge && typeof($httpAPI) !== 'undefined') { + if (isSurge && typeof ($httpAPI) !== 'undefined') { return new Promise((resolve) => { $httpAPI("POST", "v1/policy_groups/select", { group_name: group, @@ -319,11 +320,11 @@ function nobyda() { }, (b) => resolve(!b.error || 0)) }) } - if (isLoon && typeof($config.getPolicy) !== 'undefined') { + if (isLoon && typeof ($config.getPolicy) !== 'undefined') { const set = $config.setSelectPolicy(group, policy); return set || 0; } - if (isQuanX && typeof($configuration) !== 'undefined') { + if (isQuanX && typeof ($configuration) !== 'undefined') { return new Promise((resolve) => { $configuration.sendMessage({ action: "set_policy_state", @@ -359,4 +360,9 @@ function nobyda() { ssid, get } +} + +// https://zh.wikipedia.org/wiki/Wikipedia:Unihan%E7%B9%81%E7%AE%80%E4%BD%93%E5%AF%B9%E7%85%A7%E8%A1%A8/%E7%B9%81%E7%AE%80%E4%B8%80%E4%B8%80%E5%AF%B9%E5%BA%94%E8%A1%A8 +function zhHans() { + return `䊷䋙䝼䰾䲁丟並乾亂亞佇馀併來侖侶俁係俔俠倀倆倈倉個們倫偉側偵偽傑傖傘備傭傯傳傴債傷傾僂僅僉僑僕僞僥僨價儀儂億儈儉儐儔儕儘償優儲儷儺儻儼兌兒兗內兩冊冪凈凍凜凱別刪剄則剋剎剗剛剝剮剴創劃劇劉劊劌劍劑勁動務勛勝勞勢勩勱勵勸勻匭匯匱區協卻厙厠厭厲厴參叄叢吒吳吶呂咼員唄唚問啓啞啟啢喎喚喪喬單喲嗆嗇嗊嗎嗚嗩嗶嘆嘍嘔嘖嘗嘜嘩嘮嘯嘰嘵嘸嘽噓噝噠噥噦噯噲噴噸噹嚀嚇嚌嚕嚙嚦嚨嚲嚳嚴嚶囀囁囂囅囈囑囪圇國圍園圓圖團垵埡埰執堅堊堖堝堯報場塊塋塏塒塗塢塤塵塹墊墜墮墳墻墾壇壈壋壓壘壙壚壞壟壠壢壩壯壺壼壽夠夢夾奐奧奩奪奬奮奼妝姍姦娛婁婦婭媧媯媼媽嫗嫵嫻嫿嬀嬈嬋嬌嬙嬡嬤嬪嬰嬸孌孫學孿宮寢實寧審寫寬寵寶將專尋對導尷屆屍屓屜屢層屨屬岡峴島峽崍崗崢崬嵐嶁嶄嶇嶔嶗嶠嶢嶧嶮嶴嶸嶺嶼巋巒巔巰帥師帳帶幀幃幗幘幟幣幫幬幹幺幾庫廁廂廄廈廚廝廟廠廡廢廣廩廬廳弒弳張強彈彌彎彙彞彥後徑從徠復徵徹恆恥悅悞悵悶惡惱惲惻愛愜愨愴愷愾慄態慍慘慚慟慣慤慪慫慮慳慶憂憊憐憑憒憚憤憫憮憲憶懇應懌懍懟懣懨懲懶懷懸懺懼懾戀戇戔戧戩戰戱戲戶拋拾挩挾捨捫掃掄掗掙掛採揀揚換揮損搖搗搵搶摑摜摟摯摳摶摻撈撏撐撓撝撟撣撥撫撲撳撻撾撿擁擄擇擊擋擓擔據擠擬擯擰擱擲擴擷擺擻擼擾攄攆攏攔攖攙攛攜攝攢攣攤攪攬敗敘敵數斂斃斕斬斷時晉晝暈暉暘暢暫曄曆曇曉曏曖曠曨曬書會朧東杴极柵桿梔梘條梟梲棄棖棗棟棧棲棶椏楊楓楨業極榪榮榲榿構槍槤槧槨槳樁樂樅樓標樞樣樸樹樺橈橋機橢橫檁檉檔檜檟檢檣檮檯檳檸檻櫃櫓櫚櫛櫝櫞櫟櫥櫧櫨櫪櫫櫬櫱櫳櫸櫻欄權欏欒欖欞欽歐歟歡歲歷歸歿殘殞殤殨殫殮殯殲殺殻殼毀毆毿氂氈氌氣氫氬氳決沒沖況洶浹涇涼淚淥淪淵淶淺渙減渦測渾湊湞湯溈準溝溫滄滅滌滎滬滯滲滷滸滻滾滿漁漚漢漣漬漲漵漸漿潁潑潔潙潛潤潯潰潷潿澀澆澇澗澠澤澦澩澮澱濁濃濕濘濟濤濫濰濱濺濼濾瀅瀆瀉瀏瀕瀘瀝瀟瀠瀦瀧瀨瀲瀾灃灄灑灕灘灝灠灣灤灧災為烏烴無煉煒煙煢煥煩煬熅熒熗熱熲熾燁燈燉燒燙燜營燦燭燴燼燾爍爐爛爭爲爺爾牆牘牽犖犢犧狀狹狽猙猶猻獁獄獅獎獨獪獫獮獰獲獵獷獸獺獻獼玀現琺琿瑋瑒瑣瑤瑩瑪瑲璉璣璦璫環璽瓊瓏瓔瓚甌產産畝畢異畵當疇疊痙痾瘂瘋瘍瘓瘞瘡瘧瘮瘲瘺瘻療癆癇癉癘癟癢癤癥癧癩癬癭癮癰癱癲發皚皰皸皺盜盞盡監盤盧眥眾睏睜睞瞘瞜瞞瞶瞼矓矚矯硜硤硨硯碩碭碸確碼磑磚磣磧磯磽礆礎礙礦礪礫礬礱祿禍禎禕禡禦禪禮禰禱禿秈稅稈稟種稱穀穌積穎穠穡穢穩穫穭窩窪窮窯窵窶窺竄竅竇竈竊竪競筆筍筧筴箋箏節範築篋篔篤篩篳簀簍簞簡簣簫簹簽簾籃籌籙籜籟籠籩籪籬籮粵糝糞糧糲糴糶糹糾紀紂約紅紆紇紈紉紋納紐紓純紕紖紗紘紙級紛紜紝紡紬細紱紲紳紵紹紺紼紿絀終組絅絆絎結絕絛絝絞絡絢給絨絰統絲絳絶絹綁綃綆綈綉綌綏經綜綞綠綢綣綫綬維綯綰綱網綳綴綸綹綺綻綽綾綿緄緇緊緋緑緒緓緔緗緘緙線緝緞締緡緣緦編緩緬緯緱緲練緶緹緻縈縉縊縋縐縑縕縗縛縝縞縟縣縧縫縭縮縱縲縳縵縶縷縹總績繃繅繆繒織繕繚繞繡繢繩繪繫繭繮繯繰繳繸繹繼繽繾纈纊續纍纏纓纖纘纜缽罈罌罰罵罷羅羆羈羋羥義習翹耬耮聖聞聯聰聲聳聵聶職聹聽聾肅脅脈脛脫脹腎腖腡腦腫腳腸膃膚膠膩膽膾膿臉臍臏臘臚臟臠臢臨臺與興舉舊艙艤艦艫艱艷芻苎苧茲荊莊莖莢莧華萇萊萬萵葉葒著葤葦葯葷蒓蒔蒞蒼蓀蓋蓮蓯蓴蓽蔔蔞蔣蔥蔦蔭蕁蕆蕎蕒蕓蕕蕘蕢蕩蕪蕭蕷薀薈薊薌薔薘薟薦薩薴薺藍藎藝藥藪藴藶藹藺蘄蘆蘇蘊蘋蘚蘞蘢蘭蘺蘿虆處虛虜號虧虯蛺蛻蜆蜡蝕蝟蝦蝸螄螞螢螻螿蟄蟈蟎蟣蟬蟯蟲蟶蟻蠅蠆蠐蠑蠟蠣蠨蠱蠶蠻衆術衕衚衛衝衹袞裊裏補裝裡製複褌褘褲褳褸褻襇襏襖襝襠襤襪襯襲見覎規覓視覘覡覥覦親覬覯覲覷覺覽覿觀觴觶觸訁訂訃計訊訌討訐訒訓訕訖託記訛訝訟訢訣訥訩訪設許訴訶診註詁詆詎詐詒詔評詖詗詘詛詞詠詡詢詣試詩詫詬詭詮詰話該詳詵詼詿誄誅誆誇誌認誑誒誕誘誚語誠誡誣誤誥誦誨說説誰課誶誹誼誾調諂諄談諉請諍諏諑諒論諗諛諜諝諞諢諤諦諧諫諭諮諱諳諶諷諸諺諼諾謀謁謂謄謅謊謎謐謔謖謗謙謚講謝謠謡謨謫謬謭謳謹謾證譎譏譖識譙譚譜譫譯議譴護譸譽譾讀變讎讒讓讕讖讜讞豈豎豐豬豶貓貝貞貟負財貢貧貨販貪貫責貯貰貲貳貴貶買貸貺費貼貽貿賀賁賂賃賄賅資賈賊賑賒賓賕賙賚賜賞賠賡賢賣賤賦賧質賫賬賭賴賵賺賻購賽賾贄贅贇贈贊贋贍贏贐贓贔贖贗贛贜赬趕趙趨趲跡踐踴蹌蹕蹣蹤蹺躂躉躊躋躍躑躒躓躕躚躡躥躦躪軀車軋軌軍軑軒軔軛軟軤軫軲軸軹軺軻軼軾較輅輇輈載輊輒輓輔輕輛輜輝輞輟輥輦輩輪輬輯輳輸輻輾輿轀轂轄轅轆轉轍轎轔轟轡轢轤辦辭辮辯農逕這連進運過達違遙遜遞遠適遲遷選遺遼邁還邇邊邏邐郟郵鄆鄉鄒鄔鄖鄧鄭鄰鄲鄴鄶鄺酇酈醖醜醞醫醬醱釀釁釃釅釋釐釒釓釔釕釗釘釙針釣釤釧釩釵釷釹釺鈀鈁鈃鈄鈈鈉鈍鈎鈐鈑鈒鈔鈕鈞鈣鈥鈦鈧鈮鈰鈳鈴鈷鈸鈹鈺鈽鈾鈿鉀鉅鉈鉉鉋鉍鉑鉕鉗鉚鉛鉞鉢鉤鉦鉬鉭鉶鉸鉺鉻鉿銀銃銅銍銑銓銖銘銚銛銜銠銣銥銦銨銩銪銫銬銱銳銷銹銻銼鋁鋃鋅鋇鋌鋏鋒鋙鋝鋟鋣鋤鋥鋦鋨鋩鋪鋭鋮鋯鋰鋱鋶鋸鋼錁錄錆錇錈錏錐錒錕錘錙錚錛錟錠錡錢錦錨錩錫錮錯録錳錶錸鍀鍁鍃鍆鍇鍈鍋鍍鍔鍘鍚鍛鍠鍤鍥鍩鍬鍰鍵鍶鍺鎂鎄鎇鎊鎔鎖鎘鎛鎡鎢鎣鎦鎧鎩鎪鎬鎮鎰鎲鎳鎵鎸鎿鏃鏇鏈鏌鏍鏐鏑鏗鏘鏜鏝鏞鏟鏡鏢鏤鏨鏰鏵鏷鏹鏽鐃鐋鐐鐒鐓鐔鐘鐙鐝鐠鐦鐧鐨鐫鐮鐲鐳鐵鐶鐸鐺鐿鑄鑊鑌鑒鑔鑕鑞鑠鑣鑥鑭鑰鑱鑲鑷鑹鑼鑽鑾鑿钁長門閂閃閆閈閉開閌閎閏閑間閔閘閡閣閥閨閩閫閬閭閱閲閶閹閻閼閽閾閿闃闆闈闊闋闌闍闐闒闓闔闕闖關闞闠闡闤闥阪陘陝陣陰陳陸陽隉隊階隕際隨險隱隴隸隻雋雖雙雛雜雞離難雲電霢霧霽靂靄靈靚靜靦靨鞀鞏鞝鞽韁韃韉韋韌韍韓韙韜韞韻響頁頂頃項順頇須頊頌頎頏預頑頒頓頗領頜頡頤頦頭頮頰頲頴頷頸頹頻頽顆題額顎顏顒顓顔願顙顛類顢顥顧顫顬顯顰顱顳顴風颭颮颯颱颳颶颸颺颻颼飀飄飆飈飛飠飢飣飥飩飪飫飭飯飲飴飼飽飾飿餃餄餅餉養餌餎餏餑餒餓餕餖餚餛餜餞餡館餱餳餶餷餺餼餾餿饁饃饅饈饉饊饋饌饑饒饗饜饞饢馬馭馮馱馳馴馹駁駐駑駒駔駕駘駙駛駝駟駡駢駭駰駱駸駿騁騂騅騌騍騎騏騖騙騤騫騭騮騰騶騷騸騾驀驁驂驃驄驅驊驌驍驏驕驗驚驛驟驢驤驥驦驪驫骯髏髒體髕髖髮鬆鬍鬚鬢鬥鬧鬩鬮鬱魎魘魚魛魢魨魯魴魷魺鮁鮃鮊鮋鮍鮎鮐鮑鮒鮓鮚鮜鮝鮞鮦鮪鮫鮭鮮鮳鮶鮺鯀鯁鯇鯉鯊鯒鯔鯕鯖鯗鯛鯝鯡鯢鯤鯧鯨鯪鯫鯴鯷鯽鯿鰁鰂鰃鰈鰉鰍鰏鰐鰒鰓鰜鰟鰠鰣鰥鰨鰩鰭鰮鰱鰲鰳鰵鰷鰹鰺鰻鰼鰾鱂鱅鱈鱉鱒鱔鱖鱗鱘鱝鱟鱠鱣鱤鱧鱨鱭鱯鱷鱸鱺鳥鳧鳩鳬鳲鳳鳴鳶鳾鴆鴇鴉鴒鴕鴛鴝鴞鴟鴣鴦鴨鴯鴰鴴鴷鴻鴿鵁鵂鵃鵐鵑鵒鵓鵜鵝鵠鵡鵪鵬鵮鵯鵲鵷鵾鶄鶇鶉鶊鶓鶖鶘鶚鶡鶥鶩鶪鶬鶯鶲鶴鶹鶺鶻鶼鶿鷀鷁鷂鷄鷈鷊鷓鷖鷗鷙鷚鷥鷦鷫鷯鷲鷳鷸鷹鷺鷽鷿鸇鸌鸏鸕鸘鸚鸛鸝鸞鹵鹹鹺鹽麗麥麩麵麽黃黌點黨黲黶黷黽黿鼉鼴齊齋齎齏齒齔齕齗齙齜齟齠齡齦齪齬齲齶齷龍龎龐龔龕龜` } \ No newline at end of file diff --git a/Surge/JS/CamScanner.js b/Surge/JS/CamScanner.js index 84f4adeb70..ac5deddef1 100644 --- a/Surge/JS/CamScanner.js +++ b/Surge/JS/CamScanner.js @@ -30,5 +30,5 @@ hostname = ap*.intsig.net **************************/ let obj = JSON.parse($response.body); -obj = {"data":{"psnl_vip_property":{"expiry":"1643731200"}}}; +obj = {"data":{"psnl_vip_property":{"expiry":"2013017600"}}}; $done({body: JSON.stringify(obj)}); \ No newline at end of file diff --git a/Surge/JS/Google_CAPTCHA.js b/Surge/JS/Google_CAPTCHA.js new file mode 100644 index 0000000000..4b96ec11f1 --- /dev/null +++ b/Surge/JS/Google_CAPTCHA.js @@ -0,0 +1,140 @@ +/******************************** +Google搜索人机验证解决方案 +搜索内容时遇到人机验证立即并发使用多个代理策略、策略组尝试搜索内容,并返回最优结果。 + +脚本作者:@NobyDa +更新时间:2024/05/19 +平台兼容:Surge(iOS4.9.3+/macOS4.2.3+) / QuantumultX(1.0.26+) / Loon(3.1.9[694]+) + +可在 BoxJs(低优先级)、Surge模块参数、Loon插件参数中填写筛选的代理策略、策略组的正则表达式。 +所有代理策略、策略组至多筛选、使用20个,可在BoxJs中测试匹配的策略,不筛选则表示随机使用。 + +注意:Surge由于策略架构问题,正则表达式筛选的"代理策略"不包含"外部代理策略"; +QuantumultX、Loon则无此限制,正则表达式可筛选所有"策略组"内的"代理策略"。 + +********************************* +Surge(iOS 5.9.0+/macOS 5.5.0+) 模块: +https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/GoogleCAPTCHA.sgmodule + +********************************* +QuantumultX(1.0.26+) 重写资源引用: +https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/GoogleCAPTCHA.snippet + +********************************* +Loon(3.1.9[694]+) 插件: +https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_Google_CAPTCHA.plugin + +********************************* +BoxJs 订阅地址: +https://raw.githubusercontent.com/NobyDa/Script/master/NobyDa_BoxJs.json + +*********************************/ + +const $ = new NobyDa_Tools(); +$.ret = {}; + +!(async () => { + if (($response.status || $response.statusCode) == 200) return; + const req = JSON.parse(JSON.stringify($request)); + const policy = await $.policy(); + const regexText = (typeof $argument == 'string' && $argument) || + $.data.read('GOOGLE_CAPTCHA_REGEX') || // loon plugin args. + JSON.parse($.data.read('GOOGLE_CAPTCHA') || '{}').Regex || ''; // empty = all + const selected = [...policy.group, ...policy.proxy] + .filter((n) => n && new RegExp(regexText).test(n)) + .sort(() => Math.random() - 0.5).slice(0, 20); // prevent too many TCP, filtered to random select up to 20 + console.log(`[INFO]: Use policy ${JSON.stringify(selected, null, 2)}`); + await Promise.any([ + ...selected.map( + (i) => new Promise((r, e) => { + if (req.headers['User-Agent']) req.headers.Cookie = `${Math.random()}`; // prevent set-cookie + if (req.headers['user-agent']) req.headers.cookie = `${Math.random()}`; // h2 + $.http[req.method.toLowerCase()]({ + policy: i, node: i, opts: { policy: i }, // policy:surge, node:loon, opts:qx + ...req + }).then((v) => { + if (v.status == 200) { + r({ policy: i, body: { ...v, status: $.isQuanX ? 'HTTP/1.1 200' : 200 } }) + } else if (v.status == 429) { + e(console.log(`[INFO]: Policy "${i}" need to CAPTCHA`)) + } else { + e(console.log(`[INFO]: Policy "${i}" unknown resp status "${v.status}"`)) + } + }).catch((err) => e(console.log(`[ERROR]: ${err}`))) + }) + ) + ]).then((data) => { + $.ret = data.body; + console.log(`[INFO]: Use data from "${data.policy}"`); + }) +})() + .catch((err) => console.log(`[ERROR]: ${(err && err.message) || err}`)) + .finally(() => $done($.ret)); + + +function NobyDa_Tools() { + this.isLoon = typeof $loon !== "undefined"; + this.isQuanX = typeof $configuration !== 'undefined'; + this.isSurge = typeof $environment !== 'undefined' && $environment['surge-version']; + this.isNode = typeof module !== 'undefined' && !!module.exports; + this.http = Object.fromEntries( + ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH"].map( + (m) => [m.toLowerCase(), (opts) => { + if (this.isQuanX) return new Promise((resolve, reject) => { + $task.fetch({ method: m, ...opts }) + .then((r) => resolve({ + status: r.statusCode, headers: r.headers, body: r.body, + }), e => reject(e.error)) + }); + if (this.isSurge || this.isLoon || this.isNode) return new Promise((resolve, reject) => { + const request = this.isNode ? require("request") : $httpClient; + request[m.toLowerCase()](opts, (e, r, b) => { + if (e) reject(e); + else resolve({ status: r.status || r.statusCode, headers: r.headers, body: b }) + }) + }); + }] + ) + ); + this.policy = () => { + if (this.isSurge) return new Promise((r) => { + $httpAPI("GET", "v1/policies", null, (v) => r({ + proxy: v.proxies, + group: v['policy-groups'] + })) + }); + if (this.isQuanX) return new Promise((r) => { + $configuration.sendMessage({ + action: "get_customized_policy" + }).then(b => r({ + proxy: Object.keys(b.ret) + .reduce((t, i) => [...new Set([...t, ...b.ret[i].candidates || []])], []) + .filter((v) => !b.ret[v] && !['direct', 'proxy', 'reject'].includes(v)), + group: Object.keys(b.ret) + }), () => r({})); + }); + if (this.isLoon) return new Promise(async (r1) => { + const config = JSON.parse($config.getConfig()); + const groupData = await Promise.all(config['all_policy_groups'].map((i) => new Promise((r2) => { + $config.getSubPolicies(i, (b) => { r2(JSON.parse(b || '[]')) }) + }))); + r1({ + proxy: groupData.reduce((t, i) => [...new Set([...t, ...i.filter((v) => { + return v.type == 'node' && !config['all_buildin_nodes'].includes(v.name) + }).map((n) => n.name)])], []), + group: config['all_policy_groups'] + }) + }); + }; + this.data = Object.fromEntries(['read', 'write'].map( + (i) => [i, (v1, v2) => { + if (i === 'write') { + if (this.isSurge || this.isLoon) return $persistentStore.write(v1, v2); + if (this.isQuanX) return $prefs.setValueForKey(v1, v2); + } else if (i === 'read') { + if (this.isSurge || this.isLoon) return $persistentStore.read(v1); + if (this.isQuanX) return $prefs.valueForKey(v1); + } + }] + )); +} \ No newline at end of file diff --git a/Surge/JS/IPA_install.js b/Surge/JS/IPA_install.js deleted file mode 100644 index 0c8245daf8..0000000000 --- a/Surge/JS/IPA_install.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * iOS14 IPA辅助安装脚本. - * - * 该脚本仅兼容Surge4.0+, 可解决iOS14或IPadOS14无法在移动端安装IPA的问题. - * 注: 该脚本需要使用"Shu+捷径"或"Jsbox"辅助安装. 具体安装演示请移步TG频道 @NobyDa 查看. - * - * 作者: @NobyDa - * - * Surge模块地址: https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/IPA_install.sgmodule - * - * Jsbox辅助安装脚本: https://gist.githubusercontent.com/NobyDa/2489e84ca833a9ae559c2cf534b9cdc8/raw/IPA_Jsbox.js - * - * 捷径地址: https://www.icloud.com/shortcuts/53a7dad769c6453ca2ee54fa2a021ea2 - * - */ - -const eva = $request; -const ipaUrl = eva.url.match(/\/jsbox/) ? "http://localhost:8080/download?path=%2Fapp.ipa" : "http://localhost/"; -if (eva.url.match(/install/)) { - $httpClient.head(ipaUrl, (err, resp, data) => { - if (resp && resp.headers && JSON.stringify(resp.headers).match(/UTF-8''.+?\.ipa/) && resp.status == 200) { - const plist = ` - - - - items - - - assets - - - kind - software-package - url - https://nobyda/download${eva.url.match(/jsbox/)?"/jsbox":""} - - - metadata - - bundle-identifier - * - bundle-version - 1.0 - kind - software - title - ${decodeURIComponent(JSON.stringify(resp.headers).match(/UTF-8''(.+?)\.ipa/)[1])} - - - - -`; - $done({ - response: { - status: 200, - body: plist - } - }); - } else { - $notification.post('APP安装失败', '', '无法读取IPA安装包'); - $done() - } - }) -} else if (eva.method == "GET") { - $httpClient.head(ipaUrl, (err, resp, data) => { - if (resp && resp.headers && resp.status == 200) { - const name = `正在安装: ${JSON.stringify(resp.headers).match(/UTF-8''(.+?)\.ipa/)[1]} ...` - const size = `应用大小: ${(resp.headers['Content-Length'] / 1000 / 1000).toFixed(2)} MB` - $notification.post(decodeURIComponent(name), size, ''); - } else { - $notification.post('APP安装失败', '', `无法下载IPA安装包`); - } - $done({ - url: ipaUrl - }); - }) -} else { - $done({ - url: ipaUrl - }); -} \ No newline at end of file diff --git a/Surge/JS/MIX.js b/Surge/JS/MIX.js index 6d0f701b4a..5af376d043 100644 --- a/Surge/JS/MIX.js +++ b/Surge/JS/MIX.js @@ -5,19 +5,19 @@ MIX 解锁特权 (需恢复购买) QuantumultX: [rewrite_local] -https?:\/\/bmall\.camera360\.com\/api\/mix\/recovery url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/MIX.js +https?:\/\/cdn-bm\.camera360\.com\/api\/mix\/recovery url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/MIX.js [mitm] -hostname = bmall.camera360.com +hostname = cdn-bm.camera360.com *************************** Surge4 or Loon: [Script] -http-response https?:\/\/bmall\.camera360\.com\/api\/mix\/recovery requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/MIX.js +http-response https?:\/\/cdn-bm\.camera360\.com\/api\/mix\/recovery requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/MIX.js [MITM] -hostname = bmall.camera360.com +hostname = cdn-bm.camera360.com **************************/ @@ -89,4 +89,4 @@ if ($response.body) { }); } else { $done({}) -} \ No newline at end of file +} diff --git a/Surge/JS/PicsArt.js b/Surge/JS/PicsArt.js index 41ec9da898..9591e496ea 100644 --- a/Surge/JS/PicsArt.js +++ b/Surge/JS/PicsArt.js @@ -1,11 +1,12 @@ /* PicsArt 解锁高级功能 +数据来自 @chxm1023 *************************** QuantumultX: [rewrite_local] -^https:\/\/api\.(picsart|meiease)\.c(n|om)\/users\/show\/me\.json url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/PicsArt.js +^https:\/\/api\.(picsart|meiease)\.c(n|om)\/shop\/subscription\/(validate|apple\/purchases) url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/PicsArt.js [mitm] hostname = api.picsart.c*, api.meiease.c* @@ -14,13 +15,48 @@ hostname = api.picsart.c*, api.meiease.c* Surge4 or Loon: [Script] -http-response https:\/\/api\.(picsart|meiease)\.c(n|om)\/users\/show\/me\.json requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/PicsArt.js +http-response ^https:\/\/api\.(picsart|meiease)\.c(n|om)\/shop\/subscription\/(validate|apple\/purchases) requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/PicsArt.js [MITM] hostname = api.picsart.c*, api.meiease.c* **************************/ -let obj = JSON.parse($response.body); -obj.subscription.granted = "true"; -$done({body: JSON.stringify(obj)}); \ No newline at end of file +$done({ + body: JSON.stringify({ + "status": "success", + "response": [ + { + "status": "SUBSCRIPTION_PURCHASED", + "order_id": "490001314520000", + "original_order_id": "490001314520000", + "is_trial": true, + "plan_meta": { + "storage_limit_in_mb": 20480, + "frequency": "yearly", + "scope_id": "full", + "id": "com.picsart.editor.subscription_yearly", + "product_id": "subscription_yearly", + "level": 2000, + "auto_renew_product_id": "com.picsart.editor.subscription_yearly", + "type": "renewable", + "tier_id": "gold_old", + "permissions": [ + "premium_tools_standard", + "premium_tools_ai" + ], + "description": "china" + }, + "limitation": { + "max_count": 5, + "limits_exceeded": false + }, + "reason": "ok", + "subscription_id": "com.picsart.editor.subscription_yearly", + "is_eligible_for_introductory": false, + "purchase_date": 1687020148000, + "expire_date": 4092599349000 + } + ] + }) +}); \ No newline at end of file diff --git a/Surge/JS/Polarr.js b/Surge/JS/Polarr.js index 7b6a1e9ecd..db6bdac0bd 100644 --- a/Surge/JS/Polarr.js +++ b/Surge/JS/Polarr.js @@ -1,11 +1,11 @@ /* -Polarr泼辣修图 解锁特权 (需恢复购买) +Polarr泼辣修图 解锁特权 (需登陆) *************************** QuantumultX: [rewrite_local] -^https:\/\/api\.polaxiong\.com\/v1\/payments\/appleiap\/receipts\/confirmation url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Polarr.js +^https:\/\/api\.polaxiong\.com\/v1\/payments\/(appleiap\/receipts\/confirmation|profiles\/@me\/subscription) url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Polarr.js [mitm] hostname = api.polaxiong.com @@ -14,27 +14,42 @@ hostname = api.polaxiong.com Surge4 or Loon: [Script] -http-response ^https:\/\/api\.polaxiong\.com\/v1\/payments\/appleiap\/receipts\/confirmation requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Polarr.js +http-response ^https:\/\/api\.polaxiong\.com\/v1\/payments\/(appleiap\/receipts\/confirmation|profiles\/@me\/subscription) requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Polarr.js [MITM] hostname = api.polaxiong.com **************************/ -const sta = typeof $task !== "undefined" ? "HTTP/1.1 200 OK" : 200; -const res = $response; -const req = $request; - -if (res.body && req.method == "PUT") { - $done({ - body: JSON.stringify({ - "app": "PPE", - "isUnlimited": true, - "membershipExpiryDate": "2028-06-06T08:00:00.000Z" - }), - status: sta, - headers: res.headers +const statusCode = typeof $task !== "undefined" ? "HTTP/1.1 200 OK" : 200; +const response = { status: statusCode, headers: $response.headers }; + +if ($response.body && $request.url.includes("v1/payments/profiles/@me/subscription")) { + response.body = JSON.stringify({ + "isSubscribed": true, + "planId": "co.polarr.ppe.premium.studio.yearly", + "subscriptionProduct": "yearly", + "isTrial": false, + "app": "PPE", + "isUnlimited": true, + "expiryDate": "2053-08-17T19:38:37.000Z", + "planType": "yearly", + "planTier": "studio", + "startDate": "2023-08-17T19:38:37.000Z", + "subscriptionTier": "studio", + "paymentChannel": "AppleIapSubscription", + "membershipExpiryDate": "2053-08-17T19:38:37.000Z" }); -} else { - $done({}); } + +if ($response.body && $request.url.includes("v1/payments/appleiap/receipts/confirmation")) { + response.body = JSON.stringify({ + "app": "PPE", + "planType": "yearly", + "planTier": "studio", + "isUnlimited": true, + "membershipExpiryDate": "2053-08-17T19:38:37.000Z" + }); +} + +$done(response) \ No newline at end of file diff --git a/Surge/JS/Wps.js b/Surge/JS/Wps.js index d580e157bd..0f6e5812a5 100644 --- a/Surge/JS/Wps.js +++ b/Surge/JS/Wps.js @@ -5,19 +5,19 @@ WPS Office 解锁部分功能 QuantumultX: [rewrite_local] -^https?:\/\/account\.wps\.cn\/api\/users url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Wps.js +^https?:\/\/[a-z-]*account\.wps\.c(n|om)(:\d+|)\/api\/users url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Wps.js [mitm] -hostname = account.wps.cn +hostname = *account.wps.cn, *account.wps.com *************************** Surge4 or Loon: [Script] -http-response ^https?:\/\/account\.wps\.cn\/api\/users requires-body=1,max-size=-1,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Wps.js +http-response ^https?:\/\/[a-z-]*account\.wps\.c(n|om)(:\d+|)\/api\/users requires-body=1,max-size=-1,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Wps.js [MITM] -hostname = account.wps.cn +hostname = *account.wps.cn, *account.wps.com **************************/ diff --git a/Surge/JS/vivavideo.js b/Surge/JS/vivavideo.js index a52165c996..cf26b3adb4 100644 --- a/Surge/JS/vivavideo.js +++ b/Surge/JS/vivavideo.js @@ -5,19 +5,19 @@ QuantumultX: [rewrite_local] -^https:\/\/xy-viva\.kakalili\.com\/api\/rest\/u\/vipVerifyReceipt url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/vivavideo.js +^https:\/\/api-use\.intsvs\.com\/api\/rest\/u\/vipVerifyReceipt url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/vivavideo.js [mitm] -hostname = xy-viva.kakalili.com +hostname = api-use.intsvs.com *************************** Surge4 or Loon: [Script] -http-response ^https:\/\/xy-viva\.kakalili\.com\/api\/rest\/u\/vipVerifyReceipt requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/vivavideo.js +http-response ^https:\/\/api-use\.intsvs\.com\/api\/rest\/u\/vipVerifyReceipt requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/vivavideo.js [MITM] -hostname = xy-viva.kakalili.com +hostname = api-use.intsvs.com **************************/ diff --git a/Surge/Module/BahamutAnimeAds.sgmodule b/Surge/Module/BahamutAnimeAds.sgmodule new file mode 100644 index 0000000000..bb2ff23df8 --- /dev/null +++ b/Surge/Module/BahamutAnimeAds.sgmodule @@ -0,0 +1,9 @@ +#!name=动画疯 +#!desc=屏蔽播放广告 (黑屏25秒自动播放) +#!system=ios + +[Script] +动画疯(屏蔽广告) = type=http-response,pattern=^https:\/\/api\.gamer\.com\.tw\/mobile_app\/anime\/v\d/(token|m3u8).php\?,requires-body=1,max-size=0,timeout=40,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bahamut/BahamutAnimeAds.js + +[MITM] +hostname = %APPEND% api.gamer.com.tw \ No newline at end of file diff --git a/Surge/Module/BahamutDailyBonus.sgmodule b/Surge/Module/BahamutDailyBonus.sgmodule new file mode 100644 index 0000000000..4fecbd3759 --- /dev/null +++ b/Surge/Module/BahamutDailyBonus.sgmodule @@ -0,0 +1,8 @@ +#!name=🐻 巴哈姆特 [签到] +#!desc=每日定时签到,包含主站签到、公会签到、动画疯答题等;模块参数可调整签到时间。\n使用前需要进入BoxJs填写账号密码,BoxJs订阅链接可查看脚本注释。 +#!arguments=定时签到:20 8 * * * +#!arguments-desc=定时签到:Cron表达式,默认每天早上 08:20 执行。(如需动画疯答题,不建议在凌晨0:00-0:30执行) +#!category=🐻 NobyDa + +[Script] +巴哈姆特[签到] = type=cron,cronexp="{{{定时签到}}}",wake-system=1,script-update-interval=0,timeout=300,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bahamut/BahamutDailyBonus.js \ No newline at end of file diff --git a/Surge/Module/BiliComicsDailyBonus.sgmodule b/Surge/Module/BiliComicsDailyBonus.sgmodule new file mode 100644 index 0000000000..ad94ba1a36 --- /dev/null +++ b/Surge/Module/BiliComicsDailyBonus.sgmodule @@ -0,0 +1,13 @@ +#!name=🐻 哔哩哔哩漫画 [签到] +#!desc=每日定时签到,模块参数可调整签到时间。\n打开哔哩哔哩漫画APP点击"我的"即可获取cookie. +#!arguments=定时签到:0 9 * * *,禁用脚本:哔哩漫画[Cookie],禁用MITM:hostname +#!arguments-desc=定时签到:Cron表达式,默认每天早上 09:00 执行。\n\n禁用脚本:禁用获取Cookie脚本,输入 # 表示禁用。\n\n禁用MITM:禁用MITM主机名,输入 # 表示禁用。 +#!category=🐻 NobyDa + +[Script] +哔哩漫画[签到] = type=cron,cronexp="{{{定时签到}}}",wake-system=1,script-update-interval=0,timeout=60,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js + +{{{禁用脚本}}} = type=http-request,pattern=^https:\/\/app\.bilibili\.com\/x\/v\d\/account\/myinfo,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js + +[MITM] +{{{禁用MITM}}} = %APPEND% app.bilibili.com \ No newline at end of file diff --git a/Surge/Module/BiliComicsExchangePoints.sgmodule b/Surge/Module/BiliComicsExchangePoints.sgmodule new file mode 100644 index 0000000000..6d8474bcab --- /dev/null +++ b/Surge/Module/BiliComicsExchangePoints.sgmodule @@ -0,0 +1,8 @@ +#!name=🐻 哔哩哔哩漫画 [积分抢购] +#!desc=定时抢购积分商城物品,模块参数可调整抢购设置,该模块需使用"哔哩哔哩漫画签到模块"获取Cookie。 +#!arguments=定时抢购:0-59 0 0 * * 0-1,商品名称:【超特惠】限量-0点秒杀,抢购数量:0,抢购次数:100 +#!arguments-desc=定时抢购:Cron表达式,默认每周日、每周一的凌晨 0:00:00 - 0:01:59 之间每秒执行一次。\n\n商品名称:默认抢购商品名"【超特惠】限量-0点秒杀"\n\n抢购数量:默认为用户积分可抢购的最大值(以0表示)\n\n抢购次数:抢购失败时重试次数,默认100次 +#!category=🐻 NobyDa + +[Script] +哔哩漫画[积分抢购] = type=cron,cronexp="{{{定时抢购}}}",script-update-interval=0,timeout=60,wake-system=1,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/ExchangePoints.js,argument="ProductName={{{商品名称}}}&ProductNum={{{抢购数量}}}&ExchangeNum={{{抢购次数}}} \ No newline at end of file diff --git a/Surge/Module/CtripDailyBonus.sgmodule b/Surge/Module/CtripDailyBonus.sgmodule new file mode 100644 index 0000000000..0ae64b88fa --- /dev/null +++ b/Surge/Module/CtripDailyBonus.sgmodule @@ -0,0 +1,13 @@ +#!name=🐻 携程旅行 [签到] +#!desc=每日定时签到,支持多账号。\n登陆"携程旅行"微信小程序或"携程网页版"(https://m.ctrip.com/)可获取账号授权,填写模块参数可禁用脚本。 +#!arguments=定时签到:30 8 * * *,禁用脚本:携程旅行[授权],禁用MITM:hostname +#!arguments-desc=定时签到:Cron表达式,默认每日 8:30 执行。\n\n禁用脚本:禁用获取授权脚本,输入 # 表示禁用。\n\n禁用MITM:禁用MITM主机名,输入 # 表示禁用。 +#!category=🐻 NobyDa + +[Script] +携程旅行[签到] = type=cron,cronexp="{{{定时签到}}}",wake-system=1,script-update-interval=0,timeout=300,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Ctrip-DailyBonus/Ctrip.js + +{{{禁用脚本}}} = type=http-response,pattern=^https:\/\/m\.ctrip\.com\/restapi\/soa2\/\d+\/[a-zA-Z]+Login(?:$|\?),requires-body=1,max-size=0,debug=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Ctrip-DailyBonus/Ctrip.js + +[MITM] +{{{禁用MITM}}} = %APPEND% m.ctrip.com \ No newline at end of file diff --git a/Surge/Module/DisneyRating.sgmodule b/Surge/Module/DisneyRating.sgmodule new file mode 100644 index 0000000000..0f8a3c8897 --- /dev/null +++ b/Surge/Module/DisneyRating.sgmodule @@ -0,0 +1,11 @@ +#!name=Disney+评分 +#!desc=Disney+剧集页显示IMDb / 烂番茄 / 豆瓣评分 +#!arguments=脚本引擎:jsc,调试模式:0 +#!arguments-desc=脚本引擎:jsc/webview/auto,默认jsc。\n\n调试模式:1/0,开启/关闭。 +#!category=🐻 NobyDa + +[Script] +DisneyRating = type=http-response,pattern=^https:\/\/disney\.api\.edge\.bamgrid\.com\/explore\/v\d\.\d+\/page\/entity-,requires-body=1,max-size=0,binary-body-mode=0,debug={{{调试模式}}},script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Disney/DisneyRating.js,engine={{{脚本引擎}}} + +[MITM] +hostname = %APPEND% disney.api.edge.bamgrid.com \ No newline at end of file diff --git a/Surge/Module/GetCookie.sgmodule b/Surge/Module/GetCookie.sgmodule index a6df79a7a1..b26d78ce0c 100644 --- a/Surge/Module/GetCookie.sgmodule +++ b/Surge/Module/GetCookie.sgmodule @@ -1,20 +1,17 @@ -#!name=Get cookie. By NobyDa -#!desc=该模块适用于定时签到脚本的Cookie获取. 集成: 京东, 吾爱破解, 爱奇艺, 哔哩哔哩漫画, 百度贴吧, 快看漫画; 您可以在使用后手动将其禁用,以免产生不必要的MITM. +#!name=🐻 签到脚本Cookie获取 +#!desc=该模块适用于NobyDa定时签到脚本的Cookie获取. 集成: 爱奇艺, 哔哩哔哩漫画, 百度贴吧, 快看漫画, 携程旅行。 #!system=ios [Script] +爱奇艺Cookie = type=http-request,pattern=^https:\/\/passport\.iqiyi\.com\/apis\/user\/,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js -吾爱Cookie = type=http-request,pattern=https:\/\/www\.52pojie\.cn\/home\.php\?,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/52pojie-DailyBonus/52pojie.js +哔哩漫画Cookie = type=http-request,pattern=^https:\/\/app\.bilibili\.com\/x\/v\d\/account\/myinfo,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js -爱奇艺Cookie = type=http-request,pattern=^https:\/\/passport\.iqiyi\.com\/apis\/user\/info\.action,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js +百度贴吧Cookie = type=http-request,pattern=^https?:\/\/(c\.tieba|tiebac)\.baidu\.com\/c\/s\/login,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js -哔哩漫画Cookie = type=http-request,pattern=^https:\/\/passport\.biligame\.com\/api\/login\/sso.+?version%22%3A%22(3|4|5),script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js +快看漫画Cookie = type=http-request,pattern=^https:\/\/api\.kkmh\.com\/v\d\/passport\/user,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js -贴吧Cookie = type=http-request,pattern=https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js - -京东签到Cookie = type=http-request,requires-body=1,pattern=^https:\/\/(api\.m|me-api|ms\.jr)\.jd\.com\/(client\.action\?functionId=signBean|user_new\/info\/GetJDUserInfoUnion\?|gw\/generic\/hy\/h5\/m\/appSign\?),script-path=https://raw.githubusercontent.com/NobyDa/Script/master/JD-DailyBonus/JD_DailyBonus.js - -快看漫画Cookie = type=http-request,pattern=https:\/\/api\.kkmh\.com\/v\d\/passport\/user,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js +携程旅行Cookie = type=http-response,pattern=^https:\/\/m\.ctrip\.com\/restapi\/soa2\/\d+\/[a-zA-Z]+Login(?:$|\?),requires-body=1,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Ctrip-DailyBonus/Ctrip.js [MITM] -hostname = %APPEND% passport.iqiyi.com, www.52pojie.cn, api.m.jd.com, ms.jr.jd.com, me-api.jd.com, passport.biligame.com, c.tieba.baidu.com, api.kkmh.com \ No newline at end of file +hostname = %APPEND% passport.iqiyi.com, app.bilibili.com, c.tieba.baidu.com, tiebac.baidu.com, api.kkmh.com, m.ctrip.com \ No newline at end of file diff --git a/Surge/Module/GoogleCAPTCHA.sgmodule b/Surge/Module/GoogleCAPTCHA.sgmodule new file mode 100644 index 0000000000..88baccec9d --- /dev/null +++ b/Surge/Module/GoogleCAPTCHA.sgmodule @@ -0,0 +1,11 @@ +#!name=Google人机验证 +#!desc=Google搜索内容时并发使用多个策略/策略组,以避免可能出现的人机验证。注意:需要在模块参数填写策略/策略组名的正则表达式。 +#!arguments=策略正则,脚本引擎:auto +#!arguments-desc=策略正则:策略/策略组名的正则表达式,例如:\n^(🇸🇬|🇭🇰)\s.*\d+$ 如需同时使用所有策略/策略组可使用 .+ 表示。\n\n脚本引擎:jsc/webview/auto,默认auto。 +#!category=🐻 NobyDa + +[Script] +Google CAPTCHA = type=http-response,pattern=^https:\/\/www\.google\.com(?:\.[a-z]+|)\/(?:search\?(?:|.+?&)q=|$),requires-body=1,debug=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Google_CAPTCHA.js,max-size=0,timeout=10,ability=http-client-policy,engine={{{脚本引擎}}},argument={{{策略正则}}} + +[MITM] +hostname = %APPEND% www.google.com* \ No newline at end of file diff --git a/Surge/Module/HuiJuDongManAds.sgmodule b/Surge/Module/HuiJuDongManAds.sgmodule index db544f506d..d339ec365c 100644 --- a/Surge/Module/HuiJuDongManAds.sgmodule +++ b/Surge/Module/HuiJuDongManAds.sgmodule @@ -1,18 +1,16 @@ #!name=荟聚动漫 #!desc=去除大多数弹屏以及底栏广告, 由于有广告缓存, 因此可能需要卸载App重装. @NobyDa -# Update at 2021.01.30 +# Update at 2022/07/11 [Rule] -#检测 -DOMAIN,www.umeng.com,DIRECT -DOMAIN,www.adview.cn,DIRECT -DOMAIN,adview.cn,DIRECT #底栏 DOMAIN,googleads.g.doubleclick.net,REJECT-TINYGIF DOMAIN,www.19831110.com,REJECT-TINYGIF #HTTP AND,((USER-AGENT,%E8%8D%9F%E8%81%9A%E5%8A%A8%E6%BC%AB*), (URL-REGEX,\/ad)),REJECT-TINYGIF +#开屏 +DOMAIN-SUFFIX,admobile.top,REJECT-TINYGIF [URL Rewrite] #弹屏, 搜索, 以及底栏白屏广告 @@ -24,4 +22,4 @@ AND,((USER-AGENT,%E8%8D%9F%E8%81%9A%E5%8A%A8%E6%BC%AB*), (URL-REGEX,\/ad)),REJEC ^https?:\/\/.+?\.snssdk\.com\/ad\/ - reject [MITM] -hostname = %APPEND% sf?-ttcdn-tos.pstatp.com, www.51devapp.com, *.snssdk.com, www.19831110.com, api-access.pangolin-sdk-toutiao.com, os8.pw \ No newline at end of file +hostname = %APPEND% sf?-ttcdn-tos.pstatp.com, www.51devapp.com, *.snssdk.com, www.19831110.com, api-access.pangolin-sdk-toutiao.com, os8.pw, www.umeng.com, www.adview.cn, adview.cn \ No newline at end of file diff --git a/Surge/Module/IPA_install.sgmodule b/Surge/Module/IPA_install.sgmodule index b801d3918c..a9a707e58f 100644 --- a/Surge/Module/IPA_install.sgmodule +++ b/Surge/Module/IPA_install.sgmodule @@ -1,8 +1,9 @@ -#!name=iOS14 IPA应用安装 -#!desc=该模块可解决iOS14或IPadOS14无法在移动端安装IPA的问题. 注: 需要使用Shu+捷径或Jsbox辅助安装. +#!name=IPA应用辅助安装器 +#!desc=该模块可在iOS端辅助安装商店版或已签名IPA(需使用快捷指令 + Shu/Jsbox/pythonista), 查看脚本注释以了解具体方法; 安装演示可查看TG频道 @NobyDa + [Script] -IPA应用安装 = type=http-request,pattern=^https:\/\/nobyda/(install|download)(\/jsbox)?$,requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/IPA_install.js +IPA Installer = type=http-request,pattern=^https:\/\/nobyda.app/(install|download),requires-body=1,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/IPA-Installer/IPA-Installer.js [MITM] -hostname = %APPEND% nobyda \ No newline at end of file +hostname = %APPEND% nobyda.app \ No newline at end of file diff --git a/Surge/Module/KuaiKanComicsDailyBonus.sgmodule b/Surge/Module/KuaiKanComicsDailyBonus.sgmodule new file mode 100644 index 0000000000..c69570ca5c --- /dev/null +++ b/Surge/Module/KuaiKanComicsDailyBonus.sgmodule @@ -0,0 +1,13 @@ +#!name=🐻 快看漫画 [签到] +#!desc=每日定时签到,模块参数可调整签到时间。\n打开快看漫画APP点击"我的"即可获取cookie. +#!arguments=定时签到:10 9 * * *,禁用脚本:快看漫画[Cookie],禁用MITM:hostname +#!arguments-desc=定时签到:Cron表达式,默认每天早上 09:10 执行。\n\n禁用脚本:禁用获取Cookie脚本,输入 # 表示禁用。\n\n禁用MITM:禁用MITM主机名,输入 # 表示禁用。 +#!category=🐻 NobyDa + +[Script] +快看漫画[签到] = type=cron,cronexp="{{{定时签到}}}",wake-system=1,script-update-interval=0,timeout=60,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js + +{{{禁用脚本}}} = type=http-request,pattern=^https?:\/\/api\.kkmh\.com\/v\d\/passport\/user,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js + +[MITM] +{{{禁用MITM}}} = %APPEND% api.kkmh.com \ No newline at end of file diff --git a/Surge/Module/NewBing.sgmodule b/Surge/Module/NewBing.sgmodule new file mode 100644 index 0000000000..b35ccdd1b4 --- /dev/null +++ b/Surge/Module/NewBing.sgmodule @@ -0,0 +1,8 @@ +#!name=New Bing for other browsers +#!desc=Unlock browser restrictions for new bing AI search. + +[Header Rewrite] +^https:\/\/www\.bing\.com\/(search|new) header-replace-regex User-Agent ^\w+\/[0-9\.\s]+\((\w+);.+ "Mozilla/5.0 ($1; Intel Mac OS X 10_12_6) AppleWebKit/537.36 Chrome/110.0 Safari/537.36 Edg/110.0" + +[MITM] +hostname = %APPEND% www.bing.com \ No newline at end of file diff --git a/Surge/Module/TestFlightAccount.sgmodule b/Surge/Module/TestFlightAccount.sgmodule new file mode 100644 index 0000000000..8ad486b781 --- /dev/null +++ b/Surge/Module/TestFlightAccount.sgmodule @@ -0,0 +1,14 @@ +#!name=TestFlight账户管理 +#!desc=自动存储/合并多个TestFlight账户列表, 并可导出/分享TestFlight APP. +#!arguments=请求超时:30,启用缓存:1,使用iOS列表:0,脚本引擎:jsc,调试模式:0 +#!arguments-desc=请求超时:单位:秒。默认30秒。\n\n启用缓存:1/0,开启/关闭,默认开启。用于缓存APP列表,改善列表页面加载过慢。一般与"请求超时"配合使用,开启缓存并刷新列表后,可适当调小超时。\n\n使用iOS列表:1/0,开启/关闭。强制使用iOS应用列表,用于改善 macOS TestFlight 加载过慢。iOS用户无需开启。\n\n脚本引擎:jsc/webview/auto,默认为jsc,如遇内存超限问题可调整为 auto 或 webview\n\n调试模式:1/0,开启/关闭。用于调试脚本。 +#!category=🐻 NobyDa + +[General] +skip-proxy = %APPEND% iosapps.itunes.apple.com + +[Script] +TestFlight账户管理 = type=http-request,pattern=^https:\/\/testflight\.apple\.com\/v\d\/(app|account|invite)s\/,requires-body=1,timeout=180,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/TestFlight/TestFlightAccount.js,debug={{{调试模式}}},argument="timeout={{{请求超时}}}&enableCache={{{启用缓存}}}&forceIOSlist={{{使用iOS列表}}}&debug={{{调试模式}}}",engine={{{脚本引擎}}} + +[MITM] +hostname = %APPEND% testflight.apple.com \ No newline at end of file diff --git a/Surge/Module/TieBaDailyBonus.sgmodule b/Surge/Module/TieBaDailyBonus.sgmodule new file mode 100644 index 0000000000..294084e1b3 --- /dev/null +++ b/Surge/Module/TieBaDailyBonus.sgmodule @@ -0,0 +1,13 @@ +#!name=🐻 百度贴吧 [签到] +#!desc=每日定时签到,模块参数可调整签到时间。\n打开百度贴吧APP点击"我的"即可获取cookie. +#!arguments=定时签到:40 8 * * *,禁用脚本:百度贴吧[Cookie],禁用MITM:hostname +#!arguments-desc=定时签到:Cron表达式,默认每天早上 08:40 执行。\n\n禁用脚本:禁用获取Cookie脚本,输入 # 表示禁用。\n\n禁用MITM:禁用MITM主机名,输入 # 表示禁用。 +#!category=🐻 NobyDa + +[Script] +百度贴吧[签到] = type=cron,cronexp="{{{定时签到}}}",wake-system=1,script-update-interval=0,timeout=600,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js + +{{{禁用脚本}}} = type=http-request,pattern=^https?:\/\/(c\.tieba|tiebac)\.baidu\.com\/c\/s\/login,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js + +[MITM] +{{{禁用MITM}}} = %APPEND% c.tieba.baidu.com, tiebac.baidu.com \ No newline at end of file diff --git a/Surge/Module/iQIYIDailyBonus.sgmodule b/Surge/Module/iQIYIDailyBonus.sgmodule new file mode 100644 index 0000000000..d705c77753 --- /dev/null +++ b/Surge/Module/iQIYIDailyBonus.sgmodule @@ -0,0 +1,13 @@ +#!name=🐻 爱奇艺 [会员签到] +#!desc=每日定时签到,模块参数可调整签到时间。\n登陆爱奇艺网页版 https://m.ctrip.com/ 使用密码登录可获取签到Cookie. +#!arguments=定时签到:10 9 * * *,禁用脚本:爱奇艺[Cookie],禁用MITM:hostname +#!arguments-desc=定时签到:Cron表达式,默认每天早上 09:10 执行。\n\n禁用脚本:禁用获取Cookie脚本,输入 # 表示禁用。\n\n禁用MITM:禁用MITM主机名,输入 # 表示禁用。 +#!category=🐻 NobyDa + +[Script] +爱奇艺[会员签到] = type=cron,cronexp="{{{定时签到}}}",wake-system=1,script-update-interval=0,timeout=60,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js + +{{{禁用脚本}}} = type=http-request,pattern=^https:\/\/passport\.iqiyi\.com\/apis\/user\/,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js + +[MITM] +{{{禁用MITM}}} = %APPEND% passport.iqiyi.com \ No newline at end of file diff --git a/Surge/WeChat.list b/Surge/WeChat.list index 43a1ffc326..f6569c7e64 100644 --- a/Surge/WeChat.list +++ b/Surge/WeChat.list @@ -160,7 +160,6 @@ DOMAIN-KEYWORD,203.205.232. DOMAIN-KEYWORD,203.205.235. DOMAIN-KEYWORD,203.205.253. DOMAIN-KEYWORD,203.205.254. -DOMAIN-KEYWORD,203.209.245. DOMAIN-KEYWORD,211.95.137. DOMAIN-KEYWORD,211.95.138. DOMAIN-KEYWORD,218.68.88. @@ -209,6 +208,8 @@ DOMAIN-KEYWORD,61.241.31. DOMAIN-KEYWORD,61.241.44. DOMAIN-KEYWORD,61.241.47. DOMAIN-KEYWORD,61.241.49. +DOMAIN-KEYWORD,43.156.86. +DOMAIN-KEYWORD,43.156.222. # WeChat Pay SDK DOMAIN-KEYWORD,101.226.129. @@ -257,6 +258,7 @@ IP-CIDR6,2408:8752:0:10::/60,no-resolve IP-CIDR6,2408:8752:0:2:30::/112,no-resolve IP-CIDR6,2408:8752:0:30::/64,no-resolve IP-CIDR6,2408:8752:0:F::/64,no-resolve +IP-CIDR6,2408:8756:F50::/48,no-resolve IP-CIDR6,2408:8756:2CF2:19::/112,no-resolve IP-CIDR6,2408:8756:2CFF:10::/60,no-resolve IP-CIDR6,2408:8756:3AF0:10::/112,no-resolve @@ -293,13 +295,16 @@ IP-CIDR6,2409:8C5C:110:63::/72,no-resolve # China Telecom IPv6 (WeChat) IP-CIDR6,240E:928:1400:10::/112,no-resolve +IP-CIDR6,240E:965:802:620::/60,no-resolve IP-CIDR6,240E:93C:8:10::/60,no-resolve IP-CIDR6,240E:95C:2003:20::/60,no-resolve IP-CIDR6,240E:95C:3003:14::/60,no-resolve IP-CIDR6,240E:96C:6400:700::/60,no-resolve IP-CIDR6,240E:97C:18:601::/64,no-resolve +IP-CIDR6,240E:97C:18:910::/60,no-resolve IP-CIDR6,240E:97C:2F::/60,no-resolve IP-CIDR6,240E:97D:4:1E00::/60,no-resolve +IP-CIDR6,240E:97D:2010:100::/60,no-resolve IP-CIDR6,240E:97F:3000:1102::/64,no-resolve IP-CIDR6,240E:CF:8800::/56,no-resolve IP-CIDR6,240E:E1:A800::/46,no-resolve @@ -350,4 +355,4 @@ DOMAIN-SUFFIX,up-hl.3g.qq.com DOMAIN-SUFFIX,yun-hl.3g.qq.com USER-AGENT,WeChat* -USER-AGENT,MicroMessenger* \ No newline at end of file +USER-AGENT,MicroMessenger* diff --git a/TestFlight/TestFlightAccount.js b/TestFlight/TestFlightAccount.js new file mode 100644 index 0000000000..8b4f63cf46 --- /dev/null +++ b/TestFlight/TestFlightAccount.js @@ -0,0 +1,311 @@ +/******************************** +TestFlight账户管理脚本 + +脚本作者: @NobyDa +脚本兼容: Surge4、QuantumultX、Loon(2.1.20 413+) +更新时间: 2024/04/26 +主要功能: +1. 自动存储多个TestFlight账户,并自动合并APP列表,避免切换账户。 + +2. 账户内单个测试版APP允许多方共享: + - 导出:点击测试版APP -> App详情 -> 描述 -> 复制底部密钥并分享给对方 + - 导入:TestFlight 右上角"兑换" -> 粘贴密钥 -> 弹出保存成功通知后刷新APP列表 + - 多方共享为实验性功能,双方都需要使用该脚本; 该功能主要解决某些APP的TF名额稀缺的问题 + +请注意,该脚本已经与"TF区域限制解除脚本"合并,如需使用该脚本请务必禁用它,否则可能出现APP安装异常 + +********************************* +Surge4 添加脚本: +********************************* + +Surge模块地址: +https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/TestFlightAccount.sgmodule + +********************************* +QuantumultX 添加脚本: +********************************* + +QuantumultX重写引用地址: +https://raw.githubusercontent.com/NobyDa/Script/master/TestFlight/TestFlightAccount.js + +注:以上引用地址需要打开并使用KOP-XIAO资源解析器,如没有解析器请使用脚本配置: + +[rewrite_local] +^https:\/\/testflight\.apple\.com\/v\d\/(app|account|invite)s\/ url script-analyze-echo-response https://raw.githubusercontent.com/NobyDa/Script/master/TestFlight/TestFlightAccount.js + +[mitm] +hostname = testflight.apple.com + +********************************* +Loon 添加脚本: +********************************* + +Loon插件地址: +https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_TF_Account.plugin + +*********************************/ + +const $ = API("TESTFLIGHT-ACCOUNT"); +const args = formatArgument(typeof $argument == "string" && $argument || ''); +$.env.isNode ? $request = $.read('Request') : null; +const [obj, req, rsp] = [new Map(), $request, {}]; +const [k1, k2, k3] = ['x-session-id', 'x-request-id', 'x-session-digest']; +const [list, appList, cacheInfo] = [$.read('AccountList') || {}, $.read('AppList') || {}, $.read('CachedInfo') || {}]; +$.debug = Number(args.debug) || ($.read('Debug') === 'true'); +$.EnableCache = !(Number(args.enableCache) === 0) || !($.read('EnableCache') === 'false'); +$.ForceIOSlist = Number(args.forceIOSlist) || ($.read('ForceIOSlist') === 'true'); +$.RequestTimeout = Number(args.timeout || $.read('Timeout')) || 30; + +runs() + .then((resp) => { + resp = ChangeBody(resp); + rsp.body = resp.body || '{}'; + rsp.headers = formatHeaders(resp.headers || { 'Content-Type': 'application/json' }); + rsp.status = $.env.isQX ? `HTTP/1.1 ${resp.status || 200}` : resp.status || 200; + delete rsp.headers['content-length']; + delete rsp.headers['transfer-encoding']; //prevent issues in qx + $.log(`Return to client: ${$.stringify(rsp)}`); + }) + .catch(e => $.error(e.error || e.message || e)) + .finally(() => $.done($.env.isQX ? rsp : { response: rsp })); + +async function runs() { + // Object.keys(list).map(a => delete list[a].only) + req.headers = formatHeaders(req.headers); //compatible with HTTP/2 + const appID = req.url.split(/\/apps\/(\d+)/)[1]; + const other = /\/(accept|withdraw|devices|session|notifications|status)/.test(req.url); + if (/accounts\/[a-z0-9-]{36}\/apps$/.test(req.url)) { + const acc = SaveAccount(req.url.split(/\/([a-z0-9-]{36})\//)[1]); + return await Promise.all(Object.keys(acc).map(QueryRequest)); + } else if (/\/install$/.test(req.url) && req.body) { + req.body = JSON.parse(req.body); + req.body.storefrontId = '143441-19,29'; //prevent regional restrictions + req.body = JSON.stringify(req.body); + } else if (/\/[A-Z]{200,}\/redeem$/.test(req.url)) { + return { body: ExternalAccount(req.url.split(/\/([A-Z]+)\/redeem$/)[1]) }; + } + return await QueryRequest(!other && appList[appID] || null); +} + +function SaveAccount(id, part, o) { + if (!list[id]) { + list[id] = {}; + const text = `Account ID "${id}" saved. (total ${Object.keys(list).length}) 🎉`; + $.notify('TestFlight Account', '', text); + $.info(text); + }; + list[id][k1] = (part || req.headers)[k1]; + list[id][k2] = (part || req.headers)[k2]; + list[id][k3] = (part || req.headers)[k3]; + if (o) { + if (list[id].only) { + list[id].only.push(o); + $.notify('TestFlight Account', '', `App ID "${o}" saved 🎉`); + } else { + list[id].only = [o]; + } + } + return $.write(list, 'AccountList'), list; +} + +function formatHeaders(h) { + return Object.keys(h).reduce((t, i) => (t[i.toLowerCase()] = h[i], t), {}) +} + +function formatArgument(s) { + return Object.fromEntries(s.split('&').map(item => item.split('='))) +} + +function ChangeHeaders(id) { + const re = JSON.parse(JSON.stringify(req)); //easy deep copy + re.url = re.url.replace(/:\/\/.+?\//, '://testflight.apple.com/'); //prevent cdn issues + re.timeout = $.RequestTimeout * 1000; + re.insecure = true; //skip ssl + re['X-Surge-Skip-Scripting'] = true; //prevent shadowrocket loopback issues + if ($.ForceIOSlist && req.url.endsWith('/apps') && re.headers['user-agent'].includes('Mac')) { + re.headers['user-agent'] = 'Oasis/3.5.1 OasisBuild/425.2 iOS/17.4 model/iPhone16,2 hwp/t8130 build/21E219 (6; dt:311) AMS/1 TSE/0'; + } + if (id) { + $.log(`Request header replaced, using "${id}"`); + re.headers[k1] = list[id][k1]; + re.headers[k2] = list[id][k2]; + re.headers[k3] = list[id][k3]; + re.url = re.url.replace(/\/[a-z0-9-]{36}\//, `/${id}/`); + } + delete re.headers['if-none-match']; //prevent 304 + delete re.headers['content-length']; + $.log(`Send request: ${$.stringify(re)}`); + return re; +} + +function ChangeBody(resp) { + if (req.url.endsWith('/apps')) { + resp = resp.reduce((t, d) => { + d.body = JSON.parse(d.status == 200 && d.body || '{}'); + $.log(`Account "${d.account}" app list: ${$.stringify((d.body.data || []).map(i => i.name))}`); + d.body.data = (d.body.data || []).map(i => { + if ($.ForceIOSlist) { + i.platforms = i.platforms.map(j => { + if (j.name == 'osx') { + $.log(`Account "${d.account}" app [${i.name}] force mac compatible`); + j.build.compatible = true; + j.build.platformCompatible = true; + j.build.osCompatible = true; + j.build.hardwareCompatible = true; + } + return j + }) + } + i.aid = d.account; + const only = !list[d.account].only || list[d.account].only.includes(String(i.appAdamId)); + return only && t.body.data[req.url.includes(d.account) ? 'unshift' : 'push'](i), i; + }); + if (req.url.includes(d.account)) { + [t.status, t.headers] = [d.status, d.headers]; + } + return t + }, { body: { data: [], error: null } }); + resp.body.data = resp.body.data.filter(r => !r.previouslyTested && !obj.has(r.appAdamId) && obj.set(r.appAdamId, 1)); + $.write(resp.body.data.reduce((l, v) => (l[v.appAdamId] = v.aid, l), {}), 'AppList'); + $.log(`Final app: ${$.stringify(resp.body.data.map(i => i.name))}`); + resp.body = JSON.stringify(resp.body); + } + if (/\/apps\/\d+\/builds\/\d+$/.test(req.url) && resp.status == 200 && resp.body) { //beta app page + const share = ShareAccount(req.url.split(/\/apps\/(\d+)/)[1]); + resp.body = JSON.parse(resp.body); + resp.body.data.builds.map(e => e.description = `${e.description || '-'}${share}`); + resp.body = JSON.stringify(resp.body); + } + return resp; +} + +function QueryRequest(o) { + const option = ChangeHeaders(o); + const needCache = $.EnableCache && (option.url.endsWith('/apps') || /\/apps\/\d+\/builds\/\d+$/.test(req.url)); + return $.http[req.method.toLowerCase()](option) + .then(r => { + $.log(`URL "${option.url}" response: status=${r.status}, body=${Boolean(r.body)}`); + if (r.status == 401 && o) { + if (list[o].InvalidKey >= 2) { //prevent misjudgment + delete list[o]; + } else { + list[o].InvalidKey = (list[o].InvalidKey || 0) + 1; + } + $.write(list, 'AccountList'); + $.notify('TestFlight Account', '', `Account ID "${o}" key expired ⚠️`); + throw 'key expired ⚠️'; + } + if (needCache && r.status == 200 && r.body && r.body.startsWith('{')) { + const cacheKey = (cacheInfo[option.url] && cacheInfo[option.url].key) || `TESTFLIGHT-ACCOUNT-${letterEncode(option.url.split(/\/\/.+?\/(.+)/)[1])}`; + $.log(`Write to cache, URL "${option.url}", READ KEY "${cacheKey}"`); + cacheInfo[option.url] = { key: cacheKey, lastUsed: Date.now() }; + Object.keys(cacheInfo).forEach((i) => (Date.now() - (cacheInfo[i].lastUsed || 0) > 864e5 * 3) && $.delete(`#${cacheInfo[i].key}`) && delete cacheInfo[i]); //clear unused cache for 3 days + $.write(cacheInfo, 'CachedInfo'); + $.write(JSON.stringify(r), `#${cacheKey}`); + } + return { ...r, account: o } + }) + .catch(e => { + if (needCache && cacheInfo[option.url] && !(e).includes('key expired')) { + $.log(`URL "${option.url}" Try using cached data`); + const cachedData = $.read(`#${cacheInfo[option.url].key}`); + cacheInfo[option.url].lastUsed = Date.now(); + !cachedData ? delete cacheInfo[option.url] : null; + $.write(cacheInfo, 'CachedInfo'); + return { ...JSON.parse(cachedData || '{}'), account: o } + } + $.error(`URL "${option.url}" response failed: ${e}`); + return { account: o } + }) +} + +function ExternalAccount(key) { + try { + const k = JSON.parse(letterDecode(key)); + $.log(`Raw data: ${key}\nDecode data: ${$.stringify(k)}`); + if (!k.appID || !k.accID || !k.key[k1] || !k.key[k2] || !k.key[k3]) { + throw new Error('Missing data'); + } else if (appList[k.appID]) { + $.notify('TestFlight Account', '', `Failed, app already exists ⚠️`); + } else { + const save = SaveAccount(k.accID, k.key, k.appID); + } + } catch (e) { + const text = `External account parse failed`; + $.notify('TestFlight Account', '', `${text} ⚠️`); + $.error(`${text}: ${e.message || e}`); + } + return '{}' +} + +function ShareAccount(appID) { + const raw = $.stringify({ + appID: appID, + accID: appList[appID], + key: list[appList[appID]] + }); + const key = letterEncode(raw); + const disclaimer = `\n\n\n +================================ +TestFlight 账户管理脚本: + +请注意,使用"共享"功能时,请务必仔细阅读以下声明 ‼️ +请注意,使用"共享"功能时,请务必仔细阅读以下声明 ‼️ +请注意,使用"共享"功能时,请务必仔细阅读以下声明 ‼️ +================================ + +权限: +您即将共享的密钥理论上具有以下权限,包括但不限于: + + - 查看/下载您 TestFlight 账号内的任何测试版 APP + - 使用您的密钥接受测试 TestFlight 中的任何测试版 APP + - 停止测试您 TestFlight 账号内的任何测试版 APP + - 查看您接受 TestFlight 测试版 APP 邀请时所使用的邮箱 + - 查看/加入/移除您 TestFlight 账号中的设备列表 + - 更改您 TestFlight 测试版 APP 中的推送/电子邮件更新通知 + +免责: +任何用户使用"共享"功能时都应该仔细阅读权限声明,一旦您开始使用该功能,即视为您已知晓并理解密钥所具有的权限,密钥泄漏可能会导致不可预知的损失或损害,脚本作者(NobyDa)不对由此产生的任何后果负责。 + +================================ + +该脚本在"默认"情况下,对方仅可查看/下载您共享的单个APP,但仍建议仅与您信任的人共享: + +`; + $.log(`Raw data: ${raw}\nEncode data: ${key}`); + return disclaimer + key; +} + +// private encode method, based on variant in RFC4648 +function letterEncode(e) { + e = e.split("").map(e => e.charCodeAt()); + const t = new Uint8Array(4 * Math.ceil(8 * e.length / 4)); + let n = 0; + for (const o of e) { + let e = 128; + for (let r = 0; r < 8; r++) t[n++] = o & e ? 1 : 0, e >>= 1 + } + let o = "", + r = 0; + return t.forEach((e, t) => { + r = r << 1 | e, (t + 1) % 4 == 0 && (o += "XKNWSPRMCTGZVDHF"[r], r = 0) + }), o +} + +function letterDecode(e) { + const t = new Uint8Array(4 * e.length); + let n = 0; + for (const o of e) { + const e = "XKNWSPRMCTGZVDHF".indexOf(o); + let r = 8; + for (let o = 0; o < 4; o++) t[n++] = e & r ? 1 : 0, r >>= 1 + } + const o = new Uint8Array(Math.floor(t.length / 8)); + return t.forEach((e, t) => { + const n = Math.floor(t / 8); + n < o.length && (o[n] = o[n] << 1 | e) + }), String.fromCharCode(...o) +} + +// https://github.com/Peng-YM/QuanX/tree/master/Tools/OpenAPI +function ENV() { const a = "function" == typeof require && "undefined" != typeof $jsbox; return { isQX: "undefined" != typeof $task, isLoon: "undefined" != typeof $loon, isSurge: "undefined" != typeof $httpClient && "undefined" == typeof $loon, isShadowrocket: "undefined" != typeof $Shadowrocket, isBrowser: "undefined" != typeof document, isNode: "function" == typeof require && !a, isJSBox: a, isRequest: "undefined" != typeof $request, isScriptable: "undefined" != typeof importModule } } function HTTP(a = { baseURL: "" }) { function b(b, j) { j = "string" == typeof j ? { url: j } : j; const k = a.baseURL; k && !i.test(j.url || "") && (j.url = k ? k + j.url : j.url), j = { ...a, ...j }; const l = j.timeout, m = { ...{ onRequest: () => { }, onResponse: a => a, onTimeout: () => { } }, ...j.events }; m.onRequest(b, j); let n; if (c) n = new Promise((a, c) => { $task.fetch({ method: b, ...j }).then(b => a({ status: b.statusCode, headers: b.headers, body: b.body }), a => c(a.error)) }); else if (d || e || g) n = new Promise((a, c) => { var e = Math.ceil; const f = g ? require("request") : $httpClient; !j.timeout || g || d || (j.timeout = e(j.timeout / 1e3)), f[b.toLowerCase()](j, (b, d, e) => { b ? c(b) : a({ status: d.status || d.statusCode, headers: d.headers, body: e }) }) }); else if (f) { const a = new Request(j.url); a.method = b, a.headers = j.headers, a.body = j.body, n = new Promise((b, c) => { a.loadString().then(c => { b({ status: a.response.statusCode, headers: a.response.headers, body: c }) }).catch(a => c(a)) }) } else h && (n = new Promise((a, c) => { fetch(j.url, { method: b, headers: j.headers, body: j.body }).then(a => a.json()).then(b => a({ status: b.status, headers: b.headers, body: b.data })).catch(c) })); let o; const p = l ? new Promise((a, b) => { o = setTimeout(() => (m.onTimeout(), b(`timeout`)), l) }) : null; return (p ? Promise.race([p, n]).then(a => ("undefined" != typeof clearTimeout && clearTimeout(o), a)) : n).then(a => m.onResponse(a)) } const { isQX: c, isLoon: d, isSurge: e, isScriptable: f, isNode: g, isBrowser: h } = ENV(), i = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/, j = {}; return ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH"].forEach(a => j[a.toLowerCase()] = c => b(a, c)), j } function API(a = "untitled", b = !1) { const { isQX: c, isLoon: d, isSurge: e, isNode: f, isJSBox: g, isScriptable: h } = ENV(); return new class { constructor(a, b) { this.name = a, this.debug = b, this.http = HTTP(), this.env = ENV(), this.node = (() => { if (f) { const a = require("fs"); return { fs: a } } return null })(), this.initCache(); const c = (a, b) => new Promise(function (c) { setTimeout(c.bind(null, b), a) }); Promise.prototype.delay = function (a) { return this.then(function (b) { return c(a, b) }) } } initCache() { if (c && (this.cache = JSON.parse($prefs.valueForKey(this.name) || "{}")), (d || e) && (this.cache = JSON.parse($persistentStore.read(this.name) || "{}")), f) { let a = "root.json"; this.node.fs.existsSync(a) || this.node.fs.writeFileSync(a, JSON.stringify({}), { flag: "wx" }, a => console.log(a)), this.root = {}, a = `${this.name}.json`, this.node.fs.existsSync(a) ? this.cache = JSON.parse(this.node.fs.readFileSync(`${this.name}.json`)) : (this.node.fs.writeFileSync(a, JSON.stringify({}), { flag: "wx" }, a => console.log(a)), this.cache = {}) } } persistCache() { const a = JSON.stringify(this.cache, null, 2); c && $prefs.setValueForKey(a, this.name), (d || e) && $persistentStore.write(a, this.name), f && (this.node.fs.writeFileSync(`${this.name}.json`, a, { flag: "w" }, a => console.log(a)), this.node.fs.writeFileSync("root.json", JSON.stringify(this.root, null, 2), { flag: "w" }, a => console.log(a))) } write(a, b) { if (this.log(`SET ${b}`), -1 !== b.indexOf("#")) { if (b = b.substr(1), e || d) return $persistentStore.write(a, b); if (c) return $prefs.setValueForKey(a, b); f && (this.root[b] = a) } else this.cache[b] = a; this.persistCache() } read(a) { if (this.log(`READ ${a}`), -1 !== a.indexOf("#")) { if (a = a.substr(1), e || d) return $persistentStore.read(a); if (c) return $prefs.valueForKey(a); if (f) return this.root[a] } else return this.cache[a] } delete(a) { if (this.log(`DELETE ${a}`), -1 !== a.indexOf("#")) { if (a = a.substr(1), e || d) return $persistentStore.write(null, a); if (c) return $prefs.removeValueForKey(a); f && delete this.root[a] } else delete this.cache[a]; this.persistCache() } notify(a, b = "", i = "", j = {}) { const k = j["open-url"], l = j["media-url"]; if (c && $notify(a, b, i, j), e && $notification.post(a, b, i + `${l ? "\n\u591A\u5A92\u4F53:" + l : ""}`, { url: k }), d) { let c = {}; k && (c.openUrl = k), l && (c.mediaUrl = l), "{}" === JSON.stringify(c) ? $notification.post(a, b, i) : $notification.post(a, b, i, c) } if (f || h) { const c = i + (k ? `\n点击跳转: ${k}` : "") + (l ? `\n多媒体: ${l}` : ""); if (g) { const d = require("push"); d.schedule({ title: a, body: (b ? b + "\n" : "") + c }) } else console.log(`${a}\n${b}\n${c}\n\n`) } } log(a) { this.debug && console.log(`[${this.name}] LOG: ${this.stringify(a)}`) } info(a) { console.log(`[${this.name}] INFO: ${this.stringify(a)}`) } error(a) { console.log(`[${this.name}] ERROR: ${this.stringify(a)}`) } wait(a) { return new Promise(b => setTimeout(b, a)) } done(a = {}) { c || d || e ? $done(a) : f && !g && "undefined" != typeof $context && ($context.headers = a.headers, $context.statusCode = a.statusCode, $context.body = a.body) } stringify(a) { if ("string" == typeof a || a instanceof String) return a; try { return JSON.stringify(a, null, 2) } catch (a) { return "[object Object]" } } }(a, b) } \ No newline at end of file diff --git a/iQIYI-DailyBonus/iQIYI.js b/iQIYI-DailyBonus/iQIYI.js index bbec201bcc..8efdd2517a 100644 --- a/iQIYI-DailyBonus/iQIYI.js +++ b/iQIYI-DailyBonus/iQIYI.js @@ -1,7 +1,7 @@ /* 爱奇艺会员签到脚本 -更新时间: 2022.2.7 +更新时间: 2024/05/15 脚本兼容: QuantumultX, Surge4, Loon, JsBox, Node.js 电报频道: @NobyDa 问题反馈: @NobyDa_bot @@ -40,7 +40,7 @@ QuantumultX 远程脚本配置: [rewrite_local] # 获取Cookie -^https:\/\/passport\.iqiyi\.com\/apis\/user\/info\.action url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js +^https:\/\/passport\.iqiyi\.com\/apis\/user\/ url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js [mitm] hostname= passport.iqiyi.com @@ -51,7 +51,7 @@ Surge 4.2.0+ 脚本配置: [Script] 爱奇艺签到 = type=cron,cronexp=0 9 * * *,timeout=120,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js -爱奇艺获取Cookie = type=http-request,pattern=^https:\/\/passport\.iqiyi\.com\/apis\/user\/info\.action,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js +爱奇艺获取Cookie = type=http-request,pattern=^https:\/\/passport\.iqiyi\.com\/apis\/user\/,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js [MITM] hostname= passport.iqiyi.com @@ -65,7 +65,7 @@ Loon 2.1.0+ 脚本配置: cron "0 9 * * *" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js # 获取Cookie -http-request ^https:\/\/passport\.iqiyi\.com\/apis\/user\/info\.action script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js +http-request ^https:\/\/passport\.iqiyi\.com\/apis\/user\/ script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js [Mitm] hostname= passport.iqiyi.com @@ -76,60 +76,55 @@ var LogDetails = false; // 响应日志 var pushMsg = []; -var P00001 = ''; - -var P00003 = ''; - -var dfp = ''; +let P00001, P00003, DFP var $nobyda = nobyda(); (async () => { cookie = cookie || $nobyda.read("CookieQY") LogDetails = $nobyda.read("iQIYI_LogDetails") === "true" ? true : LogDetails - if (typeof process !== 'undefined' && typeof process.env !== 'undefined') { - cookie = cookie || process.env.IQIYI_COOKIE; - LogDetails = LogDetails || process.env.IQIYI_DEBUG; - barkKey = barkKey || process.env.BARK_PUSH; - barkServer = barkServer || process.env.BARK_SERVER; - } + if (typeof process !== 'undefined' && typeof process.env !== 'undefined') { + cookie = cookie || process.env.IQIYI_COOKIE; + LogDetails = LogDetails || process.env.IQIYI_DEBUG; + barkKey = barkKey || process.env.BARK_PUSH; + barkServer = barkServer || process.env.BARK_SERVER; + } if ($nobyda.isRequest) { GetCookie() } else if (cookie) { - if (cookie.includes("P00001") && cookie.includes("P00003") && cookie.includes("__dfp")) { - P00001 = cookie.match(/P00001=(.*?);/)[1]; - P00003 = cookie.match(/P00003=(.*?);/)[1]; - dfp = cookie.match(/__dfp=(.*?)@/)[1]; - await login(); - await Checkin(); - await WebCheckin(); - for (let i = 0; i < 3; i++){ - const run = await Lottery(i); - if (run) { - await new Promise(r => setTimeout(r, 1000)); - } else { - break - } + if (cookie.includes("P00001") && cookie.includes("P00003") && cookie.includes("__dfp=")) { + P00001 = cookie.match(/P00001=(.*?);/)[1]; + P00003 = cookie.match(/P00003=(.*?);/)[1]; + DFP = cookie.match(/__dfp=(\w+)/)[1]; + await login(); + await Checkin(); + for (let i = 0; i < 3; i++) { + const run = await Lottery(i); + if (run) { + await new Promise(r => setTimeout(r, 1000)); + } else { + break } - const tasks = await getTaskList(); - for (let i = 0; i < tasks.length; i++){ - if (![1, 4].includes(tasks[i].status)) { //0:待领取 1:已完成 2:未开始 4:进行中 - await joinTask(tasks[i]); - await notifyTask(tasks[i]); - await new Promise(r => setTimeout(r, 1000)); - await getTaskRewards(tasks[i]); - console.log(`--------------------`) - } + } + const tasks = await getTaskList(); + for (let i = 0; i < tasks.length; i++) { + if (![1, 4].includes(tasks[i].status)) { //0:待领取 1:已完成 2:未开始 4:进行中 + await joinTask(tasks[i]); + await notifyTask(tasks[i]); + await new Promise(r => setTimeout(r, 1000)); + await getTaskRewards(tasks[i]); + console.log(`--------------------`) } - const expires = $nobyda.expire ? $nobyda.expire.replace(/\u5230\u671f/, "") : "获取失败 ⚠️" - if (!$nobyda.isNode) $nobyda.notify("爱奇艺", "到期时间: " + expires, pushMsg.join('\n')); - if (barkKey) await BarkNotify($nobyda, barkKey, '爱奇艺', `到期时间: ${expires}\n${pushMsg.join('\n')}`, barkServer); - await $nobyda.time(); - } else { - console.log(`Cookie缺少关键值,需重新获取`) } + const expires = $nobyda.expire ? $nobyda.expire.replace(/\u5230\u671f/, "") : "获取失败 ⚠️" + if (!$nobyda.isNode) $nobyda.notify("爱奇艺", "到期时间: " + expires, pushMsg.join('\n')); + if (barkKey) await BarkNotify($nobyda, barkKey, '爱奇艺', `到期时间: ${expires}\n${pushMsg.join('\n')}`, barkServer); + await $nobyda.time(); + } else { + console.log(`Cookie缺少关键值,需重新获取`) + } } else { - $nobyda.notify("爱奇艺会员", "", "签到终止, 未获取Cookie"); + $nobyda.notify("爱奇艺会员", "", "签到终止, 未获取Cookie"); } })().finally(() => { $nobyda.done(); @@ -144,7 +139,7 @@ function login() { t: '479112291' } } - $nobyda.get(URL, function(error, response, data) { + $nobyda.get(URL, function (error, response, data) { const Details = LogDetails ? data ? `response:\n${data}` : '' : '' if (!error && data.match(/\"text\":\"\d.+?\u5230\u671f\"/)) { $nobyda.expire = data.match(/\"text\":\"(\d.+?\u5230\u671f)\"/)[1] @@ -169,27 +164,31 @@ function Checkin() { }; return new Promise(resolve => { const sign_date = { - agentType: "1", - agentversion: "1.0", - appKey: "basic_pcw", - authCookie: P00001, - qyid: md5(stringRandom(16)), - task_code: "natural_month_sign", + task_code: 'natural_month_sign', timestamp: timestamp, - typeCode: "point", + appKey: 'lequ_rn', userId: P00003, + authCookie: P00001, + agenttype: 20, + agentversion: '15.4.6', + srcplatform: 20, + appver: '15.4.6', + qyid: md5(stringRandom(16)) }; + const post_date = { - "natural_month_sign": { - "agentType": "1", - "agentversion": "1", - "authCookie": P00001, - "qyid": md5(stringRandom(16)), - "taskCode": "iQIYI_mofhr", - "verticalCode": "iQIYI" + "natural_month_sign": { + "verticalCode": "iQIYI", + "agentVersion": "15.4.6", + "authCookie": P00001, + "taskCode": "iQIYI_mofhr", + "dfp": DFP, + "qyid": md5(stringRandom(16)), + "agentType": 20, + "signFrom": 1 } }; - const sign = k("UKobMjDMsDoScuWOfp6F", sign_date, { + const sign = k("cRcFakm9KSPSjFEufg3W", sign_date, { split: "|", sort: !0, splitSecretKey: !0 @@ -197,29 +196,29 @@ function Checkin() { var URL = { url: 'https://community.iqiyi.com/openApi/task/execute?' + w(sign_date) + "&sign=" + sign, headers: { - 'Content-Type':'application/json' + 'Content-Type': 'application/json' }, body: JSON.stringify(post_date) } - $nobyda.post(URL, function(error, response, data) { + $nobyda.post(URL, function (error, response, data) { let CheckinMsg, rewards = []; - const Details = LogDetails ? `msg:\n${data||error}` : ''; + const Details = LogDetails ? `msg:\n${data || error}` : ''; try { - if (error) throw new Error(`接口请求出错 ‼️`); + if (error) throw new Error(`接口请求出错 ‼️`); const obj = JSON.parse(data) if (obj.code === "A00000") { if (obj.data.code === "A0000") { - for(let i = 0; i < obj.data.data.rewards.length; i++) { - if (obj.data.data.rewards[i].rewardType == 1) { - rewards.push(`成长值+${obj.data.data.rewards[i].rewardCount}`) - } else if (obj.data.data.rewards[i].rewardType == 2) { - rewards.push(`VIP天+${obj.data.data.rewards[i].rewardCount}`) - } else if (obj.data.data.rewards[i].rewardType == 3) { - rewards.push(`积分+${obj.data.data.rewards[i].rewardCount}`) - } - } + for (let i = 0; i < obj.data.data.rewards.length; i++) { + if (obj.data.data.rewards[i].rewardType == 1) { + rewards.push(`成长值+${obj.data.data.rewards[i].rewardCount}`) + } else if (obj.data.data.rewards[i].rewardType == 2) { + rewards.push(`VIP天+${obj.data.data.rewards[i].rewardCount}`) + } else if (obj.data.data.rewards[i].rewardType == 3) { + rewards.push(`积分+${obj.data.data.rewards[i].rewardCount}`) + } + } var continued = obj.data.data.signDays; - CheckinMsg = `应用签到: ${rewards.join(", ")}${rewards.length<3?`, 累计签到${continued}天`:``} 🎉`; + CheckinMsg = `应用签到: ${rewards.length ? `${rewards.join(", ")}${rewards.length < 3 ? `, 累计签到${continued}天` : ``}` : '无奖励'} 🎉`; } else { CheckinMsg = `应用签到: ${obj.data.msg} ⚠️`; } @@ -227,7 +226,7 @@ function Checkin() { CheckinMsg = `应用签到: Cookie无效 ⚠️`; } } catch (e) { - CheckinMsg = `应用签到: ${e.message||e}`; + CheckinMsg = `应用签到: ${e.message || e}`; } pushMsg.push(CheckinMsg); console.log(`爱奇艺-${CheckinMsg} ${Details}`); @@ -236,103 +235,47 @@ function Checkin() { }) } -function WebCheckin() { +function Lottery(s) { return new Promise(resolve => { - const web_sign_date = { - agenttype: "1", - agentversion: "0", - appKey: "basic_pca", - appver: "0", - authCookie: P00001, - channelCode: "sign_pcw", - dfp: dfp, - scoreType: "1", - srcplatform: "1", - typeCode: "point", - userId: P00003, - // user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36", - verticalCode: "iQIYI" - }; - - const sign = k("DO58SzN6ip9nbJ4QkM8H", web_sign_date, { - split: "|", - sort: !0, - splitSecretKey: !0 - }); - var URL = { - url: 'https://community.iqiyi.com/openApi/score/add?' + w(web_sign_date) + "&sign=" + sign + const URL = { + url: 'https://iface2.iqiyi.com/aggregate/3.0/lottery_activity?app_k=0&app_v=0&platform_id=0&dev_os=0&dev_ua=0&net_sts=0&qyid=0&psp_uid=0&psp_cki=' + P00001 + '&psp_status=0&secure_p=0&secure_v=0&req_sn=0' } - $nobyda.get(URL, function(error, response, data) { - let WebCheckinMsg = ''; - const Details = LogDetails ? `msg:\n${data||error}` : '' + $nobyda.get(URL, async function (error, response, data) { + const Details = LogDetails ? `msg:\n${data || error}` : '' + let LotteryMsg; try { - if (error) throw new Error(`接口请求出错 ‼️`); - const obj = JSON.parse(data) - if (obj.code === "A00000") { - if (obj.data[0].code === "A0000") { - var quantity = obj.data[0].score; - var continued = obj.data[0].continuousValue; - WebCheckinMsg = "网页签到: 积分+" + quantity + ", 累计签到" + continued + "天 🎉" - } else { - WebCheckinMsg = "网页签到: " + obj.data[0].message + " ⚠️" - } + if (error) throw new Error("接口请求出错 ‼️"); + const obj = JSON.parse(data); + if (obj.title) { + LotteryMsg = `应用抽奖: ${obj.title != '影片推荐' && obj.awardName || '未中奖'} 🎉`; + LotteryMsg = obj.kv.code == 'Q00702' && `应用抽奖: 您的抽奖次数已经用完 ⚠️` || LotteryMsg; + $nobyda.stop = obj.kv.code == 'Q00702'; + } else if (obj.kv.code == 'Q00304') { + LotteryMsg = `应用抽奖: Cookie无效 ⚠️`; + $nobyda.stop = 1; } else { - WebCheckinMsg = `网页签到: ${obj.message||'未知错误'} ⚠️` + LotteryMsg = `应用抽奖: 未知错误 ⚠️` } - } catch (e) { - WebCheckinMsg = `网页签到: ${e.message || e}`; - } - pushMsg.push(WebCheckinMsg); - console.log(`爱奇艺-${WebCheckinMsg} ${Details}`); - resolve() - }) - }) -} - -function Lottery(s) { - return new Promise(resolve => { - const URL = { - url: 'https://iface2.iqiyi.com/aggregate/3.0/lottery_activity?app_k=0&app_v=0&platform_id=0&dev_os=0&dev_ua=0&net_sts=0&qyid=0&psp_uid=0&psp_cki=' + P00001 + '&psp_status=0&secure_p=0&secure_v=0&req_sn=0' + } catch (e) { + LotteryMsg = `应用抽奖: ${e.message || e}`; } - $nobyda.get(URL, async function(error, response, data) { - const Details = LogDetails ? `msg:\n${data||error}` : '' - let LotteryMsg; - try { - if (error) throw new Error("接口请求出错 ‼️"); - const obj = JSON.parse(data); - $nobyda.last = data.match(/(机会|已经)用完/) ? true : false - if (obj.awardName && obj.code == 0) { - LotteryMsg = `应用抽奖: ${!$nobyda.last ? `${obj.awardName.replace(/《.+》/, "未中奖")} 🎉` : `您的抽奖次数已经用完 ⚠️`}` - } else if (data.match(/\"errorReason\"/)) { - const msg = data.match(/msg=.+?\)/) ? data.match(/msg=(.+?)\)/)[1].replace(/用户(未登录|不存在)/, "Cookie无效") : "" - LotteryMsg = `应用抽奖: ${msg || `未知错误`} ⚠️` - } else { - LotteryMsg = `应用抽奖: ${data}` - } - } catch (e) { - LotteryMsg = `应用抽奖: ${e.message || e}`; - } - console.log(`爱奇艺-${LotteryMsg} (${s+1}) ${Details}`) - pushMsg.push(LotteryMsg) - if (!$nobyda.last) { - resolve(1) - } else { - resolve() - } - }) + console.log(`爱奇艺-${LotteryMsg} (${s + 1}) ${Details}`) + pushMsg.push(LotteryMsg) + resolve(!$nobyda.stop) + }) }) } function getTaskList(task) { return new Promise(resolve => { - $nobyda.get(`https://tc.vip.iqiyi.com/taskCenter/task/queryUserTask?P00001=${P00001}`, function(error, response, data) { - let taskListMsg, taskList = []; - const Details = LogDetails ? `msg:\n${data||error}` : ''; + $nobyda.get(`https://tc.vip.iqiyi.com/taskCenter/task/queryUserTask?P00001=${P00001}`, function (error, response, data) { + let taskListMsg, taskList = []; + const Details = LogDetails ? `msg:\n${data || error}` : ''; try { if (error) throw new Error(`请求失败`); const obj = JSON.parse(data); if (obj.code == 'A00000' && obj.data && obj.data.tasks) { - Object.keys(obj.data.tasks).map((group) => { + Object.keys(obj.data.tasks).map((group) => { (obj.data.tasks[group] || []).map((item) => { taskList.push({ name: item.taskTitle, @@ -346,7 +289,7 @@ function getTaskList(task) { taskListMsg = `获取失败!`; } } catch (e) { - taskListMsg = `${e.message||e} ‼️`; + taskListMsg = `${e.message || e} ‼️`; } console.log(`爱奇艺-任务列表: ${taskListMsg} ${Details}`) resolve(taskList) @@ -357,16 +300,16 @@ function getTaskList(task) { function joinTask(task) { return new Promise(resolve => { $nobyda.get('https://tc.vip.iqiyi.com/taskCenter/task/joinTask?taskCode=' + task.taskCode + '&lang=zh_CN&platform=0000000000000000&P00001=' + P00001, function (error, response, data) { - let joinTaskMsg, Details = LogDetails ? `msg:\n${data||error}` : ''; - try { - if (error) throw new Error(`请求失败`); - const obj = JSON.parse(data); - joinTaskMsg = obj.code || '领取失败'; - } catch (e) { - joinTaskMsg = `错误 ${e.message||e}`; - } - console.log(`爱奇艺-领取任务: ${task.name} => ${joinTaskMsg} ${Details}`) - resolve() + let joinTaskMsg, Details = LogDetails ? `msg:\n${data || error}` : ''; + try { + if (error) throw new Error(`请求失败`); + const obj = JSON.parse(data); + joinTaskMsg = obj.code || '领取失败'; + } catch (e) { + joinTaskMsg = `错误 ${e.message || e}`; + } + console.log(`爱奇艺-领取任务: ${task.name} => ${joinTaskMsg} ${Details}`) + resolve() }) }) } @@ -374,16 +317,16 @@ function joinTask(task) { function notifyTask(task) { return new Promise(resolve => { $nobyda.get('https://tc.vip.iqiyi.com/taskCenter/task/notify?taskCode=' + task.taskCode + '&lang=zh_CN&platform=0000000000000000&P00001=' + P00001, function (error, response, data) { - let notifyTaskMsg, Details = LogDetails ? `msg:\n${data||error}` : ''; - try { - if (error) throw new Error(`请求失败`); - const obj = JSON.parse(data); - notifyTaskMsg = obj.code || '失败'; - } catch (e) { - notifyTaskMsg = e.message || e; - } - console.log(`爱奇艺-开始任务: ${task.name} => ${notifyTaskMsg} ${Details}`) - resolve() + let notifyTaskMsg, Details = LogDetails ? `msg:\n${data || error}` : ''; + try { + if (error) throw new Error(`请求失败`); + const obj = JSON.parse(data); + notifyTaskMsg = obj.code || '失败'; + } catch (e) { + notifyTaskMsg = e.message || e; + } + console.log(`爱奇艺-开始任务: ${task.name} => ${notifyTaskMsg} ${Details}`) + resolve() }) }) } @@ -392,17 +335,17 @@ function getTaskRewards(task) { return new Promise(resolve => { $nobyda.get('https://tc.vip.iqiyi.com/taskCenter/task/getTaskRewards?taskCode=' + task.taskCode + '&lang=zh_CN&platform=0000000000000000&P00001=' + P00001, function (error, response, data) { let RewardsMsg; - const Details = LogDetails ? `msg:\n${data||error}` : '' + const Details = LogDetails ? `msg:\n${data || error}` : '' try { - if (error) throw new Error(`接口请求出错 ‼️`); + if (error) throw new Error(`接口请求出错 ‼️`); const obj = JSON.parse(data) if (obj.msg === "成功" && obj.code === "A00000" && obj.dataNew[0] !== undefined) { RewardsMsg = `任务奖励: ${task.name} => ${obj.dataNew[0].name + obj.dataNew[0].value} 🎉` } else { - RewardsMsg = `任务奖励: ${task.name} => ${obj.msg!==`成功`&&obj.msg||`未完成`} ⚠️` + RewardsMsg = `任务奖励: ${task.name} => ${obj.msg !== `成功` && obj.msg || `未完成`} ⚠️` } } catch (e) { - RewardsMsg = `任务奖励: ${e.message||e}`; + RewardsMsg = `任务奖励: ${e.message || e}`; } pushMsg.push(RewardsMsg) console.log(`爱奇艺-${RewardsMsg} ${Details}`) @@ -412,22 +355,22 @@ function getTaskRewards(task) { } function GetCookie() { - if (!$request.url.includes("/apis/user/info.action")) { + if (!$request.url.includes("iqiyi.com")) { $nobyda.notify(`写入爱奇艺Cookie失败`, "", "请更新脚本配置(URL正则/MITM)"); return } - var CKA = $request.headers['Cookie']; - var iQIYI = CKA && CKA.includes("P00001=") && CKA.includes("P00003=") && CKA; + var CKA = $request.headers['Cookie'] || $request.headers['cookie'];; + var iQIYI = CKA && CKA.includes("P00001=") && CKA.includes("P00003=") && CKA.includes("__dfp=") && CKA; var RA = $nobyda.read("CookieQY") if (CKA && iQIYI) { if (RA != iQIYI) { var OldTime = $nobyda.read("CookieQYTime") if (!$nobyda.write(iQIYI, "CookieQY")) { - $nobyda.notify(`${RA?`更新`:`首次写入`}爱奇艺签到Cookie失败‼️`, "", "") + $nobyda.notify(`${RA ? `更新` : `首次写入`}爱奇艺签到Cookie失败‼️`, "", "") } else { if (!OldTime || OldTime && (Date.now() - OldTime) / 1000 >= 21600) { $nobyda.write(JSON.stringify(Date.now()), "CookieQYTime") - $nobyda.notify(`${RA?`更新`:`首次写入`}爱奇艺签到Cookie成功 🎉`, "", "") + $nobyda.notify(`${RA ? `更新` : `首次写入`}爱奇艺签到Cookie成功 🎉`, "", "") } else { console.log(`\n更新爱奇艺Cookie成功! 🎉\n检测到频繁通知, 已转为输出日志`) } @@ -440,7 +383,7 @@ function GetCookie() { } } -async function BarkNotify(c,k,t,b,p){for(let i=0;i<3;i++){console.log(`🔷Bark notify >> Start push (${i+1})`);const s=await new Promise((n)=>{c.post({url:p||'https://api.day.app/push',headers:{'Content-Type':'application/json'},body:JSON.stringify({title:t,body:b,device_key:k,ext_params:{group:t}})},(e,r,d)=>r&&r.status==200?n(1):n(d||e))});if(s===1){console.log('✅Push success!');break}else{console.log(`❌Push failed! >> ${s.message||s}`)}}} +async function BarkNotify(c, k, t, b, p) { for (let i = 0; i < 3; i++) { console.log(`🔷Bark notify >> Start push (${i + 1})`); const s = await new Promise((n) => { c.post({ url: p || 'https://api.day.app/push', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: t, body: b, device_key: k, ext_params: { group: t } }) }, (e, r, d) => r && r.status == 200 ? n(1) : n(d || e)) }); if (s === 1) { console.log('✅Push success!'); break } else { console.log(`❌Push failed! >> ${s.message || s}`) } } } function nobyda() { const times = 0 @@ -511,7 +454,7 @@ function nobyda() { url: options } options["header"] = options["headers"] - options["handler"] = function(resp) { + options["handler"] = function (resp) { let error = resp.error; if (error) error = JSON.stringify(resp.error) let body = resp.data; @@ -547,7 +490,7 @@ function nobyda() { url: options } options["header"] = options["headers"] - options["handler"] = function(resp) { + options["handler"] = function (resp) { let error = resp.error; if (error) error = JSON.stringify(resp.error) let body = resp.data; @@ -599,9 +542,9 @@ function k(e, t) { } // Modified from https://github.com/blueimp/JavaScript-MD5 -function md5(string){function RotateLeft(lValue,iShiftBits){return(lValue<>>(32-iShiftBits))}function AddUnsigned(lX,lY){var lX4,lY4,lX8,lY8,lResult;lX8=(lX&0x80000000);lY8=(lY&0x80000000);lX4=(lX&0x40000000);lY4=(lY&0x40000000);lResult=(lX&0x3FFFFFFF)+(lY&0x3FFFFFFF);if(lX4&lY4){return(lResult^0x80000000^lX8^lY8)}if(lX4|lY4){if(lResult&0x40000000){return(lResult^0xC0000000^lX8^lY8)}else{return(lResult^0x40000000^lX8^lY8)}}else{return(lResult^lX8^lY8)}}function F(x,y,z){return(x&y)|((~x)&z)}function G(x,y,z){return(x&z)|(y&(~z))}function H(x,y,z){return(x^y^z)}function I(x,y,z){return(y^(x|(~z)))}function FF(a,b,c,d,x,s,ac){a=AddUnsigned(a,AddUnsigned(AddUnsigned(F(b,c,d),x),ac));return AddUnsigned(RotateLeft(a,s),b)};function GG(a,b,c,d,x,s,ac){a=AddUnsigned(a,AddUnsigned(AddUnsigned(G(b,c,d),x),ac));return AddUnsigned(RotateLeft(a,s),b)};function HH(a,b,c,d,x,s,ac){a=AddUnsigned(a,AddUnsigned(AddUnsigned(H(b,c,d),x),ac));return AddUnsigned(RotateLeft(a,s),b)};function II(a,b,c,d,x,s,ac){a=AddUnsigned(a,AddUnsigned(AddUnsigned(I(b,c,d),x),ac));return AddUnsigned(RotateLeft(a,s),b)};function ConvertToWordArray(string){var lWordCount;var lMessageLength=string.length;var lNumberOfWords_temp1=lMessageLength+8;var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1%64))/64;var lNumberOfWords=(lNumberOfWords_temp2+1)*16;var lWordArray=Array(lNumberOfWords-1);var lBytePosition=0;var lByteCount=0;while(lByteCount>>29;return lWordArray};function WordToHex(lValue){var WordToHexValue="",WordToHexValue_temp="",lByte,lCount;for(lCount=0;lCount<=3;lCount++){lByte=(lValue>>>(lCount*8))&255;WordToHexValue_temp="0"+lByte.toString(16);WordToHexValue=WordToHexValue+WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2)}return WordToHexValue};function Utf8Encode(string){string=string.replace(/\r\n/g,"\n");var utftext="";for(var n=0;n127)&&(c<2048)){utftext+=String.fromCharCode((c>>6)|192);utftext+=String.fromCharCode((c&63)|128)}else{utftext+=String.fromCharCode((c>>12)|224);utftext+=String.fromCharCode(((c>>6)&63)|128);utftext+=String.fromCharCode((c&63)|128)}}return utftext};var x=Array();var k,AA,BB,CC,DD,a,b,c,d;var S11=7,S12=12,S13=17,S14=22;var S21=5,S22=9,S23=14,S24=20;var S31=4,S32=11,S33=16,S34=23;var S41=6,S42=10,S43=15,S44=21;string=Utf8Encode(string);x=ConvertToWordArray(string);a=0x67452301;b=0xEFCDAB89;c=0x98BADCFE;d=0x10325476;for(k=0;k>> (32 - iShiftBits)) } function AddUnsigned(lX, lY) { var lX4, lY4, lX8, lY8, lResult; lX8 = (lX & 0x80000000); lY8 = (lY & 0x80000000); lX4 = (lX & 0x40000000); lY4 = (lY & 0x40000000); lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF); if (lX4 & lY4) { return (lResult ^ 0x80000000 ^ lX8 ^ lY8) } if (lX4 | lY4) { if (lResult & 0x40000000) { return (lResult ^ 0xC0000000 ^ lX8 ^ lY8) } else { return (lResult ^ 0x40000000 ^ lX8 ^ lY8) } } else { return (lResult ^ lX8 ^ lY8) } } function F(x, y, z) { return (x & y) | ((~x) & z) } function G(x, y, z) { return (x & z) | (y & (~z)) } function H(x, y, z) { return (x ^ y ^ z) } function I(x, y, z) { return (y ^ (x | (~z))) } function FF(a, b, c, d, x, s, ac) { a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac)); return AddUnsigned(RotateLeft(a, s), b) }; function GG(a, b, c, d, x, s, ac) { a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac)); return AddUnsigned(RotateLeft(a, s), b) }; function HH(a, b, c, d, x, s, ac) { a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac)); return AddUnsigned(RotateLeft(a, s), b) }; function II(a, b, c, d, x, s, ac) { a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac)); return AddUnsigned(RotateLeft(a, s), b) }; function ConvertToWordArray(string) { var lWordCount; var lMessageLength = string.length; var lNumberOfWords_temp1 = lMessageLength + 8; var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64; var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16; var lWordArray = Array(lNumberOfWords - 1); var lBytePosition = 0; var lByteCount = 0; while (lByteCount < lMessageLength) { lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition)); lByteCount++ } lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition); lWordArray[lNumberOfWords - 2] = lMessageLength << 3; lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; return lWordArray }; function WordToHex(lValue) { var WordToHexValue = "", WordToHexValue_temp = "", lByte, lCount; for (lCount = 0; lCount <= 3; lCount++) { lByte = (lValue >>> (lCount * 8)) & 255; WordToHexValue_temp = "0" + lByte.toString(16); WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2) } return WordToHexValue }; function Utf8Encode(string) { string = string.replace(/\r\n/g, "\n"); var utftext = ""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { utftext += String.fromCharCode(c) } else if ((c > 127) && (c < 2048)) { utftext += String.fromCharCode((c >> 6) | 192); utftext += String.fromCharCode((c & 63) | 128) } else { utftext += String.fromCharCode((c >> 12) | 224); utftext += String.fromCharCode(((c >> 6) & 63) | 128); utftext += String.fromCharCode((c & 63) | 128) } } return utftext }; var x = Array(); var k, AA, BB, CC, DD, a, b, c, d; var S11 = 7, S12 = 12, S13 = 17, S14 = 22; var S21 = 5, S22 = 9, S23 = 14, S24 = 20; var S31 = 4, S32 = 11, S33 = 16, S34 = 23; var S41 = 6, S42 = 10, S43 = 15, S44 = 21; string = Utf8Encode(string); x = ConvertToWordArray(string); a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476; for (k = 0; k < x.length; k += 16) { AA = a; BB = b; CC = c; DD = d; a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478); d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756); c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB); b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE); a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF); d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A); c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613); b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501); a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8); d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF); c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1); b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE); a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122); d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193); c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E); b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821); a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562); d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340); c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51); b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA); a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D); d = GG(d, a, b, c, x[k + 10], S22, 0x2441453); c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681); b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8); a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6); d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6); c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87); b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED); a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905); d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8); c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9); b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A); a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942); d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681); c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122); b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C); a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44); d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9); c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60); b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70); a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6); d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA); c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085); b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05); a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039); d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5); c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8); b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665); a = II(a, b, c, d, x[k + 0], S41, 0xF4292244); d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97); c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7); b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039); a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3); d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92); c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D); b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1); a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F); d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0); c = II(c, d, a, b, x[k + 6], S43, 0xA3014314); b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1); a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82); d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235); c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB); b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391); a = AddUnsigned(a, AA); b = AddUnsigned(b, BB); c = AddUnsigned(c, CC); d = AddUnsigned(d, DD) } var temp = WordToHex(a) + WordToHex(b) + WordToHex(c) + WordToHex(d); return temp.toLowerCase() } -function w(){ +function w() { var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {} , t = []; return Object.keys(e).forEach((function (a) {