├── 52pojie-DailyBonus └── 52pojie.js ├── BDTieBa-DailyBonus └── TieBa.js ├── Bahamut ├── BahamutAnimeAds.js └── BahamutDailyBonus.js ├── Bilibili-DailyBonus ├── ExchangePoints.js └── Manga.js ├── Ctrip-DailyBonus └── Ctrip.js ├── Debug └── Real-time-debug.js ├── Disney └── DisneyRating.js ├── IPA-Installer ├── IPA-Installer-JSBox.js ├── IPA-Installer-Pythonista.py └── IPA-Installer.js ├── JD-DailyBonus └── JD_DailyBonus.js ├── KuaiKan-DailyBonus └── KKMH.js ├── LICENSE ├── Loon ├── Loon_Bahamut_ADS.plugin ├── Loon_Daily_bonus.plugin ├── Loon_GetCookie.plugin ├── Loon_Google_CAPTCHA.plugin ├── Loon_IPA_Installer.plugin ├── Loon_TF_Account.plugin └── Loon_TF_Download.plugin ├── NobyDa_BoxJs.json ├── QuantumultX ├── AdRule.list ├── AdRuleTest.list ├── Bilibili.list ├── DisneyRating.snippet ├── File │ ├── 91.js │ ├── Wechat.js │ ├── Zymh.js │ ├── vsco.js │ ├── wnyd.js │ └── xjsp.js ├── IPA-Installer.snippet ├── Js.conf ├── Rewrite_lhie1.conf ├── Snippet │ ├── BiliComicCookie.snippet │ ├── CtripAuth.snippet │ ├── GoogleCAPTCHA.snippet │ ├── KuaiKanCookie.snippet │ ├── TieBaCookie.snippet │ └── iQiYiCookie.snippet └── TestFlightDownload.conf ├── README.md ├── Rule-Storage ├── Include-Domain.txt └── Rule-Storage.js ├── Shortcuts └── PolicySwitch.js ├── Stash └── IPA-Installer.stoverride ├── Sub-store-parser └── DataQuery.js ├── Surge ├── AdRule.list ├── AdRuleTest.list ├── Apple.list ├── Bilibili.list ├── Download.list ├── JS │ ├── BaiduCloud.js │ ├── Bili_Auto_Regions.js │ ├── CamScanner.js │ ├── Google_CAPTCHA.js │ ├── Kuwo.js │ ├── MIX.js │ ├── NiChi.js │ ├── PicsArt.js │ ├── Polarr.js │ ├── Super.js │ ├── VUE.js │ ├── Wps.js │ ├── jibjab.js │ ├── luqi.js │ └── vivavideo.js ├── Module │ ├── BahamutAnimeAds.sgmodule │ ├── BahamutDailyBonus.sgmodule │ ├── BiliComicsDailyBonus.sgmodule │ ├── BiliComicsExchangePoints.sgmodule │ ├── CtripDailyBonus.sgmodule │ ├── DisneyRating.sgmodule │ ├── GetCookie.sgmodule │ ├── GoogleCAPTCHA.sgmodule │ ├── HuiJuDongManAds.sgmodule │ ├── IPA_install.sgmodule │ ├── KuaiKanComicsDailyBonus.sgmodule │ ├── NewBing.sgmodule │ ├── RewriteRules.sgmodule │ ├── TestFlightAccount.sgmodule │ ├── TestFlightDownload.sgmodule │ ├── TieBaDailyBonus.sgmodule │ └── iQIYIDailyBonus.sgmodule └── WeChat.list ├── TestFlight └── TestFlightAccount.js ├── Time-based-One-Time-Password ├── README.md └── TOTP.min.js └── iQIYI-DailyBonus └── iQIYI.js /52pojie-DailyBonus/52pojie.js: -------------------------------------------------------------------------------- 1 | /* 2 | 吾爱破解签到脚本 3 | 4 | 更新时间: 2022.6.18 5 | 脚本兼容: QuantumultX, Surge, Loon, Node.js 6 | 电报频道: @NobyDa 7 | 问题反馈: @NobyDa_bot 8 | 9 | ************************ 10 | QX, Surge, Loon说明: 11 | ************************ 12 | 手动登录 https://www.52pojie.cn/home.php 如通知成功获取cookie, 则可以使用此签到脚本. 13 | 获取Cookie后, 请将Cookie脚本禁用并移除主机名, 以免产生不必要的MITM. 14 | 脚本将在每天上午9点执行, 您可以修改执行时间. 15 | 16 | ************************ 17 | Node.js说明: 18 | ************************ 19 | 需自行安装"got"与"iconv-lite"模块. 例: npm install got iconv-lite -g 20 | 21 | 抓取Cookie说明: 22 | 浏览器打开 https://www.52pojie.cn/home.php 登录账号后, 开启抓包软件并刷新页面. 23 | 抓取该URL请求头下的Cookie字段, 填入以下CookieWA的单引号内即可. */ 24 | 25 | const CookieWA = ''; 26 | 27 | //Bark APP 通知推送Key 28 | const barkKey = ''; 29 | 30 | /*********************** 31 | Surge 4.2.0+ 脚本配置: 32 | ************************ 33 | 34 | [Script] 35 | 吾爱签到 = type=cron,cronexp=0 9 * * *,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/52pojie-DailyBonus/52pojie.js 36 | 37 | 吾爱获取Cookie = type=http-request,pattern=https:\/\/www\.52pojie\.cn\/home\.php\?,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/52pojie-DailyBonus/52pojie.js 38 | 39 | [MITM] 40 | hostname= www.52pojie.cn 41 | 42 | ************************ 43 | QuantumultX 远程脚本配置: 44 | ************************ 45 | 46 | [task_local] 47 | # 吾爱签到 48 | 0 9 * * * https://raw.githubusercontent.com/NobyDa/Script/master/52pojie-DailyBonus/52pojie.js 49 | 50 | [rewrite_local] 51 | # 获取Cookie 52 | https:\/\/www\.52pojie\.cn\/home\.php\? url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/52pojie-DailyBonus/52pojie.js 53 | 54 | [mitm] 55 | hostname= www.52pojie.cn 56 | 57 | ************************ 58 | Loon 2.1.0+ 脚本配置: 59 | ************************ 60 | 61 | [Script] 62 | # 吾爱签到 63 | cron "0 9 * * *" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/52pojie-DailyBonus/52pojie.js 64 | 65 | # 获取Cookie 66 | http-request https:\/\/www\.52pojie\.cn\/home\.php\? script-path=https://raw.githubusercontent.com/NobyDa/Script/master/52pojie-DailyBonus/52pojie.js 67 | 68 | [Mitm] 69 | hostname= www.52pojie.cn 70 | */ 71 | 72 | const $ = API('nobyda_52pojie'); 73 | const date = new Date(); 74 | const reqData = { 75 | url: 'https://www.52pojie.cn/home.php?mod=task&do=apply&id=2', 76 | headers: { 77 | Cookie: CookieWA || $.read("COOKIE"), 78 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0", 79 | } 80 | }; 81 | if ($.env.isRequest) { 82 | GetCookie() 83 | } else if (!reqData.headers.Cookie) { 84 | $.notify('吾爱破解', ``, `未填写/未获取Cookie!`); 85 | } else if (!reqData.headers.Cookie.includes('_auth=')) { 86 | $.notify('吾爱破解', ``, `Cookie关键授权字段缺失, 需重新获取!`); 87 | } else { 88 | $.http.put(reqData) 89 | .then((resp) => { 90 | if (resp.body.match(/(ÒÑÍê³É|\u606d\u559c\u60a8|��̳΢�š��ᰮ�ƽ�)/)) { 91 | $.msgBody = date.getMonth() + 1 + "月" + date.getDate() + "日, 签到成功 🎉" 92 | } else if (resp.body.match(/(ÄúÒÑ|\u4e0b\u671f\u518d\u6765|>��Ǹ������)/)) { 93 | $.msgBody = date.getMonth() + 1 + "月" + date.getDate() + "日, 已签过 ⚠️" 94 | } else if (resp.body.match(/(ÏȵǼ|\u9700\u8981\u5148\u767b\u5f55|�Ҫ�ȵ�¼���ܼ�)/)) { 95 | $.msgBody = "签到失败, Cookie失效 ‼️‼️" 96 | } else if (resp.statusCode == 403) { 97 | $.msgBody = "服务器暂停签到 ⚠️" 98 | } else { 99 | $.msgBody = "脚本待更新 ‼️‼️" 100 | } 101 | }) 102 | .catch((err) => ($.msgBody = `签到失败 ‼️‼️\n${err || err.message}`)) 103 | .finally(async () => { 104 | if (barkKey) { 105 | await BarkNotify($, barkKey, '吾爱破解', $.msgBody); 106 | } 107 | $.notify('吾爱破解', ``, $.msgBody); 108 | $.done(); 109 | }) 110 | } 111 | 112 | function GetCookie() { 113 | const TM = $.read("TIME"); 114 | const CK = $request.headers['Cookie'] || $request.headers['cookie']; 115 | if (CK && CK.includes('_auth=')) { 116 | $.write(CK, "COOKIE"); 117 | if (!TM || TM && (Date.now() - TM) / 1000 >= 21600) { 118 | $.notify("吾爱破解", "", `写入Cookie成功 🎉`); 119 | $.write(JSON.stringify(Date.now()), "TIME"); 120 | } else { 121 | $.info(`吾爱破解\n写入Cookie成功 🎉`) 122 | } 123 | } else { 124 | $.info(`吾爱破解\n写入Cookie失败, 关键值缺失`) 125 | } 126 | $.done() 127 | } 128 | 129 | //Bark APP notify 130 | 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}`) } } }; 131 | 132 | //https://github.com/Peng-YM/QuanX/tree/master/Tools/OpenAPI 133 | 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) } -------------------------------------------------------------------------------- /BDTieBa-DailyBonus/TieBa.js: -------------------------------------------------------------------------------- 1 | /********************************* 2 | 百度贴吧签到脚本 3 | 4 | 脚本原作者: @sazs34 5 | 平台兼容: QuantumultX, Surge, Loon 6 | 更新日期: 2024/06/01 7 | 8 | 获取Cookie说明: 9 | 打开百度贴吧App后(AppStore中国区, 非内部版),点击"我的", 如通知成功获取cookie则可以使用该脚本. 10 | 11 | ********************************* 12 | Surge(iOS 5.9.0+/macOS 5.5.0+)模块: 13 | https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/TieBaDailyBonus.sgmodule 14 | 15 | ********************************* 16 | QuantumultX 任务仓库(Gallery)订阅: 17 | https://raw.githubusercontent.com/NobyDa/Script/master/NobyDa_BoxJs.json 18 | 19 | 工具&分析->HTTP请求->右上角添加任务仓库->选择百度贴吧签到脚本添加定时任务和附加组件 20 | 21 | ********************************* 22 | Loon 脚本订阅(非插件): 23 | https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_Daily_bonus.plugin 24 | 25 | 添加后请按需启用脚本 26 | 27 | *********************************/ 28 | 29 | 30 | var $nobyda = nobyda(); 31 | var cookieVal = $nobyda.read("CookieTB"); 32 | var useParallel = 0; //0自动切换,1串行,2并行(当贴吧数量大于30个以后,并行可能会导致QX崩溃,所以您可以自动切换) 33 | var singleNotifyCount = 20; //想签到几个汇总到一个通知里,这里就填几个(比如我有13个要签到的,这里填了5,就会分三次消息通知过去) 34 | var process = { 35 | total: 0, 36 | result: [ 37 | // { 38 | // bar:'', 39 | // level:0, 40 | // exp:0, 41 | // errorCode:0, 42 | // errorMsg:'' 43 | // } 44 | ] 45 | }; 46 | var url_fetch_sign = { 47 | url: "https://tieba.baidu.com/mo/q/newmoindex", 48 | headers: { 49 | "Content-Type": "application/octet-stream", 50 | Referer: "https://tieba.baidu.com/index/tbwise/forum", 51 | Cookie: cookieVal, 52 | "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16A366" 53 | } 54 | }; 55 | var url_fetch_add = { 56 | url: "https://tieba.baidu.com/sign/add", 57 | method: "POST", 58 | headers: { 59 | "Content-Type": "application/x-www-form-urlencoded", 60 | Cookie: cookieVal, 61 | "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 10_1_1 like Mac OS X; zh-CN) AppleWebKit/537.51.1 (KHTML, like Gecko) Mobile/14B100 UCBrowser/10.7.5.650 Mobile" 62 | }, 63 | body: "" 64 | }; 65 | if ($nobyda.isRequest) { 66 | GetCookie() 67 | } else { 68 | signTieBa() 69 | } 70 | 71 | 72 | function signTieBa() { 73 | useParallel = $nobyda.read("BDTB_DailyBonus_Mode") || useParallel 74 | singleNotifyCount = $nobyda.read("BDTB_DailyBonus_notify") || singleNotifyCount 75 | if (!cookieVal) { 76 | $nobyda.notify("贴吧签到", "签到失败", "未获取到cookie"); 77 | return $nobyda.done() 78 | } 79 | $nobyda.get(url_fetch_sign, function(error, response, data) { 80 | if (error) { 81 | $nobyda.notify("贴吧签到", "签到失败", "未获取到签到列表"); 82 | $nobyda.done() 83 | } else { 84 | // $nobyda.notify("贴吧签到", "贴吧列表", response.body); 85 | var body = JSON.parse(data); 86 | var isSuccessResponse = body && body.no == 0 && body.error == "success" && body.data.tbs; 87 | if (!isSuccessResponse) { 88 | $nobyda.notify("贴吧签到", "签到失败", (body && body.error) ? body.error : "接口数据获取失败"); 89 | return $nobyda.done() 90 | } 91 | process.total = body.data.like_forum.length; 92 | if (body.data.like_forum && body.data.like_forum.length > 0) { 93 | if (useParallel == 1 || (useParallel == 0 && body.data.like_forum.length >= 30)) { 94 | signBars(body.data.like_forum, body.data.tbs, 0); 95 | } else { 96 | for (const bar of body.data.like_forum) { 97 | signBar(bar, body.data.tbs); 98 | } 99 | } 100 | } else { 101 | $nobyda.notify("贴吧签到", "签到失败", "请确认您有关注的贴吧"); 102 | return $nobyda.done() 103 | } 104 | } 105 | }) 106 | } 107 | 108 | function signBar(bar, tbs) { 109 | if (bar.is_sign == 1) { //已签到的,直接不请求接口了 110 | process.result.push({ 111 | bar: `${bar.forum_name}`, 112 | level: bar.user_level, 113 | exp: bar.user_exp, 114 | errorCode: 9999, 115 | errorMsg: "已签到" 116 | }); 117 | checkIsAllProcessed(); 118 | } else { 119 | url_fetch_add.body = `tbs=${tbs}&kw=${bar.forum_name}&ie=utf-8`; 120 | $nobyda.post(url_fetch_add, function(error, response, data) { 121 | if (error) { 122 | process.result.push({ 123 | bar: bar.forum_name, 124 | errorCode: 999, 125 | errorMsg: '接口错误' 126 | }); 127 | checkIsAllProcessed(); 128 | } else { 129 | try { 130 | var addResult = JSON.parse(data); 131 | if (addResult.no == 0) { 132 | process.result.push({ 133 | bar: bar.forum_name, 134 | errorCode: 0, 135 | errorMsg: `获得${addResult.data.uinfo.cont_sign_num}积分,第${addResult.data.uinfo.user_sign_rank}个签到` 136 | }); 137 | } else { 138 | process.result.push({ 139 | bar: bar.forum_name, 140 | errorCode: addResult.no, 141 | errorMsg: addResult.error 142 | }); 143 | } 144 | } catch (e) { 145 | $nobyda.notify("贴吧签到", "贴吧签到数据处理异常", JSON.stringify(e)); 146 | $nobyda.done() 147 | } 148 | checkIsAllProcessed(); 149 | } 150 | }) 151 | } 152 | } 153 | 154 | function signBars(bars, tbs, index) { 155 | //$nobyda.notify("贴吧签到", `进度${index}/${bars.length}`, ""); 156 | if (index >= bars.length) { 157 | //$nobyda.notify("贴吧签到", "签到已满", `${process.result.length}`); 158 | checkIsAllProcessed(); 159 | } else { 160 | var bar = bars[index]; 161 | if (bar.is_sign == 1) { //已签到的,直接不请求接口了 162 | process.result.push({ 163 | bar: `${bar.forum_name}`, 164 | level: bar.user_level, 165 | exp: bar.user_exp, 166 | errorCode: 9999, 167 | errorMsg: "已签到" 168 | }); 169 | signBars(bars, tbs, ++index); 170 | } else { 171 | url_fetch_add.body = `tbs=${tbs}&kw=${bar.forum_name}&ie=utf-8`; 172 | $nobyda.post(url_fetch_add, function(error, response, data) { 173 | if (error) { 174 | process.result.push({ 175 | bar: bar.forum_name, 176 | errorCode: 999, 177 | errorMsg: '接口错误' 178 | }); 179 | signBars(bars, tbs, ++index); 180 | } else { 181 | try { 182 | var addResult = JSON.parse(data); 183 | if (addResult.no == 0) { 184 | process.result.push({ 185 | bar: bar.forum_name, 186 | errorCode: 0, 187 | errorMsg: `获得${addResult.data.uinfo.cont_sign_num}积分,第${addResult.data.uinfo.user_sign_rank}个签到` 188 | }); 189 | } else { 190 | process.result.push({ 191 | bar: bar.forum_name, 192 | errorCode: addResult.no, 193 | errorMsg: addResult.error 194 | }); 195 | } 196 | } catch (e) { 197 | $nobyda.notify("贴吧签到", "贴吧签到数据处理异常", JSON.stringify(e)); 198 | $nobyda.done() 199 | } 200 | signBars(bars, tbs, ++index) 201 | } 202 | }) 203 | } 204 | } 205 | } 206 | 207 | function checkIsAllProcessed() { 208 | //$nobyda.notify("贴吧签到", `最终进度${process.result.length}/${process.total}`, ""); 209 | if (process.result.length != process.total) return; 210 | for (var i = 0; i < Math.ceil(process.total / singleNotifyCount); i++) { 211 | var notify = ""; 212 | var spliceArr = process.result.splice(0, singleNotifyCount); 213 | var notifySuccessCount = 0; 214 | for (const res of spliceArr) { 215 | if (res.errorCode == 0 || res.errorCode == 9999) { 216 | notifySuccessCount++; 217 | } 218 | if (res.errorCode == 9999) { 219 | notify += `【${res.bar}】已经签到,当前等级${res.level},经验${res.exp} 220 | `; 221 | } else { 222 | notify += `【${res.bar}】${res.errorCode==0?'签到成功':'签到失败'},${res.errorCode==0?res.errorMsg:('原因:'+res.errorMsg)} 223 | `; 224 | } 225 | } 226 | $nobyda.notify("贴吧签到", `签到${spliceArr.length}个,成功${notifySuccessCount}个`, notify); 227 | $nobyda.done() 228 | } 229 | } 230 | 231 | function GetCookie() { 232 | let headerCookie = $request.headers["Cookie"] || $request.headers["cookie"]; 233 | if (headerCookie && headerCookie.includes('BDUSS=')) { 234 | if (!cookieVal) { 235 | $nobyda.notify("写入百度贴吧Cookie成功 🎉", "", ""); 236 | } else { 237 | console.log(`写入百度贴吧Cookie成功 🎉`); 238 | } 239 | $nobyda.write(headerCookie, "CookieTB") 240 | } else { 241 | console.log(`写入Cookie失败, BDUSS值缺失. `); 242 | } 243 | return $nobyda.done(); 244 | } 245 | 246 | function nobyda() { 247 | const isRequest = typeof $request != "undefined" 248 | const isSurge = typeof $httpClient != "undefined" 249 | const isQuanX = typeof $task != "undefined" 250 | const notify = (title, subtitle, message) => { 251 | if (isQuanX) $notify(title, subtitle, message) 252 | if (isSurge) $notification.post(title, subtitle, message) 253 | } 254 | const write = (value, key) => { 255 | if (isQuanX) return $prefs.setValueForKey(value, key) 256 | if (isSurge) return $persistentStore.write(value, key) 257 | } 258 | const read = (key) => { 259 | if (isQuanX) return $prefs.valueForKey(key) 260 | if (isSurge) return $persistentStore.read(key) 261 | } 262 | const adapterStatus = (response) => { 263 | if (response) { 264 | if (response.status) { 265 | response["statusCode"] = response.status 266 | } else if (response.statusCode) { 267 | response["status"] = response.statusCode 268 | } 269 | } 270 | return response 271 | } 272 | const get = (options, callback) => { 273 | if (isQuanX) { 274 | if (typeof options == "string") options = { 275 | url: options 276 | } 277 | options["method"] = "GET" 278 | $task.fetch(options).then(response => { 279 | callback(null, adapterStatus(response), response.body) 280 | }, reason => callback(reason.error, null, null)) 281 | } 282 | if (isSurge) $httpClient.get(options, (error, response, body) => { 283 | callback(error, adapterStatus(response), body) 284 | }) 285 | } 286 | const post = (options, callback) => { 287 | if (isQuanX) { 288 | if (typeof options == "string") options = { 289 | url: options 290 | } 291 | options["method"] = "POST" 292 | $task.fetch(options).then(response => { 293 | callback(null, adapterStatus(response), response.body) 294 | }, reason => callback(reason.error, null, null)) 295 | } 296 | if (isSurge) { 297 | $httpClient.post(options, (error, response, body) => { 298 | callback(error, adapterStatus(response), body) 299 | }) 300 | } 301 | } 302 | const done = (value = {}) => { 303 | if (isQuanX) return $done(value) 304 | if (isSurge) isRequest ? $done(value) : $done() 305 | } 306 | return { 307 | isRequest, 308 | notify, 309 | write, 310 | read, 311 | get, 312 | post, 313 | done 314 | } 315 | }; -------------------------------------------------------------------------------- /Bahamut/BahamutAnimeAds.js: -------------------------------------------------------------------------------- 1 | /************************ 2 | 3 | 动画疯,屏蔽播放广告脚本 (黑屏25秒自动播放) 4 | 由于动画疯强制验证观看广告时间,无法实现真正意义上的跳过广告。 5 | 6 | Surge(4.11+)模块: 7 | https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/BahamutAnimeAds.sgmodule 8 | 9 | QX(1.0.27+)用户请自行搭配KOP-XIAO资源解析器重写引用Surge模块。 10 | 11 | ************************/ 12 | 13 | let [req, rsp] = [$request, JSON.parse($response.body || '{}')]; 14 | 15 | runs().catch((err) => { 16 | console.log(`[BahamutAnime] ERROR: ${err.message||err}`) 17 | }).finally(() => $done({ 18 | body: JSON.stringify(rsp) 19 | })); 20 | 21 | async function runs() { 22 | if (req.url.includes('token.php')) { 23 | if (rsp.ad) { 24 | rsp.ad.minor = []; 25 | rsp.ad.major = []; 26 | } 27 | if (rsp.data && rsp.data.ad) { 28 | rsp.data.ad.minor = []; 29 | rsp.data.ad.major = []; 30 | } 31 | } 32 | if (req.url.includes('m3u8.php') && (rsp.message || rsp.error)) { 33 | await adURL(''); 34 | await new Promise(r => setTimeout(r, 25000)); 35 | await adURL('end'); 36 | rsp = await playURL(); 37 | } 38 | } 39 | 40 | function adURL(str) { 41 | return new Promise((res) => { 42 | get({ 43 | 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]}`, 44 | headers: req.headers 45 | }, (err, resp, data) => res()) 46 | }) 47 | } 48 | 49 | function playURL() { 50 | return new Promise((res) => { 51 | get({ 52 | url: req.url, 53 | headers: req.headers 54 | }, (err, resp, data) => res(JSON.parse(data || '{}'))) 55 | }) 56 | } 57 | 58 | function get(options, callback) { 59 | if (typeof $task != "undefined") { 60 | $task.fetch(options).then(response => { 61 | response["status"] = response.statusCode 62 | callback(null, response, response.body) 63 | }, reason => callback(reason.error, null, null)) 64 | } 65 | if (typeof $httpClient != "undefined") { 66 | $httpClient.get(options, callback) 67 | } 68 | } -------------------------------------------------------------------------------- /Bilibili-DailyBonus/ExchangePoints.js: -------------------------------------------------------------------------------- 1 | /* 2 | 哔哩哔哩漫画, 积分商城自动抢购脚本 3 | 4 | 脚本作者:@NobyDa 5 | 更新时间:2024/06/01 6 | 平台兼容:Surge, QuantumultX, Loon 7 | 8 | ************************* 9 | 【 抢购脚本注意事项 】: 10 | ************************* 11 | 12 | 该脚本需要使用签到脚本获取Cookie后方可使用. 13 | 默认兑换积分商城中的"【超特惠】限量-0点秒杀", 兑换数量为用户积分可兑换的最大值 (可于BoxJs内修改) 14 | 默认执行时间为:每周日、每周一的凌晨 0:00:00 - 0:01:59 之间每秒执行一次 15 | 16 | BoxJs订阅地址: https://raw.githubusercontent.com/NobyDa/Script/master/NobyDa_BoxJs.json 17 | 18 | ************************* 19 | 【 Surge & Loon 脚本配置 】: 20 | ************************* 21 | 22 | [Script] 23 | cron "0-59 0 0 * * 0-1" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/ExchangePoints.js, wake-system=1, timeout=60 24 | 25 | ************************* 26 | 【 QX 1.0.10+ 脚本配置 】 : 27 | ************************* 28 | 29 | [task_local] 30 | 0-59 0 0 * * 0-1 * * * https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/ExchangePoints.js, tag=哔哩哔哩漫画抢券, enabled=true 31 | 32 | */ 33 | 34 | // 新建一个实例对象, 把兼容函数定义到$中, 以便统一调用 35 | let $ = new nobyda(); 36 | 37 | // 读取Surge脚本参数并转成对象 38 | let args = argsList(typeof $argument == "string" && $argument || ''); 39 | 40 | // 读取兑换商品名, 默认兑换积分商城中的"【超特惠】限量-0点秒杀" 41 | let productName = args.ProductName || $.read('BM_ProductName') || '【超特惠】限量-0点秒杀'; 42 | 43 | // 读取兑换数量, 默认兑换最大值 44 | let productNum = parseInt(args.ProductNum) || $.read('BM_ProductNum'); 45 | 46 | // 读取循环抢购次数, 默认100次 47 | let exchangeNum = args.ExchangeNum || $.read('BM_ExchangeNum') || '100'; 48 | 49 | // 读取哔哩哔哩漫画签到脚本所使用的Cookie 50 | let cookie = $.read('CookieBM'); 51 | 52 | // 预留的空对象, 便于函数之间读取数据 53 | let user = {}; 54 | 55 | (async function() { // 立即运行的匿名异步函数 56 | // 使用await关键字声明, 表示以同步方式执行异步函数, 可以简单理解为顺序执行 57 | await Promise.all([ //该方法用于将多个实例包装成一个新的实例, 可以简单理解为同时调用函数, 以进一步提高执行速度 58 | GetUserPoint(), //查询积分函数 59 | ListProduct() //查询商品函数 60 | ]); 61 | await ExchangeProduct(); //上面的查询都完成后, 则执行抢购 62 | $.done(); //抢购完成后调用Surge、QX内部特有的函数, 用于退出脚本执行 63 | })(); 64 | 65 | function GetUserPoint() { 66 | const pointUrl = { //查询积分接口 67 | url: 'https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/GetUserPoint', 68 | headers: { //请求头 69 | 'Cookie': cookie //用户鉴权Cookie 70 | } 71 | } 72 | return new Promise((resolve) => { //主函数返回Promise实例对象, 以便后续调用时可以实现顺序执行异步函数 73 | $.post(pointUrl, (error, resp, data) => { //使用post请求查询, 再使用回调函数处理返回的结果 74 | try { //使用try方法捕获可能出现的代码异常 75 | if (error) { 76 | throw new Error(error); //如果请求失败, 例如无法联网, 则抛出一个异常 77 | } else { 78 | const body = JSON.parse(data); //解析响应体json并转化为对象 79 | if (body.code == 0 && body.data) { //如果响应体为预期格式 80 | user.point = parseInt(body.data.point); //把查询的积分赋值到全局变量user中 81 | console.log(`\n当前积分: ${body.data.point}`); //打印日志 82 | } else { //否则抛出一个异常 83 | throw new Error(body.msg || data); 84 | } 85 | } 86 | } catch (e) { //接住try代码块中抛出的异常, 并打印日志 87 | console.log(`\n查询积分: 失败\n出现错误: ${e.message}`); 88 | } finally { //finally语句在try和catch之后无论有无异常都会执行 89 | resolve(); //异步操作成功时调用, 将Promise对象的状态标记为"成功", 表示已完成查询积分 90 | } 91 | }) 92 | }) 93 | } 94 | 95 | function ListProduct() { 96 | const listUrl = { //查询商品接口 97 | url: 'https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/ListProduct', 98 | headers: {} 99 | } 100 | return new Promise((resolve) => { //主函数返回Promise实例对象, 以便后续调用时可以实现顺序执行异步函数 101 | $.post(listUrl, (error, resp, data) => { //使用post请求查询, 再使用回调函数处理返回的结果 102 | try { //使用try方法捕获可能出现的代码异常 103 | if (error) { 104 | throw new Error(error); //如果请求失败, 例如无法联网, 则抛出一个异常 105 | } else { 106 | const body = JSON.parse(data); //解析响应体json并转化为对象 107 | if (body.code == 0 && body.data.length >= 1) { //如果接口正常返回商品信息 108 | // 按全局变量所填写的商品名进行过滤, 并把商品信息赋值到全局变量user中 109 | user.list = body.data.filter(t => t.title == productName).pop(); 110 | if (!user.list) { 111 | throw new Error('请检查商品名'); //如果填错商品名则抛出一个异常 112 | } else { //否则打印日志 113 | console.log(`\n查询商品: ${productName}\n商品库存: ${user.list.remain_amount}`) 114 | } 115 | } else { //否则抛出一个异常 116 | throw new Error('无商品列表'); 117 | } 118 | } 119 | } catch (e) { //接住try代码块中抛出的异常并打印日志 120 | console.log(`\n查询商品: ${productName}\n出现错误: ${e.message}`); 121 | } finally { //finally语句在try和catch之后无论有无异常都会执行 122 | resolve(); //异步操作成功时调用, 将Promise对象的状态标记为"成功", 表示已完成查询商品 123 | } 124 | }) 125 | }) 126 | } 127 | 128 | function ExchangeProduct() { 129 | return new Promise(async (resolve) => { //主函数返回Promise实例对象, 以便后续调用时可以实现顺序执行异步函数, 该实例函数带有async关键字, 表示里面有异步操作, 例如可使用await得到异步结果 130 | if (user.list && user.list.remain_amount && user.point >= 100) { //如果商品有库存并且用户积分大于100则进行抢购 131 | //兑换商品数量(用户积分 除与 商品单价得到兑换数量), 并转成整数; 默认兑换最大数量 132 | const num = parseInt(productNum || (user.point / user.list.real_cost)); 133 | const exchangeUrl = { 134 | url: 'https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/Exchange', //兑换商品接口 135 | headers: { //请求头 136 | 'Content-Type': 'application/json', //声明请求体数据格式 137 | 'Cookie': cookie //用户鉴权Cookie 138 | }, 139 | body: JSON.stringify({ //请求体转成字符串类型 140 | product_id: user.list.id, //兑换的商品id 141 | product_num: num, //兑换的商品数量 142 | point: num * user.list.real_cost //消耗的积分总数 (兑换数量乘单价得到积分总数) 143 | }) 144 | }; 145 | for (let i = 0; i < parseInt(exchangeNum); i++) { //根据全局变量定义的次数, 暴力循环抢购 146 | // 循环内调用另一个抢购函数, 并传入请求、第几次循环、兑换数量等参数, 147 | // 使用await关键字声明, 表示需要等待每一次的执行结果 148 | const run = await startExchange(exchangeUrl, i, num); 149 | if (run) { 150 | break; //如果函数返回布尔值true, 则跳出循环, 脚本结束 151 | } 152 | } 153 | } else { //商品无库存或用户积分小于100等情况, 则不执行抢购, 脚本结束 154 | console.log(`\n抢购终止: 不具备兑换条件`); //打印日志 155 | } 156 | resolve(); //将主函数的Promise对象状态标记为"成功", 表示已完成抢购任务 157 | }) 158 | } 159 | 160 | function startExchange(url, item, amount) { 161 | return new Promise((resolve) => { //主函数返回Promise实例对象, 以便后续调用时可以实现顺序执行异步函数 162 | $.post(url, (error, resp, data) => { //使用post请求查询, 再使用回调函数处理返回的结果 163 | try { //使用try方法捕获可能出现的代码异常 164 | if (error) { 165 | throw new Error(error); //如果请求失败, 例如无法联网, 则抛出一个异常 166 | } else { 167 | const body = JSON.parse(data); //解析响应体json并转化为对象 168 | if (body.code == 0) { //如果抢购成功, 则输出日志和通知 169 | console.log(`\n抢购成功: 第${item+1}次\n抢购数量: ${amount}\n消耗积分: ${amount * user.list.real_cost}`); 170 | $.notify('哔哩哔哩漫画抢券', '', `"${productName}"抢购成功, 数量: ${amount}, 消耗积分: ${amount * user.list.real_cost}`); 171 | resolve(true); //将Promise对象的状态标记为"成功", 然后返回一个布尔值true用于跳出循环 172 | } else { 173 | throw new Error(body.msg || '未知'); //抢购失败则抛出异常 174 | } 175 | } 176 | } catch (e) { //接住try代码块中抛出的异常并打印日志 177 | console.log(`\n抢购失败: 第${item+1}次\n失败原因: ${e.message}`); 178 | resolve(); //将Promise对象的状态标记为"成功", 但不返回任何值, 表示继续循环抢购 179 | } 180 | }) 181 | }) 182 | } 183 | 184 | function argsList(data) { 185 | return Array.from( 186 | data.split("&") 187 | .map((i) => i.split("=")) 188 | .map(([k, v]) => [k, decodeURIComponent(v)]) 189 | ) 190 | .reduce((a, [k, v]) => Object.assign(a, { [k]: v }), {}) 191 | } 192 | 193 | function nobyda() { 194 | const isSurge = typeof $httpClient != "undefined"; 195 | const isQuanX = typeof $task != "undefined"; 196 | const isNode = typeof require == "function"; 197 | const node = (() => { 198 | if (isNode) { 199 | const request = require('request'); 200 | return { 201 | request 202 | } 203 | } else { 204 | return null; 205 | } 206 | })() 207 | const adapterStatus = (response) => { 208 | if (response) { 209 | if (response.status) { 210 | response["statusCode"] = response.status 211 | } else if (response.statusCode) { 212 | response["status"] = response.statusCode 213 | } 214 | } 215 | return response 216 | } 217 | this.read = (key) => { 218 | if (isQuanX) return $prefs.valueForKey(key) 219 | if (isSurge) return $persistentStore.read(key) 220 | } 221 | this.notify = (title, subtitle, message) => { 222 | if (isQuanX) $notify(title, subtitle, message) 223 | if (isSurge) $notification.post(title, subtitle, message) 224 | if (isNode) console.log(`${title}\n${subtitle}\n${message}`) 225 | } 226 | this.post = (options, callback) => { 227 | 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' 228 | if (isQuanX) { 229 | if (typeof options == "string") options = { 230 | url: options 231 | } 232 | options["method"] = "POST" 233 | $task.fetch(options).then(response => { 234 | callback(null, adapterStatus(response), response.body) 235 | }, reason => callback(reason.error, null, null)) 236 | } 237 | if (isSurge) { 238 | options.headers['X-Surge-Skip-Scripting'] = false 239 | $httpClient.post(options, (error, response, body) => { 240 | callback(error, adapterStatus(response), body) 241 | }) 242 | } 243 | if (isNode) { 244 | node.request.post(options, (error, response, body) => { 245 | callback(error, adapterStatus(response), body) 246 | }) 247 | } 248 | } 249 | this.done = () => { 250 | if (isQuanX || isSurge) { 251 | $done() 252 | } 253 | } 254 | }; -------------------------------------------------------------------------------- /Bilibili-DailyBonus/Manga.js: -------------------------------------------------------------------------------- 1 | /* 2 | 哔哩哔哩漫画签到 3 | 4 | 脚本兼容:QuantumultX, Surge, Loon 5 | 电报频道:@NobyDa 6 | 问题反馈:@NobyDa_bot 7 | 更新日期:2024/03/18 8 | 如果转载,请注明出处 9 | 10 | 说明: 11 | 打开哔哩哔哩漫画后 (AppStore中国区),单击"我的", 如果通知获取cookie成功, 则可以使用此脚本. 12 | 13 | 脚本将在每天上午9点执行。 您可以修改执行时间。 14 | 15 | ~~~~~~~~~~~~~~~~ 16 | Surge 4.2.0+ : 17 | 18 | [Script] 19 | Bili漫画签到 = type=cron,cronexp=0 9 * * *,wake-system=1,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js 20 | 21 | 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 22 | 23 | [MITM] 24 | hostname = app.bilibili.com 25 | ~~~~~~~~~~~~~~~~ 26 | QX 1.0.10+ : 27 | 28 | [task_local] 29 | 0 9 * * * https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js, tag=Bili漫画签到 30 | 31 | [rewrite_local] 32 | #获取Bili漫画Cookie 33 | ^https:\/\/app\.bilibili\.com\/x\/v2\/account\/myinfo url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js 34 | 35 | [mitm] 36 | hostname = app.bilibili.com 37 | ~~~~~~~~~~~~~~~~ 38 | */ 39 | 40 | const $ = new Env(`哔哩哔哩漫画`); 41 | 42 | const cookie = $.getdata("CookieBM") || ($.isNode() && process.env['CookieBM']) || ''; // 哔哩哔哩漫画Cookie 43 | 44 | const barkKey = $.isNode() && process.env['BM_BARK_KEY'] || ''; // bark key 45 | 46 | if (typeof $request !== 'undefined') { 47 | GetCookie(cookie) 48 | } else if (!cookie) { 49 | $.msg($.name, ``, `签到Cookie失效/未获取 ⚠️`); 50 | $.done(); 51 | } else { 52 | checkin() 53 | } 54 | 55 | function checkin() { 56 | const bilibili = { 57 | url: 'https://manga.bilibili.com/twirp/activity.v1.Activity/ClockIn', 58 | headers: { 59 | Cookie: cookie, 60 | "User-Agent": "comic-universal/1552 CFNetwork/1406.0.4 Darwin/22.4.0 os/ios model/iPhone 12 mobi_app/iphone_comic build/1552 osVer/16.4 network/2 channel/AppStore" 61 | }, 62 | body: "platform=ios" 63 | }; 64 | $.post(bilibili, async function (error, response, data) { 65 | if (error && !data) { 66 | $.msgBody = `请求失败!\n${error}`; 67 | } else if (data.includes(`"code":0`)) { 68 | $.msgBody = "签到成功!🎉"; 69 | } else if (data.includes(`"code":1`)) { 70 | $.msgBody = "签到失败,今日已签过 ⚠️"; 71 | } else if (data.includes(`"invalid_argument"`)) { 72 | $.msgBody = "签到失败,Cookie失效(已清除) ⚠️"; 73 | $.setdata("", "CookieBM"); 74 | } else { 75 | $.msgBody = `签到失败 ‼️\n${data}`; 76 | } 77 | if (barkKey) { 78 | await BarkNotify($, barkKey, $.name, $.msgBody); 79 | } 80 | $.msg($.name, ``, $.msgBody); 81 | $.done(); 82 | }) 83 | } 84 | 85 | function GetCookie(oldCookie) { 86 | const req = JSON.stringify($request); 87 | if (!req.includes(`_comic`)) { 88 | $.log($.name, `非${$.name}客户端URL请求,跳过脚本 ⚠️`); 89 | } else if (!req.includes(`SESSDATA=`)) { 90 | $.msg($.name, ``, `获取Cookie失败,关键值缺失 ⚠️`); 91 | } else { 92 | const cookieValue = req.split(/(SESSDATA=.+?;)/)[1]; 93 | const setCookie = $.setdata(cookieValue, `CookieBM`); 94 | if (oldCookie) { 95 | $.log($.name, `更新Cookie${setCookie ? `成功 🎉` : `失败 ⚠️`}`); 96 | } else { 97 | $.msg($.name, ``, `获取Cookie${setCookie ? `成功 🎉` : `失败 ⚠️`}`); 98 | } 99 | } 100 | $.done() 101 | } 102 | 103 | //Bark APP notify 104 | 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}`) } } }; 105 | 106 | // https://github.com/chavyleung/scripts/blob/master/Env.min.js 107 | 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) } -------------------------------------------------------------------------------- /Debug/Real-time-debug.js: -------------------------------------------------------------------------------- 1 | /* 2 | * LAN script real-time debug 3 | * 4 | * PC: Use "Live Server" plugin in VSCode to create a LAN backend 5 | * APP: After backend address is modified in script, use this script as script path 6 | */ 7 | 8 | !async function() { 9 | const _$ = new nobyda(); 10 | const _r = await new Promise(e => { 11 | _$.get({ 12 | url: 'http://192.168.1.66:5500/debug.js' // LAN backend address 13 | }, (t, c, o) => { 14 | if (c && c.status == 200 && o) { 15 | _$.write(o, 'Real-time-debug'); 16 | e(o); 17 | } 18 | }); 19 | setTimeout(e, 100); 20 | }); 21 | if (_r) { 22 | console.log("🌐 Run local network script..."); 23 | eval(_r); 24 | } else { 25 | console.log("⚠️ Run cache script..."); 26 | eval(_$.read('Real-time-debug')) 27 | } 28 | 29 | function nobyda() { 30 | const isSurge = typeof $httpClient != "undefined"; 31 | const isQuanX = typeof $task != "undefined"; 32 | const adapterStatus = (response) => { 33 | if (response) { 34 | if (response.status) { 35 | response["statusCode"] = response.status 36 | } else if (response.statusCode) { 37 | response["status"] = response.statusCode 38 | } 39 | } 40 | return response 41 | }; 42 | this.write = (value, key) => { 43 | if (isQuanX) return $prefs.setValueForKey(value, key); 44 | if (isSurge) return $persistentStore.write(value, key); 45 | }; 46 | this.read = (key) => { 47 | if (isQuanX) return $prefs.valueForKey(key); 48 | if (isSurge) return $persistentStore.read(key); 49 | }; 50 | this.get = (options, callback) => { 51 | if (isQuanX) { 52 | $task.fetch(options).then(response => { 53 | callback(null, adapterStatus(response), response.body) 54 | }, reason => callback(reason.error, null, null)) 55 | } 56 | if (isSurge) { 57 | $httpClient.get(options, (error, response, body) => { 58 | callback(error, adapterStatus(response), body) 59 | }) 60 | } 61 | }; 62 | this.done = (value = {}) => $done(value) 63 | } 64 | }(); -------------------------------------------------------------------------------- /Disney/DisneyRating.js: -------------------------------------------------------------------------------- 1 | /********************************* 2 | Disney+ 显示IMDb评分 / 烂番茄评分 / 豆瓣评分 3 | 4 | 脚本作者: @NobyDa 5 | 脚本兼容: Surge、QuantumultX、Loon 6 | 系统兼容: iOS14+ 7 | 更新时间: 2024/05/04 8 | 脚本参考: https://github.com/yichahucha/surge/blob/master/nf_rating.js 9 | 10 | Surge模块: 11 | https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/DisneyRating.sgmodule 12 | 13 | QuantumultX重写引用: 14 | https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/DisneyRating.snippet 15 | 16 | *********************************/ 17 | 18 | const $tool = new Tool(); 19 | const consoleLog = false; 20 | let obj = $response.body; 21 | let IMDbApikeys = IMDbApikeyList(); 22 | let IMDbApikey = $tool.read("ImdbApikeyCacheKey"); 23 | if (!IMDbApikey) { 24 | updateIMDbApikey(); 25 | } 26 | 27 | const requestRatings = async () => { 28 | if (consoleLog) console.log("Disney Original Body:\n" + obj); 29 | obj = JSON.parse(obj); 30 | const sliced = obj?.data?.page?.actions?.[0]?.internalTitle?.split(' - '); 31 | let title = sliced?.[0] || obj?.data?.page?.visuals?.title; 32 | if (title) { 33 | title = title.replace(/.+?:\s|\s?\(.+?\)\s?/g,''); 34 | } else { 35 | throw 'NO TITLE'; 36 | } 37 | const year = obj?.data?.page?.visuals?.metastringParts?.releaseYearRange?.startYear; 38 | const type = (sliced?.[1]?.startsWith('s') && 'series') || (sliced?.[1] == 'movie' && 'movie'); 39 | const IMDb = await requestIMDbRating(title, year, type); 40 | const Douban = await requestDoubanRating(IMDb.id); 41 | const IMDbrating = IMDb.msg.rating; 42 | const tomatoes = IMDb.msg.tomatoes; 43 | const country = IMDb.msg.country; 44 | // const awards = IMDb.msg.awards; 45 | const doubanRating = Douban.rating; 46 | // const message = `${awards.length > 0 ? awards + "\n" : ""}${country}\n${IMDbrating}\n${doubanRating}${tomatoes.length > 0 ? "\n" + tomatoes + "\n" : "\n"}`; 47 | return { country, tomatoes, IMDbrating, doubanRating }; 48 | } 49 | 50 | requestRatings() 51 | .then(data => { 52 | if (obj?.data?.page?.visuals) { 53 | obj.data.page.visuals.promoLabel = { 54 | promoLabelType: "generic", 55 | header: `${data.country}${data.tomatoes ? `\n${data.tomatoes}` : ``}`, 56 | subheader: `${data.IMDbrating}${data.doubanRating ? `\n${data.doubanRating}` : ``}` 57 | } 58 | } 59 | if (consoleLog) console.log("Disney Modified Body:\n" + JSON.stringify(obj)); 60 | }) 61 | .catch(error => console.log(`ERROR: ${error}`)) 62 | .finally(() => $done({ body: typeof obj == 'object' ? JSON.stringify(obj) : obj })); 63 | 64 | function requestDoubanRating(imdbId) { 65 | return new Promise(function (resolve, reject) { 66 | const url = `https://www.douban.com/search?cat=1002&q=${imdbId}`; 67 | if (consoleLog) console.log("Disney Douban Rating URL:\n" + url); 68 | $tool.get(url, function (error, response, data) { 69 | if (!error) { 70 | if (consoleLog) console.log("Disney Douban Rating Data:\n" + data); 71 | if (response.status == 200) { 72 | const rating = get_douban_rating_message(data); 73 | resolve({ rating }); 74 | } else { 75 | resolve({}); 76 | } 77 | } else { 78 | console.log("Disney Douban Rating Error: " + error); 79 | resolve({}); 80 | } 81 | }); 82 | }); 83 | } 84 | 85 | function requestIMDbRating(title, year, type) { 86 | return new Promise(function (resolve, reject) { 87 | let url = "https://www.omdbapi.com/?t=" + encodeURIComponent(title) + "&apikey=" + IMDbApikey; 88 | if (year) url += "&y=" + year; 89 | if (type) url += "&type=" + type; 90 | if (consoleLog) console.log("Disney IMDb Rating URL:\n" + url); 91 | $tool.get(url, function (error, response, data) { 92 | if (!error) { 93 | if (consoleLog) console.log("Disney IMDb Rating Data:\n" + data); 94 | if (response.status == 200) { 95 | const obj = JSON.parse(data); 96 | if (obj.Response == "True") { 97 | const id = obj.imdbID; 98 | const msg = get_IMDb_message(obj); 99 | resolve({ id, msg }); 100 | } else { 101 | reject(`Title [${title}] IMDb data not found`); 102 | } 103 | } else if (response.status == 401) { 104 | if (IMDbApikeys.length > 1) { 105 | updateIMDbApikey(); 106 | requestIMDbRating(title, year, type); 107 | } else { 108 | reject(`IMDb Key invalid`); 109 | } 110 | } else { 111 | reject(`Unknown status: ${response.status}, Data: ${data}`); 112 | } 113 | } else { 114 | reject(`IMDB data response failed: ${error}`); 115 | } 116 | }); 117 | }); 118 | } 119 | 120 | function updateIMDbApikey() { 121 | if (IMDbApikey) IMDbApikeys.splice(IMDbApikeys.indexOf(IMDbApikey), 1); 122 | const index = Math.floor(Math.random() * IMDbApikeys.length); 123 | IMDbApikey = IMDbApikeys[index]; 124 | $tool.write(IMDbApikey, "ImdbApikeyCacheKey"); 125 | } 126 | 127 | function get_IMDb_message(data) { 128 | let rating_message = "IMDb: ⭐️ N/A"; 129 | let tomatoes_message = ""; 130 | let country_message = ""; 131 | let ratings = data.Ratings; 132 | let awards_message = ""; 133 | if (data.Awards && data.Awards != "N/A") { 134 | awards_message = "🏆 " + data.Awards; 135 | } 136 | if (ratings.length > 0) { 137 | const imdb_source = ratings[0]["Source"]; 138 | if (imdb_source == "Internet Movie Database") { 139 | const imdb_votes = data.imdbVotes; 140 | const imdb_rating = ratings[0]["Value"]; 141 | rating_message = "IMDb: ⭐️ " + imdb_rating + " " + imdb_votes; 142 | if (data.Type == "movie") { 143 | if (ratings.length > 1) { 144 | const source = ratings[1]["Source"]; 145 | if (source == "Rotten Tomatoes") { 146 | const tomatoes = ratings[1]["Value"]; 147 | tomatoes_message = "Tomatoes: 🍅 " + tomatoes; 148 | } 149 | } 150 | } 151 | } 152 | } 153 | country_message = get_country_message(data.Country); 154 | return { rating: rating_message, tomatoes: tomatoes_message, country: country_message, awards: awards_message } 155 | } 156 | 157 | function get_douban_rating_message(data) { 158 | const s = data.replace(/\n| |&#\d{2}/g, '') 159 | .match(/\[(\u7535\u5f71|\u7535\u89c6\u5267)\].+?subject-cast\">.+?<\/span>/g); 160 | const average = s ? s[0].split(/">(\d\.\d) { 171 | emoji_country += countryEmoji(item) + " " + item + ", "; 172 | }); 173 | return emoji_country.slice(0, -2); 174 | } 175 | 176 | // function errorTip() { 177 | // return { noData: "⭐️ N/A", error: "❌ N/A" } 178 | // } 179 | 180 | function IMDbApikeyList() { 181 | const apikeys = [ 182 | "f75e0253", "d8bb2d6b", 183 | "ae64ce8d", "7218d678", 184 | "b2650e38", "8c4a29ab", 185 | "9bd135c2", "953dbabe", 186 | "1a66ef12", "3e7ea721", 187 | "457fc4ff", "d2131426", 188 | "9cc1a9b7", "e53c2c11", 189 | "f6dfce0e", "b9db622f", 190 | "e6bde2b9", "d324dbab", 191 | "d7904fa3", "aeaf88b9", 192 | "4e89234e",]; 193 | return apikeys; 194 | } 195 | 196 | 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"] } 197 | 198 | function Tool() { 199 | _node = (() => { 200 | if (typeof require == "function") { 201 | const request = require('request') 202 | return ({ request }) 203 | } else { 204 | return (null) 205 | } 206 | })() 207 | _isSurge = typeof $httpClient != "undefined" 208 | _isQuanX = typeof $task != "undefined" 209 | this.isSurge = _isSurge 210 | this.isQuanX = _isQuanX 211 | this.isResponse = typeof $response != "undefined" 212 | this.notify = (title, subtitle, message) => { 213 | if (_isQuanX) $notify(title, subtitle, message) 214 | if (_isSurge) $notification.post(title, subtitle, message) 215 | if (_node) console.log(JSON.stringify({ title, subtitle, message })); 216 | } 217 | this.write = (value, key) => { 218 | if (_isQuanX) return $prefs.setValueForKey(value, key) 219 | if (_isSurge) return $persistentStore.write(value, key) 220 | } 221 | this.read = (key) => { 222 | if (_isQuanX) return $prefs.valueForKey(key) 223 | if (_isSurge) return $persistentStore.read(key) 224 | } 225 | this.get = (options, callback) => { 226 | if (_isQuanX) { 227 | if (typeof options == "string") options = { url: options } 228 | options["method"] = "GET" 229 | $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) 230 | } 231 | if (_isSurge) $httpClient.get(options, (error, response, body) => { callback(error, _status(response), body) }) 232 | if (_node) _node.request(options, (error, response, body) => { callback(error, _status(response), body) }) 233 | } 234 | this.post = (options, callback) => { 235 | if (_isQuanX) { 236 | if (typeof options == "string") options = { url: options } 237 | options["method"] = "POST" 238 | $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) 239 | } 240 | if (_isSurge) $httpClient.post(options, (error, response, body) => { callback(error, _status(response), body) }) 241 | if (_node) _node.request.post(options, (error, response, body) => { callback(error, _status(response), body) }) 242 | } 243 | _status = (response) => { 244 | if (response) { 245 | if (response.status) { 246 | response["statusCode"] = response.status 247 | } else if (response.statusCode) { 248 | response["status"] = response.statusCode 249 | } 250 | } 251 | return response 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /IPA-Installer/IPA-Installer-JSBox.js: -------------------------------------------------------------------------------- 1 | /* 2 | * IPA-installer JSBox script. This script is not available stand alone, checkout the demo from TG channel @NobyDa 3 | * 4 | * Modified from https://github.com/axelburks/JSBox/blob/master/IPA%20Installer.js by @NobyDa 5 | */ 6 | 7 | var port_number = 8070 8 | 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` 9 | 10 | $app.strings = { 11 | "en": { 12 | "starterror": "Not support running in this way", 13 | "ftypeerror": " is not ipa file", 14 | "installtitle": "Installing...", 15 | "installmsg": "\n\nYou can check on Homescreen.\nPlease tap \"Done\" button after finished", 16 | "inerrtitle": "IPA file import error", 17 | "inerrmsg": "Please rerun the script" 18 | }, 19 | "zh-Hans": { 20 | "starterror": "不支持此方式运行!", 21 | "ftypeerror": " 非 ipa 文件!", 22 | "installtitle": "正在安装…", 23 | "installmsg": "\n\n可前往桌面查看安装进度\n完成后请点击\"Done\"按钮", 24 | "inerrtitle": "IPA文件导入失败", 25 | "inerrmsg": "请重新运行此脚本" 26 | } 27 | } 28 | 29 | // 从应用内启动 30 | if ($app.env == $env.app) { 31 | $drive.open({ 32 | handler: function(data) { 33 | fileCheck(data) 34 | } 35 | }) 36 | } 37 | // 从 Action Entension 启动 38 | else if ($app.env == $env.action) { 39 | fileCheck($context.data) 40 | } 41 | 42 | else { 43 | $ui.error($l10n("starterror")) 44 | delayClose(2) 45 | } 46 | 47 | 48 | function startServer(port) { 49 | $http.startServer({ 50 | port: port, 51 | path: "", 52 | handler: function(result) { 53 | console.info(result.url) 54 | } 55 | }) 56 | } 57 | 58 | function fileCheck(data) { 59 | if (data && data.fileName) { 60 | var fileName = data.fileName; 61 | if (fileName.indexOf(".ipa") == -1) { 62 | $ui.error(fileName + $l10n("ftypeerror")) 63 | delayClose(2) 64 | } else { 65 | install(fileName, data); 66 | } 67 | } 68 | } 69 | 70 | function install(fileName, file) { 71 | var result = $file.write({ 72 | data: file, 73 | path: "app.ipa" 74 | }) 75 | if (result) { 76 | startServer(port_number) 77 | $location.startUpdates({ 78 | handler: function(resp) { 79 | console.info(resp.lat + " " + resp.lng + " " + resp.alt) 80 | } 81 | }) 82 | var preResult = $app.openURL(plist_url); 83 | if (preResult) { 84 | $ui.alert({ 85 | title: $l10n("installtitle"), 86 | message: "\n" + fileName + $l10n("installmsg"), 87 | actions: [{ 88 | title: "Cancel", 89 | style: "Cancel", 90 | handler: function() { 91 | $http.stopServer() 92 | $file.delete("app.ipa") 93 | delayClose(0.2) 94 | } 95 | }, 96 | { 97 | title: "Done", 98 | handler: function() { 99 | $http.stopServer() 100 | $file.delete("app.ipa") 101 | delayClose(0.2) 102 | } 103 | }] 104 | }) 105 | } else { 106 | $ui.alert({ 107 | title: "Open itms-services scheme failed", 108 | message: "Please rerun the script or restart device", 109 | actions: [ 110 | { 111 | title: "OK", 112 | handler: function() { 113 | delayClose(0.2) 114 | } 115 | }] 116 | }) 117 | } 118 | } else { 119 | $ui.alert({ 120 | title: $l10n("inerrtitle"), 121 | message: $l10n("inerrmsg"), 122 | actions: [{ 123 | title: "OK", 124 | style: "Cancel", 125 | handler: function() { 126 | delayClose(0.2) 127 | } 128 | }] 129 | }) 130 | } 131 | } 132 | 133 | function delayClose(time) { 134 | $location.stopUpdates() 135 | $thread.main({ 136 | delay: time, 137 | handler: function() { 138 | if ($app.env == $env.action || $app.env == $env.safari) { 139 | $context.close() 140 | } 141 | $app.close() 142 | } 143 | }) 144 | } 145 | -------------------------------------------------------------------------------- /IPA-Installer/IPA-Installer-Pythonista.py: -------------------------------------------------------------------------------- 1 | # IPA-installer pythonista script. This script is not available stand alone, checkout the demo from TG channel @NobyDa 2 | # 3 | # Modified from https://github.com/axelburks/Pythonista/blob/master/IPA%20Installer.py by @NobyDa 4 | 5 | import os, appex, console, shutil, http.server, webbrowser, time 6 | from os import path 7 | from threading import Thread 8 | 9 | port_number = 8090 10 | 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' 11 | save_dir = path.expanduser('./ipa') 12 | if not path.exists(save_dir): 13 | os.makedirs(save_dir) 14 | 15 | httpd = None 16 | def startServer(port): 17 | Handler = http.server.SimpleHTTPRequestHandler 18 | 19 | global httpd 20 | httpd = http.server.HTTPServer(("", port), Handler) 21 | 22 | print("Start server at port", port) 23 | httpd.serve_forever() 24 | 25 | def start(port): 26 | thread = Thread(target=startServer, args=[port]) 27 | thread.start() 28 | 29 | startTime = int(time.time()) 30 | while not httpd: 31 | if int(time.time()) > startTime + 60: 32 | print("Time out") 33 | break 34 | return httpd 35 | 36 | def stop(): 37 | if httpd: 38 | httpd.shutdown() 39 | 40 | def main(): 41 | if appex.is_running_extension(): 42 | get_path = appex.get_file_path() 43 | file_name = path.basename(get_path) 44 | file_ext = path.splitext(file_name)[-1] 45 | if file_ext == '.ipa': 46 | dstpath = path.join(save_dir, 'app.ipa') 47 | try: 48 | shutil.copy(get_path, dstpath) 49 | 50 | except Exception as eer: 51 | print(eer) 52 | console.hud_alert('导入失败!','error',1) 53 | start(port_number) 54 | if httpd: 55 | webbrowser.open(plist_url) 56 | try: 57 | finish = console.alert(file_name, '\n正在安装...请返回桌面查看进度...\n\n安装完成后请返回点击已完成','已完成', hide_cancel_button=False) 58 | if finish == 1: 59 | stop() 60 | shutil.rmtree('./ipa') 61 | print("Server stopped") 62 | except: 63 | stop() 64 | shutil.rmtree('./ipa') 65 | print("Cancelled") 66 | appex.finish() 67 | else: 68 | console.hud_alert('非 ipa 文件无法导入安装', 'error', 2) 69 | appex.finish() 70 | else: 71 | console.hud_alert('请在分享扩展中打开本脚本','error',2) 72 | 73 | if __name__ == '__main__': 74 | main() -------------------------------------------------------------------------------- /IPA-Installer/IPA-Installer.js: -------------------------------------------------------------------------------- 1 | /* 2 | * iOS IPA应用辅助安装脚本. 3 | * 4 | * 兼容: QuantumultX、Surge5,Loon、Shadowrocket、Stash 5 | * 作者: @NobyDa 6 | * 7 | * 快捷指令 + Shu配合安装: 8 | * 导入IPA文件至Shu -> Shu长按IPA文件 -> 导出文件 -> WiFi传输 -> 本机 -> 系统共享 -> 分享至IPA-Installer快捷指令 9 | * 10 | * 快捷指令 + JSBox/Pythonista配合安装: 11 | * IPA文件长按分享至IPA-Installer快捷指令(iOS14跳过),完成后再分享至Jsbox/pythonista分享扩展. 12 | * 13 | * 14 | * QuanX重写: https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/IPA-Installer.snippet 15 | * 16 | * Surge模块: https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/IPA_install.sgmodule 17 | * 18 | * loon插件: https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_IPA_Installer.plugin 19 | * 20 | * Stash覆写: https://raw.githubusercontent.com/NobyDa/Script/master/Stash/IPA-Installer.stoverride 21 | * 22 | * 快捷指令(iOS15+): https://www.icloud.com/shortcuts/4a121aa54cae4619a952baa29e044e30 23 | * 24 | * 快捷指令(iOS14): https://www.icloud.com/shortcuts/179dfcd7505e44f89207086d2b1a32ea 25 | * 26 | * 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 27 | * 28 | * Pythonista脚本: https://github.com/NobyDa/Script/blob/master/IPA-Installer/IPA-Installer-Pythonista.py 29 | */ 30 | 31 | const $ = new compatible_tool(); 32 | 33 | (async function () { 34 | const args = urlArgs($request.url); 35 | const plist = ` 36 | 37 | 38 | 39 | items 40 | 41 | 42 | assets 43 | 44 | 45 | kind 46 | software-package 47 | url 48 | https://nobyda.app/download?url=${encodeURIComponent(args.url)} 49 | 50 | 51 | metadata 52 | 53 | bundle-identifier 54 | ${args.bundleId || $.read("nobyda_ipa_bundle_id") || "*"} 55 | bundle-version 56 | 1.0 57 | kind 58 | software 59 | title 60 | IPA 61 | 62 | 63 | 64 | 65 | `; 66 | if ($request.url.includes("/install?")) { 67 | if (args.bundleId) { 68 | $.write(args.bundleId, "nobyda_ipa_bundle_id"); 69 | }; 70 | $.resp = { response: { status: 200, body: args.client && plist || "{}" } }; 71 | } else { 72 | if ($request.method == "GET") { 73 | const size = await ipaSize(args.url); 74 | $.notify(`IPA Installer`, ``, size && `Installing IPA, Size: ${size} MB` || `HTTP local server read failed!`); 75 | } 76 | $.resp = { response: { status: 307, headers: { Location: args.url }, body: "{}" } }; 77 | } 78 | })() 79 | .catch((e) => $.notify(`IPA Installer`, ``, `ERROR: ${e.message || e}\nPATH: ${e.stack}`)) 80 | .finally(() => $.done($.resp)) 81 | 82 | 83 | function ipaSize(url) { 84 | return new Promise((r, e) => { 85 | $.http({ method: "head", url: url, policy: "DIRECT", }, (e, h, d) => { 86 | r(h && h.status == 200 && `${((h.headers["Content-Length"] || 0) / 1000 / 1000).toFixed(2)}`) 87 | }); 88 | setTimeout(() => r(), 1000) 89 | }); 90 | } 91 | 92 | function urlArgs(str) { 93 | return Object.fromEntries( 94 | (str.startsWith("http") && str.split("?")[1] || str).split("&") 95 | .map((item) => item.split("=")) 96 | .map(([k, v]) => [k, decodeURIComponent(v)]) 97 | ); 98 | } 99 | 100 | function compatible_tool() { 101 | const isSurge = typeof $httpClient != "undefined"; 102 | const isQuanX = typeof $task != "undefined"; 103 | const isStash = typeof $environment == "object" && $environment["stash-version"]; 104 | const adapterStatus = (response) => { 105 | if (response && response.statusCode) { 106 | response.status = response.statusCode; 107 | } 108 | return response 109 | }; 110 | this.read = (key) => { 111 | if (isQuanX) return $prefs.valueForKey(key); 112 | if (isSurge) return $persistentStore.read(key); 113 | }; 114 | this.write = (value, key) => { 115 | if (isQuanX) return $prefs.setValueForKey(value, key); 116 | if (isSurge) return $persistentStore.write(value, key); 117 | }; 118 | this.notify = (title, subtitle, message) => { 119 | if (isQuanX) $notify(title, subtitle, message); 120 | if (isSurge) $notification.post(title, subtitle, message); 121 | }; 122 | this.http = (options, callback) => { 123 | if (options.policy) { 124 | options.node = options.policy; 125 | options.opts = { policy: options.policy }; 126 | if (isStash) options.headers = { 127 | ...options.headers, 128 | ...{ "X-Stash-Selected-Proxy": encodeURIComponent(options.policy) } 129 | }; 130 | } 131 | if (isQuanX) { 132 | $task.fetch(options).then(response => { 133 | callback(null, adapterStatus(response), response.body) 134 | }, reason => callback(reason.error, null, null)) 135 | } 136 | if (isSurge) { 137 | $httpClient[options.method](options, (error, response, body) => { 138 | callback(error, adapterStatus(response), body) 139 | }) 140 | } 141 | }; 142 | this.done = (value = {}) => { 143 | if (value.response && isQuanX) { 144 | value.response.status = `HTTP/1.1 ${value.response.status}`; 145 | } 146 | $done((value.response && isQuanX) ? value.response : value) 147 | } 148 | }; -------------------------------------------------------------------------------- /KuaiKan-DailyBonus/KKMH.js: -------------------------------------------------------------------------------- 1 | /* 2 | 快看漫画签到脚本 3 | 4 | 更新时间: 2022.06.18 5 | 脚本兼容: QuantumultX, Surge4, Loon, Node.js 6 | 电报频道: @NobyDa 7 | 问题反馈: @NobyDa_bot 8 | 9 | 获取Cookie说明: 10 | 打开快看漫画App后(AppStore中国区),点击"我的", 如通知成功获取cookie, 则可以使用此签到脚本. 11 | 获取Cookie后, 请将Cookie脚本禁用并移除主机名,以免产生不必要的MITM. 12 | 脚本将在每天上午9:00执行, 您可以修改执行时间。 13 | 14 | 如果使用Node.js, 需自行安装got与tough-cookie模块. 例: npm install got tough-cookie -g 15 | 16 | Node.js用户抓取Cookie说明: 17 | 开启抓包, 打开快看漫画App后(AppStore中国区),点击"我的" 返回抓包app搜索关键字 passport/user 复制请求头Cookie填入以下cookie处的单引号内即可 18 | */ 19 | 20 | var cookie = '' 21 | 22 | var barkKey = ''; //Bark APP 通知推送key 23 | 24 | /********************* 25 | QuantumultX 远程脚本配置: 26 | ********************** 27 | [task_local] 28 | 0 9 * * * https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js, tag=快看漫画, img-url=https://ftp.bmp.ovh/imgs/2020/09/a3345da5e9094363.png, enabled=true 29 | 30 | [rewrite_local] 31 | # 获取Cookie 32 | ^https:\/\/api\.kkmh\.com\/v\d\/passport\/user url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js 33 | 34 | [mitm] 35 | hostname= api.kkmh.com 36 | 37 | ********************** 38 | Surge 4.2.0+ 脚本配置: 39 | ********************** 40 | [Script] 41 | 快看漫画签到 = type=cron,cronexp=0 9 * * *,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js 42 | 43 | 快看漫画获取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 44 | 45 | [MITM] 46 | hostname= api.kkmh.com 47 | 48 | ************************ 49 | Loon 2.1.0+ 脚本配置: 50 | ************************ 51 | 52 | [Script] 53 | # 快看漫画签到 54 | cron "0 9 * * *" script-path=https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js 55 | 56 | # 获取Cookie 57 | http-request ^https:\/\/api\.kkmh\.com\/v\d\/passport\/user script-path=https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js 58 | 59 | [Mitm] 60 | hostname= api.kkmh.com 61 | 62 | */ 63 | var LogDetails = false; //响应日志 64 | var $ = new Env('快看漫画'); 65 | var date = new Date() 66 | var imgUrl = { 67 | 'open-url': 'kuaikan://', 68 | 'media-url': 'https://ftp.bmp.ovh/imgs/2020/09/16da56c186ffa6a2.png' 69 | }; 70 | 71 | (async () => { 72 | if (typeof $request != "undefined") { 73 | GetCookie() 74 | } else if (cookie || $.getdata("@KKMH.COOKIE")) { 75 | if (cookie) $.setdata(cookie, "@KKMH.COOKIE"); 76 | LogDetails = $.getdata("@KKMH.LOG") === "true" || LogDetails 77 | await Checkin(); 78 | } else { 79 | $.msg($.name, "", "签到终止, 未获取Cookie ⚠️", imgUrl); 80 | } 81 | })().finally(() => { 82 | $.done(); 83 | }) 84 | 85 | function Checkin() { 86 | return new Promise(resolve => { 87 | $.get({ 88 | url: 'https://h5.kuaikanmanhua.com/v2/checkin/task_center/checkin', 89 | headers: { 90 | 'Cookie': cookie || $.getdata("@KKMH.COOKIE"), 91 | 'User-Agent': 'Kuaikan/5.75.0/575000(iPhone;Scale/3.00) (iPhone; CPU)', 92 | 'X-Device': '0' 93 | } 94 | }, async (error, response, data) => { 95 | try { 96 | if (error) throw new Error(error) 97 | const cc = JSON.parse(data) 98 | const Details = LogDetails ? data ? `response:\n${data}` : '' : '' 99 | if (cc.code == 200) { 100 | $.log(`${$.name} 成功${Details}`) 101 | const pop = cc.data.check_in_home_info.pop_title 102 | const text = cc.data.check_in_home_info.check_in_bubble_text 103 | const title = cc.data.check_in_home_info.check_in_title 104 | const score = cc.data.check_in_home_info.user_score 105 | const kkb = cc.data.check_in_home_info.user_kkb 106 | const uid = $.getdata("@KKMH.COOKIE") ? $.getdata("@KKMH.COOKIE").match(/uid=(\d+)/) : '' 107 | const rep = $.getdata("@KKMH.DATE") == date.getDate() && (uid ? uid[1] : '') == $.getdata("@KKMH.UID") 108 | const gift = await GiftPack(title); 109 | $.subtitle = rep ? '今天已签过!' : pop; 110 | $.msgBody = `${rep?``:text+', '}现有${$.score||score}积分, ${$.kkb||kkb}KK币\n${gift||title} 🎉`; 111 | $.setdata(JSON.stringify(date.getDate()), "@KKMH.DATE") 112 | $.setdata(uid ? uid[1] : '', "@KKMH.UID") 113 | } else { 114 | $.log(`${$.name} 失败${Details}`) 115 | if (cc.code == 401) { 116 | $.msgBody = 'Cookie失效 ⚠️'; 117 | } else { 118 | $.msgBody = cc.message || '未知错误 ⚠️'; 119 | } 120 | } 121 | } catch (err) { 122 | $.logErr(err) 123 | $.msgBody = `错误, 已输出日志 ⚠️`; 124 | } finally { 125 | $.msg($.name, $.subtitle || '', $.msgBody, imgUrl); 126 | if (barkKey) { 127 | await BarkNotify($, barkKey, $.name, $.msgBody); 128 | } 129 | resolve() 130 | } 131 | }) 132 | }) 133 | } 134 | 135 | function GiftPack(type) { 136 | return new Promise(resolve => { 137 | if (!type.match(/今(日|天)可领/)) return resolve(); 138 | $.get({ 139 | url: 'https://h5.kuaikanmanhua.com/v1/checkin/api/check/open_gift_bag', 140 | headers: { 141 | 'Cookie': cookie || $.getdata("@KKMH.COOKIE"), 142 | 'User-Agent': 'Kuaikan/5.75.0/575000(iPhone;Scale/3.00) (iPhone; CPU)', 143 | 'X-Device': '0' 144 | } 145 | }, (error, response, data) => { 146 | try { 147 | if (error) throw new Error(error) 148 | const cc = JSON.parse(data) 149 | const Details = LogDetails ? data ? `response:\n${data}` : '' : '' 150 | if (cc.code == 200 && cc.data) { 151 | $.log(`${$.name} 成功${Details}`) 152 | $.kkb = cc.data.giftBagKkb ? cc.data.giftBagKkb + cc.data.kkb : cc.data.kkb 153 | $.score = cc.data.score; 154 | $.gifts = `领取连签礼包成功`; 155 | if (cc.data.giftBagScore) $.gifts += `, +${cc.data.giftBagScore}积分`; 156 | if (cc.data.giftBagKkb) $.gifts += `, +${cc.data.giftBagKkb}KK币`; 157 | if (cc.data.giftBagSupplement) $.gifts += `, +1 补签胶囊`; 158 | if (cc.data.giftBagCardCoupon) $.gifts += `, +1 ${cc.data.cardCoupon.title}`; 159 | if (cc.data.giftBagYouzanCoupon) $.gifts += `, +1 ${cc.data.youzanCoupon.title}`; 160 | } else { 161 | $.log(`${$.name} 失败${Details}`) 162 | $.gifts = `领取连签礼包失败, ${cc.message || '未知错误'}` 163 | } 164 | } catch (err) { 165 | $.logErr(err) 166 | $.gifts = `领取连签礼包错误, 已输出日志` 167 | } finally { 168 | resolve($.gifts) 169 | } 170 | }) 171 | }) 172 | } 173 | 174 | function GetCookie() { 175 | const RA = $.getdata("@KKMH.COOKIE") 176 | const TM = $.getdata("@KKMH.TIME") 177 | const CK = $request.headers['Cookie'] || $request.headers['cookie']; 178 | if (JSON.stringify($request.headers).match(/session=/) && CK) { 179 | if (RA != CK) { 180 | if ($.setdata(CK, "@KKMH.COOKIE")) { 181 | $.setdata(JSON.stringify(Date.now()), "@KKMH.TIME") 182 | if (!TM || TM && (Date.now() - TM) / 1000 >= 21600) { 183 | $.msg(`${RA?`更新`:`首次写入`}${$.name}Cookie成功 🎉`, "", "", imgUrl) 184 | } else if (RA.match(/uid=\d+/)[0] == CK.match(/uid=\d+/)[0]) { 185 | $.log(`\n更新${$.name}Cookie成功! 🎉\n检测到频繁通知, 已转为输出日志`) 186 | } else { 187 | $.msg(`更新${$.name}Cookie成功 🎉`, "", "", imgUrl) 188 | } 189 | } else { 190 | $.msg(`${RA?`更新`:`首次写入`}${$.name}Cookie失败‼️`, "", "", imgUrl) 191 | } 192 | } else { 193 | $.log(`${$.name}-Cookie相同, 跳过写入 ⚠️`) 194 | } 195 | } else { 196 | $.log(`${$.name}-请求不含Cookie, 跳过写入 ‼️`) 197 | } 198 | } 199 | 200 | //Bark APP notify 201 | 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}`)}}} 202 | 203 | //Compatible code from https://github.com/chavyleung/scripts/blob/master/Env.min.js 204 | 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)} -------------------------------------------------------------------------------- /Loon/Loon_Bahamut_ADS.plugin: -------------------------------------------------------------------------------- 1 | #!name= 巴哈姆特动画疯 2 | #!desc= 该Loon插件用以屏蔽动画疯播放广告 (由于强制验证观看广告时间,故以黑屏25秒的方式屏蔽) 3 | #!author= NobyDa 4 | #!homepage= https://github.com/NobyDa/Script/tree/master 5 | #!icon= https://raw.githubusercontent.com/NobyDa/mini/master/Color/bahamutGame.png 6 | 7 | [Script] 8 | 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=屏蔽动画疯广告 9 | 10 | [MITM] 11 | hostname = api.gamer.com.tw -------------------------------------------------------------------------------- /Loon/Loon_Daily_bonus.plugin: -------------------------------------------------------------------------------- 1 | #!name= 🐻 NobyDa签到脚本 2 | #!desc= 包括哔哩漫画、贴吧、快看、爱奇艺,携程旅行、巴哈姆特。部分脚本获取Cookie方法请看脚本注释。注意,该Loon链接目前仅适用于"订阅脚本",非"插件"。添加脚本订阅后请按需启用脚本。 3 | #!author= NobyDa 4 | #!homepage= https://github.com/NobyDa/Script/tree/master 5 | #!icon= https://raw.githubusercontent.com/github/explore/80688e429a7d4ef2fca1e82350fe8e3517d3494d/topics/javascript/javascript.png 6 | 7 | 8 | [Script] 9 | 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=携程旅行 [签到] 10 | 11 | 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] 12 | 13 | 14 | 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=爱奇艺 [会员签到] 15 | 16 | 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] 17 | 18 | 19 | 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=哔哩漫画 [签到] 20 | 21 | 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] 22 | 23 | 24 | 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=百度贴吧 [签到] 25 | 26 | 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] 27 | 28 | 29 | 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=快看漫画 [签到] 30 | 31 | 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] 32 | 33 | 34 | 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=巴哈姆特 [签到] 35 | 36 | 37 | [MITM] 38 | hostname = passport.iqiyi.com, app.bilibili.com, c.tieba.baidu.com, tiebac.baidu.com, api.kkmh.com, m.ctrip.com -------------------------------------------------------------------------------- /Loon/Loon_GetCookie.plugin: -------------------------------------------------------------------------------- 1 | #!name= NobyDa签到脚本Cookie获取 2 | #!desc= 包括哔哩漫画、贴吧、快看、爱奇艺,携程旅行。获取方法请看脚本注释;建议使用后手动将该插件禁用, 以避免无意义的MITM。 3 | #!author= NobyDa 4 | #!homepage= https://github.com/NobyDa/Script/tree/master 5 | #!icon= https://raw.githubusercontent.com/github/explore/80688e429a7d4ef2fca1e82350fe8e3517d3494d/topics/javascript/javascript.png 6 | 7 | [Script] 8 | http-request ^https:\/\/passport\.iqiyi\.com\/apis\/user\/ script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js, tag=爱奇艺Cookie 9 | 10 | 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 11 | 12 | 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 13 | 14 | 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 15 | 16 | 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 17 | 18 | [MITM] 19 | hostname = passport.iqiyi.com, app.bilibili.com, c.tieba.baidu.com, tiebac.baidu.com, api.kkmh.com, m.ctrip.com -------------------------------------------------------------------------------- /Loon/Loon_Google_CAPTCHA.plugin: -------------------------------------------------------------------------------- 1 | #!name = Google人机验证 2 | #!desc = Google搜索内容时并发使用多个策略/策略组,以避免可能出现的人机验证。注意:需要在插件参数填写策略/策略组名的正则表达式。 3 | #!author = NobyDa 4 | #!input = GOOGLE_CAPTCHA_REGEX 5 | #!homepage = https://github.com/NobyDa/Script/tree/master 6 | #!icon = https://cdn.jsdelivr.net/gh/NobyDa/mini@master/Color/Google.png 7 | #!date = 2024-05-19 12:00:00 8 | 9 | 10 | [Script] 11 | 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人机验证 12 | 13 | [MITM] 14 | hostname = www.google.com* -------------------------------------------------------------------------------- /Loon/Loon_IPA_Installer.plugin: -------------------------------------------------------------------------------- 1 | #!name=IPA应用辅助安装器 2 | #!desc=该模块可在iOS端辅助安装商店版或已签名IPA(需使用快捷指令 + Shu/Jsbox/pythonista), 查看脚本注释以了解具体方法; 安装演示可查看TG频道 @NobyDa 3 | #!author=NobyDa 4 | #!homepage=https://github.com/NobyDa/Script/tree/master 5 | #!icon=https://cdn.jsdelivr.net/gh/NobyDa/mini@master/Color/Apple.png 6 | 7 | 8 | [Script] 9 | 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 10 | 11 | [MITM] 12 | hostname = nobyda.app -------------------------------------------------------------------------------- /Loon/Loon_TF_Account.plugin: -------------------------------------------------------------------------------- 1 | #!name=TestFlight账户管理 2 | #!desc=自动存储/合并多个TestFlight账户列表, 并可分享/导出TestFlight APP. 3 | #!author= NobyDa 4 | #!homepage= https://github.com/NobyDa/Script/tree/master 5 | #!icon= https://cdn.jsdelivr.net/gh/NobyDa/mini@master/Color/testflight.png 6 | 7 | [General] 8 | skip-proxy = iosapps.itunes.apple.com 9 | 10 | [Script] 11 | 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账户管理 12 | 13 | [MITM] 14 | hostname = testflight.apple.com -------------------------------------------------------------------------------- /Loon/Loon_TF_Download.plugin: -------------------------------------------------------------------------------- 1 | #!name= TestFlight区域限制解除 2 | #!desc= 该Loon插件用以解决更新TestFlight App时, 提示"APP不可用"问题. 3 | #!author= NobyDa 4 | #!homepage= https://github.com/NobyDa/Script/tree/master 5 | #!icon= https://cdn.jsdelivr.net/gh/NobyDa/mini@master/Color/testflight.png 6 | 7 | [General] 8 | skip-proxy = iosapps.itunes.apple.com 9 | 10 | [Script] 11 | 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区域限制解除 12 | 13 | [MITM] 14 | hostname = testflight.apple.com 15 | -------------------------------------------------------------------------------- /QuantumultX/Bilibili.list: -------------------------------------------------------------------------------- 1 | # 该规则集用于配合bilibili自动地区脚本使用。 2 | host,api.biliapi.com,Bilibili 3 | host,api.biliapi.net,Bilibili 4 | host,api.bilibili.com,Bilibili 5 | host,app.biliapi.com,Bilibili 6 | host,app.biliapi.net,Bilibili 7 | host,app.bilibili.com,Bilibili 8 | host,grpc.biliapi.net,Bilibili 9 | host,m.bilibili.com,Bilibili 10 | host,upos-hz-mirrorakam.akamaized.net,Bilibili 11 | host,www.bilibili.com,Bilibili 12 | host-keyword,cn-hk-eq-bcache-,Bilibili 13 | ip-cidr,121.11.192.0/24,Bilibili -------------------------------------------------------------------------------- /QuantumultX/DisneyRating.snippet: -------------------------------------------------------------------------------- 1 | # Disney+剧集页显示IMDb / 烂番茄 / 豆瓣评分 2 | # https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/DisneyRating.snippet 3 | 4 | 5 | ^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 6 | 7 | hostname = disney.api.edge.bamgrid.com -------------------------------------------------------------------------------- /QuantumultX/File/91.js: -------------------------------------------------------------------------------- 1 | /* 2 | 91短视频 解锁部分限制 3 | http://download.91porn.love/ 4 | 5 | *************************** 6 | QuantumultX: 7 | 8 | [rewrite_local] 9 | ^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 10 | 11 | *************************** 12 | Surge4: 13 | 14 | [Script] 15 | http-response ^https?:\/\/.+?\.(my10api|(.*91.*))\.(com|tips|app|xyz)(:\d{2,5}|)\/api.php$ requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/91.js 16 | 17 | [General] 18 | force-http-engine-hosts = *91*:8080, *my10api*:8080 19 | 20 | **************************/ 21 | 22 | let body = $response.body; 23 | let obj = JSON.parse(body && /^\{/.test(body) ? body : '{}'); 24 | if (obj.data && obj.data.match(/^[A-Z0-9]{1000,40000}$/)) { 25 | obj.data = "FCA27C420C9BC230C86627D052F62E5E04CC1B51BF986A7C60673DC92F82697E9EB8C7BFB5AA267AC87399CDF8DBD1B1B25FEA57E27F38D0FCFB0CA5CFD8ED7B809FBCF3372C4DBB22083C4BC85A039512735A83834D7450EFD24EA2712FF841050BE99B7A4A31BBFCBE28BD3522227838BABE6E372874533E51A59A81CBFCB9C943C5C9646091E408D3B68BF6122DA929D558290D186EFBA2BE8019B86E35CB174626952650A959CA1A116ADCF1B14773DB033A8055E56F673682219629775138CDF3C653A0179232C8B653FDEB45D704140F8CA0C7716A02E5F7ED7CB41A68A247E9ECC0B744318534B0501865FBDF68AA1E7167663B59EDD8C56114E4A52B52A2020CA89B0F06F9D626BE3446ED5BF64E2FEE7AEA815CC047DBF3AE0F07DF1B4856070430ECF72AA542E22AF59861F2E48099C6E2CF2C1E3DD938196CB40FEE135A61AC76AAE6011C5A126CF9477AA0FDB76BE94279B66063E93E0FC8CFD802D0E2326B462EE26BF073E22B19A60F8BAF74C891DC57B18C8EFA091C9C66B6E94468E9A7165403A0CD2A3D45B23B2A0A43CEEF16FAF704866B6AC10686C8B6C65FB43DFDA9F531576815E7337E640C22870D8E9E4F1AEB6B5386BA48B264FBE302B2D0724C8D8FE9A147397BF8046114C06A99DF953E43ADBBBD3EBC538AEFC02091156B2782C482F17792D4D9FADBA46FB1BA8491146EC2393AB5C26C33CF0B61854D5492D2171A09AA147ACD9FD75798F43154E70624740A08F49507EF296B9B6FC54680C4A8AC265CF7717C8FA646207BF97A0B8241736FAA61EFB1F828545F515940F7873B20E6A1ABE055746F72F03EF49AAACA30A9C2EEF8E5CDE41BE80B1E5B66F485062F70B36A3ACE30116E062B06F95B404291398337E9449C919C096DE09DDF772CBC7373678AE532AB190C02414F2E0777C62679E5B6790D40FB17D832B4A27308D48D53B2A2302F0616BA6ECDD78947205456B0C063EF1EFE54125131F6755971C4DC84087135A89AFBC9BEC74C530BE9A22067A503DC535F0BF9DA16EE2BE41AF891C1A1A55F7B8522A6CA3D7044740316CAA2A25DE5DE1E67DA72E60FE46B5E49029852C859F2ACDDC57233F47AB3C4290E67B851A55B7C834D4A5DFE3E0E16344D0AF027E70ED05E269DBC955AAC496F0A9F794DD8E5059FA73D6A1A249B9E91921A48FE2CC639B29D97073FD936993E9B4634EAE4F805E1F5F65001FA81EE94FF142FE48C6D25CCE206F8731FFE321611ED0C9D95511B3AD30E43F668409A32742C0383A6B3B43663FAEF31F334C83EC641CC451D2FCBA2287E825206A7A2E980E53C2B6D3F39D4581E96719632425518F8CF04FEA775F6F828B75E7EF3C0F36D952DCA728955DADB3D501FFEA09E21D272912DFA4C5DE82B02A459E94100B522A86BA27D841B26754179606DC9C3A25968A915EB070431DA31E76C8C3F8F689957ECE7CB4644EAA545A8EBC151466554120767BC4353B0D252C566A535182AF6B53247A2C024DAA12E9EEDE31F6988804444E40157429F832BA8A959B9A62449ED822D1532BD52870B46BDA1509C1C9619F1EFDF4EA5BC9C1A49B3EF91B0FF3548C78905D248FD5195843A447F4BAFF13965303A0B9B719327698E2D679B43D4D25A8F4CDB316CD21E6C88E21A98187930C82EB616ABE917E1C2B5C045D97CDD41FA65E999F9B7FFEDAAE0F9B735A9BAC94533A2A14B3D4413E4723D947D23CA48E52A67A6506B647810F45B92AB1703C068E67EF1ECA8C3D3BF2149AEC9C0CD623850338445088C3AFA3CC08D30BF12CFA448A10C4E3C4AA5108F9DC1C7D223A0E1A89B01B1C64DB2DFEFBABC32C4F3EAEA6EA39587D44512E9A3F579844974974EEDDC125EA3A56F3821C9FE387CEA62C37160633E14E99A33FC0CB68D19F58EB6A93380476C01A7A0E9631412BEAD87FDCE17DECA4E475A47B0D6DD82D7EDBCC677D487220B172FED1E26AAA00A1771B11A281F6CC3E9582862331765E162033025DBCD8FC9CC3E50A27C72940A5E0C7692E5B474D132FB11D017706D9D653E1731E5EFC1337A964EB9F0C1865FE475421816ADC7ADACE6FAFA6BA0D8B7FECF766B640D5944254BC9DD638BAB91313DF77C91A8FB74012873AFCB3EACF18CA8D1C67EE16F6F83CA22D59F5D577F5B0844D4FFBC1A6D9C37F5848CB672E32AA48445A1B6D6837CCF98E4D4FE49B5F62186940F868473BA71F2C68C62687D9E5BB4B01E5E079A040275D86E66559025E6253D1759559B1FA60F48B7AC130F0070D21C0E38CDCF63DD755CD790FD3990109A3B856422E8118C5075D6EDFB58EFF8AA4401871036ADB9F766F9FC895F317A9D9DF38BD6E0D3E671BBE79F2C4BC8811F5E94A878D0E922FBAC4C86"; 26 | $done({body: JSON.stringify(obj)}); 27 | } else { 28 | $done({}) 29 | } -------------------------------------------------------------------------------- /QuantumultX/File/Wechat.js: -------------------------------------------------------------------------------- 1 | /* 2 | 微信 去除公众号文章底部广告 3 | 4 | *************************** 5 | QuantumultX: 6 | 7 | [rewrite_local] 8 | ^https?:\/\/mp\.weixin\.qq\.com\/mp\/getappmsgad url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/Wechat.js 9 | 10 | [mitm] 11 | hostname = mp.weixin.qq.com 12 | 13 | *************************** 14 | Surge4 or Loon: 15 | 16 | [Script] 17 | http-response ^https?:\/\/mp\.weixin\.qq\.com\/mp\/getappmsgad requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/Wechat.js 18 | 19 | [MITM] 20 | hostname = mp.weixin.qq.com 21 | 22 | **************************/ 23 | 24 | var obj = JSON.parse($response.body); 25 | obj.advertisement_num = 0; 26 | obj.advertisement_info = []; 27 | delete obj.appid; 28 | $done({body: JSON.stringify(obj)}); 29 | -------------------------------------------------------------------------------- /QuantumultX/File/Zymh.js: -------------------------------------------------------------------------------- 1 | /* 2 | 解锁知音漫客付费章节 (需登录) 3 | 4 | *************************** 5 | QuantumultX: 6 | 7 | [rewrite_local] 8 | ^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 9 | 10 | [mitm] 11 | hostname = apigate.kaimanhua.com 12 | 13 | *************************** 14 | Surge4 or Loon: 15 | 16 | [Script] 17 | 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 18 | 19 | [MITM] 20 | hostname = apigate.kaimanhua.com 21 | **************************/ 22 | 23 | var obj = JSON.parse($response.body); 24 | obj.status = 0; 25 | obj.data.isvip = 1; 26 | obj.data.coins = 6666; 27 | obj.data.Cgold = 6666; 28 | $done({body: JSON.stringify(obj)}); 29 | -------------------------------------------------------------------------------- /QuantumultX/File/vsco.js: -------------------------------------------------------------------------------- 1 | /******************************** 2 | Membership unlock for VSCO & 1Blocker & HTTPBot 3 | Please note that you may need to reinstall app for script to work. 4 | 5 | QuantumultX rewrite link: 6 | https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/vsco.js 7 | 8 | Please note that the above rewrite link requires open KOP-XIAO's resource parser 9 | 10 | ********************************* 11 | Surge4, Loon and Shadowrocket configuration: 12 | 13 | [Script] 14 | http-request ^https?:\/\/api\.revenuecat\.com\/v\d\/subscribers\/ script-path=https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/vsco.js 15 | 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 16 | 17 | [MITM] 18 | hostname = api.revenuecat.com 19 | ********************************/ 20 | 21 | const resp = {}; 22 | const obj = JSON.parse(typeof $response != "undefined" && $response.body || null); 23 | const ua = $request.headers['User-Agent'] || $request.headers['user-agent']; 24 | const list = { 25 | 'HTTPBot': { name: 'rc_lifetime', id: 'com.behindtechlines.HTTPBot.prounlock' }, 26 | 'VSCO': { name: 'membership', id: 'com.circles.fin.premium.yearly' }, 27 | '1Blocker': { name: 'premium', id: 'blocker.ios.subscription.yearly' } 28 | }; 29 | const data = { 30 | "expires_date": "2030-02-18T07:52:54Z", 31 | "original_purchase_date": "2020-02-11T07:52:55Z", 32 | "purchase_date": "2020-02-11T07:52:54Z" 33 | }; 34 | 35 | if (typeof $response == "undefined") { 36 | delete $request.headers["x-revenuecat-etag"]; // prevent 304 issues 37 | delete $request.headers["X-RevenueCat-ETag"]; 38 | resp.headers = $request.headers; 39 | } else if (obj && obj.subscriber) { 40 | obj.subscriber.subscriptions = obj.subscriber.subscriptions || {}; 41 | obj.subscriber.entitlement = obj.subscriber.entitlement || {}; 42 | for (const i in list) { 43 | if (new RegExp(`^${i}`, `i`).test(ua)) { 44 | obj.subscriber.subscriptions[list[i].id] = data; 45 | obj.subscriber.entitlements[list[i].name] = JSON.parse(JSON.stringify(data)); 46 | obj.subscriber.entitlements[list[i].name].product_identifier = list[i].id; 47 | break; 48 | } 49 | } 50 | resp.body = JSON.stringify(obj); 51 | } 52 | 53 | $done(resp); 54 | -------------------------------------------------------------------------------- /QuantumultX/File/wnyd.js: -------------------------------------------------------------------------------- 1 | /* 2 | 网易蜗牛读书 解锁特权 3 | 原作者: yxiaocai & JO2EY 4 | 5 | *************************** 6 | QuantumultX: 7 | 8 | [rewrite_local] 9 | ^https?:\/\/p\.du\.163\.com\/gain\/readtime\/info\.json url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/wnyd.js 10 | 11 | [mitm] 12 | hostname = p.du.163.com 13 | 14 | *************************** 15 | Surge4 or Loon: 16 | 17 | [Script] 18 | http-response ^https?:\/\/p\.du\.163\.com\/gain\/readtime\/info\.json requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/wnyd.js 19 | 20 | [MITM] 21 | hostname = p.du.163.com 22 | 23 | **************************/ 24 | var body = $response.body; 25 | var obj = JSON.parse(body); 26 | 27 | obj.tradeEndTime = 1879685290000; 28 | body = JSON.stringify(obj); 29 | $done({body}); 30 | -------------------------------------------------------------------------------- /QuantumultX/File/xjsp.js: -------------------------------------------------------------------------------- 1 | /* 2 | 香蕉视频 解锁部分观看限制 3 | 官网: https://www.aa2.app 4 | 5 | *************************** 6 | QuantumultX: 7 | 8 | [rewrite_local] 9 | ^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 10 | 11 | [mitm] 12 | hostname = ios.fuliapps.com, apple.fuliapps.com, ios.xiangjiaoapps.com, apple.xiangjiaoapps.com, *.xiangxiangapps.com, *.pipiapps.com 13 | 14 | *************************** 15 | Surge4 or Loon: 16 | 17 | [Script] 18 | http-response https?:\/\/.+?\.(pipi|fuli|xiang(jiao|xiang))apps\.com\/(ucp\/index|getGlobalData|(\/|)vod\/reqplay\/) requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/xjsp.js 19 | 20 | [MITM] 21 | hostname = ios.fuliapps.com, apple.fuliapps.com, ios.xiangjiaoapps.com, apple.xiangjiaoapps.com, *.xiangxiangapps.com, *.pipiapps.com 22 | 23 | **************************/ 24 | 25 | var body = $response.body; 26 | var url = $request.url; 27 | 28 | if (body) { 29 | var obj = JSON.parse($response.body); 30 | if (/\/ucp\/index/.test(url) && obj.data) { 31 | obj.data.uinfo.minivod_play_daily_remainders = "666"; 32 | obj.data.uinfo.minivod_down_daily_remainders = "666"; 33 | obj.data.uinfo.down_daily_remainders = "666"; 34 | obj.data.uinfo.play_daily_remainders = "666"; 35 | obj.data.uinfo["next_upgrade_need"] = "0"; 36 | obj.data.user.isvip = "1"; 37 | obj.data.user.gicon = "V5"; 38 | obj.data.user.gid = "5"; 39 | } 40 | if (/\/getGlobalData/.test(url) && obj.data) { 41 | obj.data.app_launch_times_adshow = "0"; 42 | obj.data.adgroups = ""; 43 | obj.data.iOS_adgroups = ""; 44 | } 45 | if (/\/reqplay\//.test(url) && obj.data) { 46 | obj.retcode = "0"; 47 | if (obj.data.hasOwnProperty("httpurl_preview")) { 48 | var playurl = obj.data["httpurl_preview"]; 49 | obj.data["httpurl"] = playurl; 50 | }; 51 | } 52 | $done({ body: JSON.stringify(obj) }); 53 | } else { 54 | $done({}) 55 | } -------------------------------------------------------------------------------- /QuantumultX/IPA-Installer.snippet: -------------------------------------------------------------------------------- 1 | # 该文件为 "IPA应用辅助安装脚本" QuantumultX远端重写资源. 2 | # 该资源可在iOS端辅助安装商店版或已签名IPA(需使用快捷指令 + Shu/Jsbox/pythonista), 查看脚本注释以了解具体方法; 安装演示可查看TG频道 @NobyDa 3 | 4 | ^https:\/\/nobyda.app/(install|download) url script-analyze-echo-response https://raw.githubusercontent.com/NobyDa/Script/master/IPA-Installer/IPA-Installer.js 5 | 6 | hostname = nobyda.app -------------------------------------------------------------------------------- /QuantumultX/Js.conf: -------------------------------------------------------------------------------- 1 | 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 2 | 3 | # 去微信公众号广告 (By Choler) 4 | ^https?:\/\/mp\.weixin\.qq\.com\/mp\/getappmsgad url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/Wechat.js 5 | 6 | # 网易蜗牛读书VIP (By yxiaocai and JO2EY) 7 | ^https?://p\.du\.163\.com/readtime/info.json url reject 8 | ^https?:\/\/p\.du\.163\.com\/gain\/readtime\/info\.json url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/wnyd.js 9 | 10 | # 知音漫客VIP 11 | ^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 12 | 13 | # VSCO & 1Blocker 14 | ^https?:\/\/api\.revenuecat\.com\/v\d\/subscribers\/ url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/vsco.js 15 | ^https?:\/\/api\.revenuecat\.com\/v\d\/subscribers\/ url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/vsco.js 16 | 17 | # 香蕉视频VIP 18 | ^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 19 | 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 22 | 23 | # JibJab解锁pro 24 | ^https:\/\/origin-prod-phoenix\.jibjab\.com\/v1\/user url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/jibjab.js 25 | 26 | # 小影 解锁Vip 27 | ^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 28 | 29 | # 扫描全能王 pro 30 | ^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 31 | 32 | # 百度网盘 解除在线视频倍率/清晰度 33 | ^https:\/\/pan\.baidu\.com\/rest\/\d\.\d\/membership\/user url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/BaiduCloud.js 34 | 35 | # MIX 解锁高级特权 (需恢复购买) 36 | ^https?:\/\/bmall\.camera360\.com\/api\/mix\/recovery url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/MIX.js 37 | 38 | ################################# 39 | ###########其他仓库引用########### 40 | ################################# 41 | 42 | # 去微博应用内广告 (yichahucha) 43 | ^https?://(sdk|wb)app\.uve\.weibo\.com(/interface/sdk/sdkad.php|/wbapplua/wbpullad.lua) url script-response-body https://raw.githubusercontent.com/yichahucha/surge/master/wb_launch.js 44 | ^https?://m?api\.weibo\.c(n|om)/2/(statuses/(unread|extend|positives/get|(friends|video)(/|_)(mix)?timeline)|stories/(video_stream|home_list)|(groups|fangle)/timeline|profile/statuses|comments/build_comments|photo/recommend_list|service/picfeed|searchall|cardlist|page|!/(photos/pic_recommend_status|live/media_homelist)|video/tiny_stream_video_list|photo/info|remind/unread_count) url script-response-body https://raw.githubusercontent.com/yichahucha/surge/master/wb_ad.js 45 | 46 | # 知乎去广告 (onewayticket255) 47 | https://api.zhihu.com/(ad|drama|fringe|commercial|market/popover|search/(top|preset|tab)|.*featured-comment-ad) url reject-200 48 | 49 | # 京东比价 50 | ^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 51 | 52 | # Netflix评分 (yichahucha) 53 | ^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 54 | ^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 55 | 56 | ################################# 57 | ################################# 58 | ################################# 59 | 60 | -------------------------------------------------------------------------------- /QuantumultX/Snippet/BiliComicCookie.snippet: -------------------------------------------------------------------------------- 1 | # 该 QuantumultX 远程重写配置片段用于获取"哔哩哔哩漫画签到"账号Cookie 2 | # 配置脚本后打开哔哩哔哩漫画(AppStore中国区),点击"我的"可完成获取 3 | # https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/BiliComicCookie.snippet 4 | 5 | 6 | ^https:\/\/app\.bilibili\.com\/x\/v2\/account\/myinfo url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/Bilibili-DailyBonus/Manga.js 7 | 8 | hostname = app.bilibili.com -------------------------------------------------------------------------------- /QuantumultX/Snippet/CtripAuth.snippet: -------------------------------------------------------------------------------- 1 | # 该 QuantumultX 远程重写配置片段用于获取"携程签到"账号授权 2 | # 配置脚本后登陆"携程旅行"微信小程序或"携程网页版"(https://m.ctrip.com/)即可完成获取 3 | # https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/CtripAuth.snippet 4 | 5 | 6 | ^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 7 | 8 | hostname = m.ctrip.com -------------------------------------------------------------------------------- /QuantumultX/Snippet/GoogleCAPTCHA.snippet: -------------------------------------------------------------------------------- 1 | # QuantumultX 远程重写配置片段 2 | 3 | # Google搜索人机验证解决方案 4 | # Google搜索内容时并发使用多个代理策略、策略组尝试搜索内容,并返回最优结果。具体细节可查看脚本注释。 5 | 6 | # 脚本:https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Google_CAPTCHA.js 7 | # 片段:https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/GoogleCAPTCHA.snippet 8 | 9 | 10 | ^https:\/\/www\.google\.com(?:\.[a-z]+|)\/(?:search\?(?:|.+?&)q=|$) url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Google_CAPTCHA.js 11 | 12 | hostname = www.google.com* -------------------------------------------------------------------------------- /QuantumultX/Snippet/KuaiKanCookie.snippet: -------------------------------------------------------------------------------- 1 | # 该 QuantumultX 远程重写配置片段用于获取"快看漫画签到"账号Cookie 2 | # 配置脚本后打开快看漫画(AppStore中国区),点击"我的"可完成获取 3 | # https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/KuaiKanCookie.snippet 4 | 5 | 6 | ^https:\/\/api\.kkmh\.com\/v\d\/passport\/user url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/KuaiKan-DailyBonus/KKMH.js 7 | 8 | hostname = api.kkmh.com -------------------------------------------------------------------------------- /QuantumultX/Snippet/TieBaCookie.snippet: -------------------------------------------------------------------------------- 1 | # 该 QuantumultX 远程重写配置片段用于获取"百度贴吧签到"账号Cookie 2 | # 配置脚本后打开百度贴吧App(AppStore中国区, 非内部版),点击"我的"可完成获取 3 | # https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/TieBaCookie.snippet 4 | 5 | 6 | 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 7 | 8 | hostname = c.tieba.baidu.com -------------------------------------------------------------------------------- /QuantumultX/Snippet/iQiYiCookie.snippet: -------------------------------------------------------------------------------- 1 | # 该 QuantumultX 远程重写配置片段用于获取"爱奇艺签到"账号Cookie 2 | # 配置脚本后 Safari 浏览器打开 https://m.iqiyi.com/user.html 使用密码登录可完成获取 3 | # https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/iQiYiCookie.snippet 4 | 5 | 6 | ^https:\/\/passport\.iqiyi\.com\/apis\/user\/ url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js 7 | 8 | hostname = passport.iqiyi.com -------------------------------------------------------------------------------- /QuantumultX/TestFlightDownload.conf: -------------------------------------------------------------------------------- 1 | # 该订阅仅适用于QuantumultX, 用于更新TestFlight App时, 提示"APP不可用"问题. 解除区域限制. 2 | 3 | hostname = testflight.apple.com 4 | 5 | ^https?:\/\/testflight\.apple\.com\/v\d\/accounts\/.+?\/install$ url script-request-body https://gist.githubusercontent.com/NobyDa/9be418b93afc5e9c8a8f4d28ae403cf2/raw/TF_Download.js -------------------------------------------------------------------------------- /Rule-Storage/Include-Domain.txt: -------------------------------------------------------------------------------- 1 | DOMAIN-KEYWORD,.a 2 | DOMAIN-KEYWORD,.b 3 | DOMAIN-KEYWORD,.c 4 | DOMAIN-KEYWORD,.d 5 | DOMAIN-KEYWORD,.e 6 | DOMAIN-KEYWORD,.f 7 | DOMAIN-KEYWORD,.g 8 | DOMAIN-KEYWORD,.h 9 | DOMAIN-KEYWORD,.i 10 | DOMAIN-KEYWORD,.j 11 | DOMAIN-KEYWORD,.k 12 | DOMAIN-KEYWORD,.l 13 | DOMAIN-KEYWORD,.m 14 | DOMAIN-KEYWORD,.n 15 | DOMAIN-KEYWORD,.o 16 | DOMAIN-KEYWORD,.p 17 | DOMAIN-KEYWORD,.q 18 | DOMAIN-KEYWORD,.r 19 | DOMAIN-KEYWORD,.s 20 | DOMAIN-KEYWORD,.t 21 | DOMAIN-KEYWORD,.u 22 | DOMAIN-KEYWORD,.v 23 | DOMAIN-KEYWORD,.w 24 | DOMAIN-KEYWORD,.x 25 | DOMAIN-KEYWORD,.y 26 | DOMAIN-KEYWORD,.z -------------------------------------------------------------------------------- /Rule-Storage/Rule-Storage.js: -------------------------------------------------------------------------------- 1 | /* 2 | Surge规则自动生成脚本 3 | 更新时间:2024/08/11 4 | 5 | 需按照博客内教程配合使用: 6 | https://nobyda.github.io/2024/02/24/Surge_Rule_Storage 7 | 8 | */ 9 | 10 | const args = argsList(typeof $argument == "string" && $argument || 'region=debug'); 11 | /* 12 | When matching whitelist rules, skip generating suffix domain. Three ways to write: 13 | Domain: example.com 14 | Domain suffix: .example.com 15 | Domain keyword: .example. 16 | */ 17 | args.whitelist = args.whitelist || `[".mwcname.com", ".akadns.", ".akamai.", ".cloud.", ".cdn.", ".yun."]`; 18 | args.key = args.key || 'Rule-Storage'; 19 | 20 | (async () => { 21 | const host = $request.hostname.toLowerCase(); 22 | const inHost = $request.listenPort == 6152 && !$request.sourcePort && !$request.processPath && /^[a-z0-9]{10}\.[a-z]+$/.test(host); //Prevent benchmark 23 | if (['127.0.0.1', '0.0.0.0'].filter((v) => [...($request.dnsResult || {}).v4Addresses || []].includes(v)).length) { 24 | // DNS poisoning 25 | args.matched = false; 26 | args.region = 'global'; 27 | } 28 | if (!/\d$|:/.test(host) && host.includes('.') && !inHost) { 29 | const data = JSON.parse($persistentStore.read(args.key) || '{}'); 30 | const saved_rules = $persistentStore.read(`${args.key}-${args.region}`); 31 | if (!evalRules(host, saved_rules)) { 32 | data[args.region] = saveDecision(host, data[args.region]); 33 | if (data[args.region][host].quantity >= (args.quantity || 10)) { 34 | const eTLDs = await eTLD(data.eTLD || JSON.parse($persistentStore.read(`${args.key}-eTLD`) || '{}')); 35 | if (data.eTLD) { // legacy 36 | $persistentStore.write(JSON.stringify(data.eTLD), `${args.key}-eTLD`); 37 | delete data.eTLD; 38 | } 39 | const suffix = shortenDomain(host, eTLDs.public_suffix); 40 | const domain = evalRules(host, JSON.parse(args.whitelist)) ? host : suffix; 41 | const text = [...formatRules(saved_rules), ...formatRules(domain)].join('\n'); 42 | delete data[args.region][host]; 43 | $persistentStore.write(text, `${args.key}-${args.region}`) 44 | } 45 | } 46 | return $persistentStore.write(JSON.stringify(data), args.key) 47 | } 48 | })().catch((e) => $notification.post(args.key, ``, e.message || e)) 49 | .finally(() => $done({ matched: Boolean(args.matched) })); 50 | 51 | function saveDecision(host_name, content = {}) { 52 | const count = []; 53 | for (const i in content) { 54 | if (Date.now() - content[i].update_time > 86400000 * (args.cacheDays || 30)) { 55 | delete content[i]; 56 | continue 57 | } 58 | count.push(content[i].update_time); 59 | } 60 | if (count.length > (args.cacheNumber || 1000)) { // limit amount to prevent NE memory issues. 61 | const spill = count.sort((x, y) => x - y).slice(0, count.length - (args.cacheNumber || 1000)); 62 | for (const is of spill) { 63 | for (const ic in content) { 64 | if (content[ic].update_time === is) { 65 | delete content[ic]; 66 | break 67 | } 68 | } 69 | } 70 | } 71 | if (content[host_name]) { 72 | if (Date.now() - content[host_name].update_time > ((args.interval || 30) * 1000)) { 73 | content[host_name].update_time = Date.now(); 74 | content[host_name].quantity++; 75 | } 76 | } else { 77 | content[host_name] = { update_time: Date.now(), quantity: 1 } 78 | } 79 | return content 80 | } 81 | 82 | function evalRules(host_name, rule_list) { 83 | const host_suffix = host_name.split('.').reverse(); 84 | rule_list = typeof rule_list == 'object' ? rule_list : formatRules(rule_list, 1); 85 | for (const i in rule_list) { 86 | if (rule_list[i].startsWith('.') && !rule_list[i].endsWith('.')) { 87 | const rule_host_suffix = rule_list[i].split('.').reverse().filter((v) => v); 88 | if (rule_host_suffix.filter((v, i) => host_suffix[i] === v).length === rule_host_suffix.length) { 89 | return true 90 | } 91 | } else if (rule_list[i].startsWith('.') && rule_list[i].endsWith('.')) { 92 | if (host_name.includes(rule_list[i].slice(1, -1))) { 93 | return true 94 | } 95 | } else if (rule_list[i] === host_name) { 96 | return true 97 | } 98 | } 99 | return false 100 | } 101 | 102 | function formatRules(list, type) { 103 | return (list || '').replace(/\r|\ |(\/\/|#|;).*/g, '').split('\n').map((v) => { 104 | if (v.startsWith('DOMAIN,')) { return type ? v.split(",")[1] : v } 105 | if (v.startsWith('DOMAIN-SUFFIX,')) { return type ? `.${v.split(",")[1]}` : v } 106 | if (v.startsWith('.')) { return type ? v : `DOMAIN-SUFFIX,${v.slice(1)}` } 107 | if (v.includes('.')) { return type ? v : `DOMAIN,${v}` } 108 | }).filter((v) => v); 109 | } 110 | 111 | async function eTLD(content = {}) { 112 | if (!content.update_time || (Date.now() - content.update_time > 86400000 * 30)) { 113 | await new Promise(resolve => { 114 | $httpClient.get({ 115 | url: 'https://publicsuffix.org/list/public_suffix_list.dat' 116 | }, (error, resp, body) => { 117 | if (resp.status == 200 && !error && body) { 118 | content.update_time = Date.now(); 119 | content.public_suffix = body.replace(/\r|.*(\/\/|#|;).*|\n(\!|\*\.)/g, '\n').split('\n').filter((t) => t); 120 | $persistentStore.write(JSON.stringify(content), `${args.key}-eTLD`); 121 | resolve() 122 | } else if (content.update_time) { 123 | console.log(`Update eTLD list failed: ${error}`); 124 | resolve() 125 | } else { 126 | throw new Error(`Download eTLD list failed: ${error}`) 127 | } 128 | }) 129 | }) 130 | } 131 | return content 132 | } 133 | 134 | /* 135 | Shorten multi level domain: non-eTLD, full eTLD, second level domain will return original 136 | Basic logic: www.abc.com -> .abc.com 137 | */ 138 | function shortenDomain(host_name, eTLD_list) { 139 | return host_name.split('.').reverse().reduce((t, v, i, c) => { 140 | if (t === host_name || c.length == 2) { return host_name } 141 | if (t.startsWith('.')) { return t } 142 | const host_suffix = v + (t && `.${t}` || ''); 143 | for (const ix in eTLD_list) { 144 | if (eTLD_list[ix] === host_suffix) { 145 | return host_suffix 146 | } 147 | } 148 | return !i && host_name || `.${host_suffix}` 149 | }, '') 150 | } 151 | 152 | function argsList(data) { 153 | return Array.from( 154 | data.split("&") 155 | .map((i) => i.split("=")) 156 | .map(([k, v]) => [k, decodeURIComponent(v)]) 157 | ) 158 | .reduce((a, [k, v]) => Object.assign(a, { [k]: v }), {}) 159 | } -------------------------------------------------------------------------------- /Shortcuts/PolicySwitch.js: -------------------------------------------------------------------------------- 1 | /* 2 | 捷径策略切换脚本, 该脚本需与捷径配合使用. 3 | 4 | 脚本兼容: Surge4.7, QuanX1.0.22(545+), Loon2.1.10(290+) 5 | 捷径地址: https://www.icloud.com/shortcuts/0f5b9a825cad47488a78ff2876b822dd 6 | 7 | 脚本配置: 8 | -----------Surge------------ 9 | [Script] 10 | 捷径策略切换 = type=http-request,pattern=^http:\/\/nobyda\.policy,requires-body=1,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Shortcuts/PolicySwitch.js 11 | 12 | --------QuantumuitX--------- 13 | [rewrite_local] 14 | ^http:\/\/nobyda\.policy url script-analyze-echo-response https://raw.githubusercontent.com/NobyDa/Script/master/Shortcuts/PolicySwitch.js 15 | 16 | ------------Loon------------ 17 | [Script] 18 | http-request ^http:\/\/nobyda\.policy script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Shortcuts/PolicySwitch.js, requires-body=true, tag=捷径策略切换 19 | 20 | ---------------------------- 21 | */ 22 | 23 | const $ = new nobyda(); 24 | const url = $request.url; 25 | const body = JSON.parse($request.body || '{}'); 26 | 27 | (async function SwitchPoliy() { 28 | let res = {}; 29 | if (/\/getGroup$/.test(url)) 30 | res.group = await $.getGroup(); 31 | if (/\/getPolicy$/.test(url)) 32 | res.policy = await $.getPolicy(body.group); 33 | if (/\/setPolicy$/.test(url)) 34 | res.success = await $.setPolicy(body.group, body.policy); 35 | $.done(res); 36 | })() 37 | 38 | function nobyda() { 39 | const isLoon = typeof($loon) !== "undefined"; 40 | const isQuanX = typeof($configuration) !== 'undefined'; 41 | const isSurge = typeof($httpAPI) !== 'undefined'; 42 | const m = `不支持您的APP版本, 请等待APP更新 ⚠️`; 43 | this.getGroup = () => { 44 | if (isSurge) { 45 | return new Promise((resolve) => { 46 | $httpAPI("GET", "v1/policies", {}, (b) => resolve(b['policy-groups'])) 47 | }) 48 | } 49 | if (isLoon) { 50 | const getName = JSON.parse($config.getConfig()); 51 | return getName['all_policy_groups']; 52 | } 53 | if (isQuanX) { 54 | return new Promise((resolve) => { 55 | $configuration.sendMessage({ 56 | action: "get_customized_policy" 57 | }).then(b => { 58 | if (b.ret) { 59 | resolve(Object.keys(b.ret).filter(s => b.ret[s].type == "static")); 60 | } else resolve(); 61 | }, () => resolve()); 62 | }) 63 | } 64 | return m; 65 | } 66 | this.getPolicy = (groupName) => { 67 | if (isSurge) { 68 | return new Promise((resolve) => { 69 | $httpAPI("GET", "v1/policy_groups", {}, (b) => { 70 | resolve(b[groupName].map(g => g.name)) 71 | }) 72 | }) 73 | } 74 | if (isLoon) { 75 | return new Promise((resolve) => { 76 | $config.getSubPolicys(groupName, (b) => { 77 | const get = JSON.parse(b || '[]').map(n => n.name); 78 | resolve(get) 79 | }) 80 | }) 81 | } 82 | if (isQuanX) { 83 | return new Promise((resolve) => { 84 | $configuration.sendMessage({ 85 | action: "get_customized_policy", 86 | content: groupName 87 | }).then(b => { 88 | if (b.ret && b.ret[groupName]) { 89 | resolve(b.ret[groupName].candidates); 90 | } else resolve(); 91 | }, () => resolve()); 92 | }) 93 | } 94 | return m; 95 | } 96 | this.setPolicy = (group, policy) => { 97 | if (isSurge) { 98 | return new Promise((resolve) => { 99 | $httpAPI("POST", "v1/policy_groups/select", { 100 | group_name: group, 101 | policy: policy 102 | }, (b) => resolve(!b.error)) 103 | }) 104 | } 105 | if (isLoon) { 106 | const set = $config.setSelectPolicy(group, policy); 107 | return set; 108 | } 109 | if (isQuanX) { 110 | return new Promise((resolve) => { 111 | $configuration.sendMessage({ 112 | action: "set_policy_state", 113 | content: { 114 | [group]: policy 115 | } 116 | }).then((b) => resolve(!b.error), () => resolve()); 117 | }) 118 | } 119 | return m; 120 | } 121 | this.done = (body) => { 122 | const e = { 123 | response: { 124 | body: JSON.stringify(body) 125 | } 126 | }; 127 | $done(typeof($task) != "undefined" ? e.response : e); 128 | } 129 | } -------------------------------------------------------------------------------- /Stash/IPA-Installer.stoverride: -------------------------------------------------------------------------------- 1 | name: IPA应用辅助安装器 2 | desc: 该模块可在iOS端辅助安装商店版或已签名IPA(需使用快捷指令 + Shu/Jsbox/pythonista), 查看脚本注释以了解具体方法; 安装演示可查看TG频道 @NobyDa 3 | 4 | http: 5 | mitm: 6 | - nobyda.app 7 | script: 8 | - match: ^https:\/\/nobyda.app/(install|download) 9 | name: IPA-Installer 10 | type: request 11 | require-body: true 12 | timeout: 10 13 | script-providers: 14 | IPA-Installer: 15 | url: https://raw.githubusercontent.com/NobyDa/Script/master/IPA-Installer/IPA-Installer.js 16 | interval: 86400 -------------------------------------------------------------------------------- /Sub-store-parser/DataQuery.js: -------------------------------------------------------------------------------- 1 | /****************************** 2 | 3 | Sub-Store外置流量查询脚本 4 | 5 | 该脚本基于Sub-Store, 可解决APP使用Sub-Store链接后, 没有流量通知的问题. 使用前需确认您的机场订阅是否支持流量信息. (注:节点名流量信息暂不支持) 6 | Sub-Store订阅管理器: https://github.com/Peng-YM/Sub-Store 7 | 8 | 最后更新: 2022.6.12 9 | 测试兼容: QuantumultX, Surge, Loon. 10 | 使用方法: 打开Sub-Store => 订阅 => 编辑 => 节点操作+ => 脚本操作 => 填入脚本链接或粘贴脚本 => 保存 11 | 12 | 您的APP更新Sub-Store订阅链接时, 将自动发送流量通知. 13 | 14 | 脚本链接: https://raw.githubusercontent.com/NobyDa/Script/master/Sub-store-parser/DataQuery.js 15 | 16 | ******************************/ 17 | 18 | async function operator(proxies, client) { 19 | if (['JSON', 'URI'].includes(client)) return proxies; 20 | const $ = $substore; //OpenAPI in Sub-Store 21 | const single = $.read('subs'); 22 | const collection = $.read('collections'); 23 | const subtag = decodeURIComponent($request.url.split(/download\/(collection\/|)(.*)/)[2]); 24 | const group = []; 25 | if ($request.url.includes('/collection/')) { //collection subscription. 26 | const deployed = collection[subtag].process.filter((c) => c.type == 'Script Operator' && c.args.content.includes('/DataQuery.js')).length; 27 | for (let i = 0; i < collection[subtag].subscriptions.length; i++) { 28 | if (deployed) group.push({ 29 | name: collection[subtag].subscriptions[i], url: single[collection[subtag].subscriptions[i]].url 30 | }); 31 | } 32 | } else { //single subscription. 33 | group.push({ name: single[subtag].name, url: single[subtag].url }) 34 | } 35 | await Promise.all( 36 | group.map((c) => $.http.get(c.url) 37 | .then((r) => { 38 | const t = parseInfo(r); 39 | $.notify( 40 | `🔹 订阅昵称:「 ${c.name} 」`, 41 | t.expire ? `🔹 过期时间:「 ${t.expire} 」` : ``, 42 | `🔸 已用流量:「 ${t.used} GB 」\n🔸 剩余流量:「 ${t.free} GB 」` 43 | ); 44 | }) 45 | .catch((e) => $.notify(`🔹 订阅昵称:「 ${c.name} 」`, ``, `🔺 查询失败:「 ${e.message || e} 」`)) 46 | ) 47 | ) 48 | return proxies; 49 | } 50 | 51 | function parseInfo(resp) { //reference to https://github.com/KOP-XIAO/QuantumultX/blob/master/Scripts/resource-parser.js 52 | var sinfo = JSON.stringify(resp.headers || '').replace(/ /g, "").toLowerCase(); 53 | if (sinfo.indexOf("total=") == -1 && sinfo.indexOf("download=") == -1) 54 | throw new Error('该订阅不包含流量信息'); 55 | // var total = (parseFloat(sinfo.split("total=")[1].split(",")[0]) / (1024 ** 3)).toFixed(0); 56 | 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); 57 | 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); 58 | if (sinfo.indexOf("expire=") != -1) { 59 | var epr = new Date(parseFloat(sinfo.split("expire=")[1].split(",")[0]) * 1000); 60 | var year = epr.getFullYear(); 61 | var mth = epr.getMonth() + 1 < 10 ? '0' + (epr.getMonth() + 1) : (epr.getMonth() + 1); 62 | var day = epr.getDate() < 10 ? "0" + (epr.getDate()) : epr.getDate(); 63 | return { expire: `${year}-${mth}-${day}`, used: usd, free: left } 64 | } 65 | return { used: usd, free: left } 66 | } -------------------------------------------------------------------------------- /Surge/Apple.list: -------------------------------------------------------------------------------- 1 | # This ruleset includes 99% of apple inc network connections(global). If there are any missing, please PR. 2 | 3 | DOMAIN-SUFFIX,apple.co 4 | DOMAIN-SUFFIX,apple.cn 5 | DOMAIN-SUFFIX,apple.com 6 | DOMAIN-SUFFIX,apple.com.cn 7 | DOMAIN-SUFFIX,apple.com.cdn20.com 8 | DOMAIN-SUFFIX,apple.com.mwcloudcdn.com 9 | DOMAIN-SUFFIX,apple.com.mwcname.com 10 | DOMAIN-SUFFIX,apple.news 11 | DOMAIN-SUFFIX,appsto.re 12 | DOMAIN-SUFFIX,appstore.com 13 | DOMAIN-SUFFIX,cdn-apple.com 14 | DOMAIN-SUFFIX,apple-cloudkit.com 15 | DOMAIN-SUFFIX,apple-dns.net 16 | DOMAIN-SUFFIX,apple-livephotoskit.com 17 | DOMAIN-SUFFIX,apple-mapkit.com 18 | DOMAIN-SUFFIX,itunes.com.edgekey.net 19 | DOMAIN-SUFFIX,apple.com.edgekey.net 20 | DOMAIN-SUFFIX,apple-support.akadns.net 21 | DOMAIN-SUFFIX,apple.com.edgekey.net.globalredir.akadns.net 22 | DOMAIN-SUFFIX,aaplimg.com 23 | DOMAIN-SUFFIX,crashlytics.com 24 | DOMAIN-SUFFIX,digicert.com 25 | DOMAIN-SUFFIX,itunes.com 26 | DOMAIN-SUFFIX,me.com 27 | DOMAIN-SUFFIX,mzstatic.com 28 | DOMAIN-SUFFIX,apple 29 | 30 | DOMAIN,apple.comscoreresearch.com 31 | 32 | DOMAIN-KEYWORD,icloud 33 | DOMAIN-KEYWORD,testflight 34 | DOMAIN-KEYWORD,apple.com.akadns.net 35 | 36 | IP-CIDR,139.178.128.0/18,no-resolve 37 | IP-CIDR,144.178.0.0/19,no-resolve 38 | IP-CIDR,144.178.36.0/22,no-resolve 39 | IP-CIDR,144.178.48.0/20,no-resolve 40 | IP-CIDR,192.35.50.0/24,no-resolve 41 | IP-CIDR,198.183.17.0/24,no-resolve 42 | IP-CIDR,205.180.175.0/24,no-resolve 43 | IP-CIDR,63.92.224.0/19,no-resolve 44 | IP-CIDR,65.199.22.0/23,no-resolve 45 | IP-CIDR,17.0.0.0/8,no-resolve 46 | IP-CIDR6,2403:300::/32,no-resolve 47 | IP-CIDR6,2620:149::/32,no-resolve 48 | IP-CIDR6,2a01:b740::/32,no-resolve 49 | IP-CIDR6,2a01:b747::/32,no-resolve 50 | 51 | 52 | USER-AGENT,%E5%9C%B0%E5%9B%BE* 53 | USER-AGENT,%E6%9F%A5%E6%89%BE* 54 | USER-AGENT,%E8%AE%BE%E7%BD%AE* 55 | USER-AGENT,*WeatherFoundation* 56 | USER-AGENT,*com.apple.mobileme.fmip1* 57 | USER-AGENT,AppStore* 58 | USER-AGENT,AppleNews* 59 | USER-AGENT,AppleTV* 60 | USER-AGENT,FMDClient* 61 | USER-AGENT,FMFD* 62 | USER-AGENT,FindMy* 63 | USER-AGENT,Maps* 64 | USER-AGENT,Music* 65 | USER-AGENT,TestFlight* 66 | USER-AGENT,com.apple.Maps* 67 | USER-AGENT,com.apple.appstored* 68 | USER-AGENT,com.apple.geod* 69 | USER-AGENT,com.apple.news* 70 | USER-AGENT,com.apple.trustd* 71 | USER-AGENT,com.apple.tv* 72 | USER-AGENT,fmflocatord* 73 | USER-AGENT,geod* 74 | USER-AGENT,locationd* -------------------------------------------------------------------------------- /Surge/Bilibili.list: -------------------------------------------------------------------------------- 1 | # 该规则集用于配合bilibili自动地区脚本使用。 2 | DOMAIN,api.biliapi.com 3 | DOMAIN,api.biliapi.net 4 | DOMAIN,api.bilibili.com 5 | DOMAIN,app.biliapi.com 6 | DOMAIN,app.biliapi.net 7 | DOMAIN,app.bilibili.com 8 | DOMAIN,grpc.biliapi.net 9 | DOMAIN,m.bilibili.com 10 | DOMAIN,upos-hz-mirrorakam.akamaized.net 11 | DOMAIN,www.bilibili.com 12 | DOMAIN-KEYWORD,cn-hk-eq-bcache- 13 | IP-CIDR,121.11.192.0/24,no-resolve -------------------------------------------------------------------------------- /Surge/Download.list: -------------------------------------------------------------------------------- 1 | # Mac Download 2 | PROCESS-NAME,aria2c 3 | PROCESS-NAME,fdm 4 | PROCESS-NAME,Folx 5 | PROCESS-NAME,NetTransport 6 | PROCESS-NAME,Thunder 7 | PROCESS-NAME,Transmission 8 | PROCESS-NAME,uTorrent 9 | PROCESS-NAME,WebTorrent 10 | PROCESS-NAME,WebTorrent Helper 11 | PROCESS-NAME,DownloadService 12 | PROCESS-NAME,Weiyun 13 | 14 | # bt 15 | DOMAIN-KEYWORD,aria2 16 | DOMAIN-KEYWORD,xunlei 17 | DOMAIN-KEYWORD,yunpan 18 | DOMAIN-KEYWORD,Thunder 19 | DOMAIN-KEYWORD,XLLiveUD 20 | URL-REGEX,(torrent|announce.php\?passkey=|tracker|BitTorrent|bt_key|ed2k|find_node|get_peers|info_hash|magnet:|peer_id=) 21 | -------------------------------------------------------------------------------- /Surge/JS/BaiduCloud.js: -------------------------------------------------------------------------------- 1 | /* 2 | 百度网盘 解锁在线视频倍率/清晰度 3 | 4 | *************************** 5 | QuantumultX: 6 | 7 | [rewrite_local] 8 | https:\/\/pan\.baidu\.com\/rest\/\d\.\d\/membership\/user url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/BaiduCloud.js 9 | 10 | [mitm] 11 | hostname = pan.baidu.com 12 | 13 | *************************** 14 | Surge4 or Loon: 15 | 16 | [Script] 17 | http-response https:\/\/pan\.baidu\.com\/rest\/\d\.\d\/membership\/user requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/BaiduCloud.js 18 | 19 | [MITM] 20 | hostname = pan.baidu.com 21 | 22 | **************************/ 23 | 24 | if ($response.body) { 25 | $done({ 26 | body: JSON.stringify({ 27 | "product_infos": [{ 28 | "product_id": "5310897792128633390", 29 | "start_time": 1417260485, 30 | "end_time": 2147483648, 31 | "buy_time": "1417260485", 32 | "cluster": "offlinedl", 33 | "detail_cluster": "offlinedl", 34 | "product_name": "gz_telecom_exp" 35 | }, { 36 | "product_name": "svip2_nd", 37 | "product_description": "超级会员", 38 | "function_num": 0, 39 | "start_time": 1553702399, 40 | "buy_description": "", 41 | "buy_time": 0, 42 | "product_id": "1", 43 | "auto_upgrade_to_svip": 0, 44 | "end_time": 1872502399, 45 | "cluster": "vip", 46 | "detail_cluster": "svip", 47 | "status": 0 48 | }], 49 | "currenttime": 1573473597, 50 | "reminder": { 51 | "reminderWithContent": [], 52 | "advertiseContent": [] 53 | }, 54 | "request_id": 7501873289383874371 55 | }) 56 | }); 57 | } else { 58 | $done({}); 59 | } -------------------------------------------------------------------------------- /Surge/JS/Bili_Auto_Regions.js: -------------------------------------------------------------------------------- 1 | /************************** 2 | 3 | 哔哩哔哩(白图标外区版), 港澳台番剧自动切换地区 & 显示豆瓣评分 4 | 5 | 如需禁用豆瓣评分或策略通知, 可前往BoxJs设置. 6 | BoxJs订阅地址: https://raw.githubusercontent.com/NobyDa/Script/master/NobyDa_BoxJs.json 7 | 8 | Update: 2023.02.11 9 | Author: @NobyDa 10 | Use: Surge, QuanX, Loon 11 | 12 | **************************** 13 | 港澳台自动切换地区说明 : 14 | **************************** 15 | 16 | 地区自动切换功能仅适用于Surge4.7+(iOS),Loon2.1.10(286)+,QuanX1.0.22(543)+ 17 | 低于以上版本仅显示豆瓣评分. 18 | 19 | 您需要配置相关规则集: 20 | Surge、Loon: 21 | https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Bilibili.list 22 | 23 | QuanX: 24 | https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Bilibili.list 25 | 26 | 绑定相关select或static策略组,并且需要具有相关的区域代理服务器纳入您的子策略中,子策略可以是服务器也可以是其他区域策略组. 27 | 最后,您可以通过BoxJs设置策略名和子策略名,或者手动填入脚本. 28 | 29 | 如需搜索指定地区番剧, 可在搜索框添加后缀" 港", " 台", " 中". 例如: 进击的巨人 港 30 | 31 | QX用户注: 使用切换地区功能请确保您的QX=>其他设置=>温和策略机制处于关闭状态, 以及填写策略名和子策略名时注意大小写. 32 | 33 | **************************** 34 | Surge 4.7+ 远程脚本配置 : 35 | **************************** 36 | [Script] 37 | 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 38 | 39 | #可选, 适用于搜索指定地区的番剧 40 | 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 41 | 42 | [MITM] 43 | hostname = ap?.bili*i.com, ap?.bili*i.net 44 | 45 | **************************** 46 | Quantumult X 远程脚本配置 : 47 | **************************** 48 | [rewrite_local] 49 | ^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 50 | 51 | #可选, 适用于搜索指定地区的番剧 52 | ^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 53 | 54 | [mitm] 55 | hostname = ap?.bili*i.com, ap?.bili*i.net 56 | 57 | [filter_local] 58 | #可选, 由于qx纯tun特性, 不添加规则可能会导致脚本失效. https://github.com/NobyDa/Script/issues/382 59 | ip-cidr, 203.107.1.1/24, reject 60 | 61 | **************************** 62 | Loon 远程脚本配置 : 63 | **************************** 64 | [Script] 65 | 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自动地区 66 | 67 | #可选, 适用于搜索指定地区的番剧 68 | 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自动地区(搜索) 69 | 70 | [Mitm] 71 | hostname = ap?.bili*i.com, ap?.bili*i.net 72 | 73 | ***************************/ 74 | 75 | let $ = nobyda(); 76 | let run = EnvInfo(); 77 | 78 | async function SwitchRegion(title, url, body) { 79 | const Group = $.read('BiliArea_Policy') || '📺 DomesticMedia'; //Your blibli policy group name. 80 | const CN = $.read('BiliArea_CN') || 'DIRECT'; //Your China sub-policy name. 81 | const TW = $.read('BiliArea_TW') || '🇹🇼 sub-policy'; //Your Taiwan sub-policy name. 82 | const HK = $.read('BiliArea_HK') || '🇭🇰 sub-policy'; //Your HongKong sub-policy name. 83 | const DF = $.read('BiliArea_DF') || '🏁 sub-policy'; //Sub-policy name used after region is blocked(e.g. url 404) 84 | const off = $.read('BiliArea_disabled') || ''; //WiFi blacklist(disable region change), separated by commas. 85 | const current = await $.getPolicy(Group); 86 | const area = (() => { 87 | let select = {}; 88 | let chtMatch = title && title.split('').some(v => zhHans().includes(v)); 89 | if (/\u6e2f[\u4e00-\u9fa5]+\u5340|%20%E6%B8%AF&/.test(title || url)) { 90 | const test = /\u53f0[\u4e00-\u9fa5]+\u5340/.test(title); 91 | if (current != HK && (current == TW && test ? 0 : 1)) 92 | select = { policy: HK, mode: '香港' }; 93 | } else if (/\u53f0[\u4e00-\u9fa5]+\u5340|%20%E5%8F%B0&/.test(title || url)) { 94 | if (current != TW) select = { policy: TW, mode: '台湾' }; 95 | } else if (body.code === -404 || chtMatch) { 96 | if (current != DF) select = { policy: DF, mode: '后备' }; 97 | } else if (current != CN) { 98 | select = { policy: CN, mode: '直连' }; 99 | } 100 | if ($.isQuanX && current === 'direct' && select.policy === 'DIRECT') { 101 | select = {}; //prevent loopback in some cases 102 | } 103 | return select; 104 | })() 105 | 106 | if (area.policy && !off.includes($.ssid || undefined)) { 107 | const change = await $.setPolicy(Group, area.policy); 108 | const msg = (() => { 109 | if (change && typeof current !== 'number') { 110 | return `${current} ➤ ${area.policy}`; 111 | } else if (current === 2) { 112 | return `策略组名未填写或填写有误 ⚠️` 113 | } else if (current === 3) { 114 | return `不支持您的VPN应用版本 ⚠️` 115 | } else if (change === 0) { 116 | return `子策略名未填写或填写有误 ⚠️` 117 | } else { 118 | return `未知错误 ⚠️` 119 | } 120 | })() 121 | if ($.read('BiliAreaNotify') === 'true') { 122 | console.log(`${title || ''}\n模式: 策略组使用"${area.mode}"子策略\n走向: ${msg}`); 123 | } else { 124 | $.notify(title || '', ``, `模式: 策略组使用"${area.mode}"子策略\n走向: ${msg}`); 125 | } 126 | if (change) { 127 | return true; 128 | } 129 | } 130 | return false; 131 | } 132 | 133 | function EnvInfo() { 134 | const url = $request.url; 135 | if (typeof ($response) !== 'undefined') { 136 | const raw = JSON.parse($response.body || "{}"); 137 | const data = raw.data || raw.result || {}; 138 | const title = [data.title, data.series && data.series.series_title, data.season_title] 139 | .filter(c => /\u5340\uff09/.test(c))[0] || data.title; 140 | SwitchRegion(title, null, raw) 141 | .then(s => s ? $done({ 142 | status: $.isQuanX ? "HTTP/1.1 307" : 307, 143 | headers: { 144 | Location: url 145 | }, 146 | body: "{}" 147 | }) : QueryRating(raw, data)); 148 | } else { 149 | const res = { 150 | url: url.replace(/%20(%E6%B8%AF|%E5%8F%B0|%E4%B8%AD)&/g, '&') 151 | }; 152 | SwitchRegion(null, url, {}).then(() => $done(res)); 153 | } 154 | } 155 | 156 | async function QueryRating(body, play) { 157 | try { 158 | const ratingEnabled = $.read('BiliDoubanRating') === 'false'; 159 | if (!ratingEnabled && play.title && body.data && body.data.badge_info) { 160 | const [t1, t2] = await Promise.all([ 161 | GetRawInfo(play.title.replace(/\uff08[\u4e00-\u9fa5]+\u5340\uff09/, '')), 162 | GetRawInfo(play.origin_name) 163 | ]); 164 | const exYear = body.data.publish.release_date_show.split(/^(\d{4})/)[1]; 165 | const info1 = (play.staff && play.staff.info) || ''; 166 | const info2 = (play.actor && play.actor.info) || ''; 167 | const info3 = (play.celebrity && play.celebrity.map(n => n.name).join('/')) || ''; 168 | const filterInfo = [play.title, play.origin_name, info1 + info2 + info3, exYear]; 169 | const [rating, folk, name, id, other] = ExtractMovieInfo([...t1, ...t2], filterInfo); 170 | const limit = JSON.stringify(body.data.modules) 171 | .replace(/"\u53d7\u9650"/g, `""`).replace(/("area_limit":)1/g, '$10'); 172 | body.data.modules = JSON.parse(limit); 173 | body.data.detail = body.data.new_ep.desc.replace(/连载中,/, ''); 174 | body.data.badge_info.text = `⭐️ 豆瓣:${!$.is403 ? `${rating || '无评'}分 (${folk || '无评价'})` : `查询频繁!`}`; 175 | body.data.evaluate = `${body.data.evaluate || ''}\n\n豆瓣评分搜索结果: ${JSON.stringify(other, 0, 1)}`; 176 | body.data.new_ep.desc = name; 177 | body.data.styles.unshift({ 178 | name: "⭐️ 点击此处打开豆瓣剧集详情页", 179 | url: `https://m.douban.com/${id ? `movie/subject/${id}/` : `search/?query=${encodeURI(play.title)}`}` 180 | }); 181 | } 182 | } catch (err) { 183 | console.log(`Douban rating: \n${err}\n`); 184 | } finally { 185 | $done({ 186 | body: JSON.stringify(body) 187 | }); 188 | } 189 | } 190 | 191 | function ExtractMovieInfo(ret, fv) { 192 | const sole = new Set(ret.map(s => JSON.stringify(s))); //delete duplicate 193 | const f1 = [...sole].map(p => JSON.parse(p)) 194 | .filter(t => { 195 | t.accuracy = 0; 196 | if (t.name && fv[0]) { //title 197 | if (t.name.includes(fv[0].slice(0, 4))) t.accuracy++; 198 | if (t.name.includes(fv[0].slice(-3))) t.accuracy++; 199 | } 200 | if (t.origin && fv[1]) { //origin title 201 | if (t.origin.includes(fv[1].slice(0, 4))) t.accuracy++; 202 | if (t.origin.includes(fv[1].slice(-3))) t.accuracy++; 203 | } 204 | if (t.pd && fv[2]) { //producer or actor 205 | const len = t.pd.split('/').filter(c => fv[2].includes(c)); 206 | t.accuracy += len.length; 207 | } 208 | if (t.year && fv[3] && t.year == fv[3]) t.accuracy++; //year 209 | return Boolean(t.accuracy); 210 | }); 211 | let x = {}; //assign most similar 212 | const f2 = f1.reduce((p, c) => c.accuracy > p ? (x = c, c.accuracy) : p, 0); 213 | return [x.rating, x.folk, x.name, x.id, f1]; 214 | } 215 | 216 | function GetRawInfo(t) { 217 | let res = []; 218 | let st = Date.now(); 219 | return new Promise((resolve) => { 220 | if (!t) return resolve(res); 221 | $.get({ 222 | url: `https://www.douban.com/search?cat=1002&q=${encodeURIComponent(t)}`, 223 | headers: { 224 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Safari/605.1.15', 225 | 'Cookie': JSON.stringify(st) 226 | } 227 | }, (error, resp, data) => { 228 | if (error) { 229 | console.log(`Douban rating: \n${t}\nRequest error: ${error}\n`); 230 | } else { 231 | if (/\u767b\u5f55<\/a>\u540e\u91cd\u8bd5\u3002/.test(data)) $.is403 = true; 232 | let s = data.replace(/\n| |&#\d{2}/g, '') 233 | .match(/\[(\u7535\u5f71|\u7535\u89c6\u5267)\].+?subject-cast\">.+?<\/span>/g) || []; 234 | for (let i = 0; i < s.length; i++) { 235 | res.push({ 236 | name: s[i].split(/\}\)">(.+?)<\/a>/)[1], 237 | origin: s[i].split(/\u540d:(.+?)(\/|<)/)[1], 238 | pd: s[i].split(/\u539f\u540d.+?\/(.+?)\/\d+<\/span>$/)[1], 239 | rating: s[i].split(/">(\d\.\d)$/)[1] 243 | }) 244 | } 245 | let et = ((Date.now() - st) / 1000).toFixed(2); 246 | console.log(`Douban rating: \n${t}\n${res.length} movie info searched. (${et} s)\n`); 247 | } 248 | resolve(res); 249 | }) 250 | }) 251 | } 252 | 253 | function nobyda() { 254 | const isHTTP = typeof $httpClient != "undefined"; 255 | const isLoon = typeof $loon != "undefined"; 256 | const isQuanX = typeof $task != "undefined"; 257 | const isSurge = typeof $network != "undefined" && typeof $script != "undefined"; 258 | const ssid = (() => { 259 | if (isQuanX && typeof ($environment) !== 'undefined') { 260 | return $environment.ssid; 261 | } 262 | if (isSurge && $network.wifi) { 263 | return $network.wifi.ssid; 264 | } 265 | if (isLoon) { 266 | return JSON.parse($config.getConfig()).ssid; 267 | } 268 | })(); 269 | const notify = (title, subtitle, message) => { 270 | console.log(`${title}\n${subtitle}\n${message}`); 271 | if (isQuanX) $notify(title, subtitle, message); 272 | if (isHTTP) $notification.post(title, subtitle, message); 273 | } 274 | const read = (key) => { 275 | if (isQuanX) return $prefs.valueForKey(key); 276 | if (isHTTP) return $persistentStore.read(key); 277 | } 278 | const adapterStatus = (response) => { 279 | if (!response) return null; 280 | if (response.status) { 281 | response["statusCode"] = response.status; 282 | } else if (response.statusCode) { 283 | response["status"] = response.statusCode; 284 | } 285 | return response; 286 | } 287 | const getPolicy = (groupName) => { 288 | if (isSurge) { 289 | if (typeof ($httpAPI) === 'undefined') return 3; 290 | return new Promise((resolve) => { 291 | $httpAPI("GET", "v1/policy_groups/select", { 292 | group_name: encodeURIComponent(groupName) 293 | }, (b) => resolve(b.policy || 2)) 294 | }) 295 | } 296 | if (isLoon) { 297 | if (typeof ($config.getPolicy) === 'undefined') return 3; 298 | const getName = $config.getPolicy(groupName); 299 | return getName || 2; 300 | } 301 | if (isQuanX) { 302 | if (typeof ($configuration) === 'undefined') return 3; 303 | return new Promise((resolve) => { 304 | $configuration.sendMessage({ 305 | action: "get_policy_state" 306 | }).then(b => { 307 | if (b.ret && b.ret[groupName]) { 308 | resolve(b.ret[groupName][1]); 309 | } else resolve(2); 310 | }, () => resolve()); 311 | }) 312 | } 313 | } 314 | const setPolicy = (group, policy) => { 315 | if (isSurge && typeof ($httpAPI) !== 'undefined') { 316 | return new Promise((resolve) => { 317 | $httpAPI("POST", "v1/policy_groups/select", { 318 | group_name: group, 319 | policy: policy 320 | }, (b) => resolve(!b.error || 0)) 321 | }) 322 | } 323 | if (isLoon && typeof ($config.getPolicy) !== 'undefined') { 324 | const set = $config.setSelectPolicy(group, policy); 325 | return set || 0; 326 | } 327 | if (isQuanX && typeof ($configuration) !== 'undefined') { 328 | return new Promise((resolve) => { 329 | $configuration.sendMessage({ 330 | action: "set_policy_state", 331 | content: { 332 | [group]: policy 333 | } 334 | }).then((b) => resolve(!b.error || 0), () => resolve()); 335 | }) 336 | } 337 | } 338 | const get = (options, callback) => { 339 | if (isQuanX) { 340 | options["method"] = "GET"; 341 | $task.fetch(options).then(response => { 342 | callback(null, adapterStatus(response), response.body) 343 | }, reason => callback(reason.error, null, null)) 344 | } 345 | if (isHTTP) { 346 | if (isSurge) options.headers['X-Surge-Skip-Scripting'] = false; 347 | $httpClient.get(options, (error, response, body) => { 348 | callback(error, adapterStatus(response), body) 349 | }) 350 | } 351 | } 352 | return { 353 | getPolicy, 354 | setPolicy, 355 | isSurge, 356 | isQuanX, 357 | isLoon, 358 | notify, 359 | read, 360 | ssid, 361 | get 362 | } 363 | } 364 | 365 | // 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 366 | function zhHans() { 367 | return `䊷䋙䝼䰾䲁丟並乾亂亞佇馀併來侖侶俁係俔俠倀倆倈倉個們倫偉側偵偽傑傖傘備傭傯傳傴債傷傾僂僅僉僑僕僞僥僨價儀儂億儈儉儐儔儕儘償優儲儷儺儻儼兌兒兗內兩冊冪凈凍凜凱別刪剄則剋剎剗剛剝剮剴創劃劇劉劊劌劍劑勁動務勛勝勞勢勩勱勵勸勻匭匯匱區協卻厙厠厭厲厴參叄叢吒吳吶呂咼員唄唚問啓啞啟啢喎喚喪喬單喲嗆嗇嗊嗎嗚嗩嗶嘆嘍嘔嘖嘗嘜嘩嘮嘯嘰嘵嘸嘽噓噝噠噥噦噯噲噴噸噹嚀嚇嚌嚕嚙嚦嚨嚲嚳嚴嚶囀囁囂囅囈囑囪圇國圍園圓圖團垵埡埰執堅堊堖堝堯報場塊塋塏塒塗塢塤塵塹墊墜墮墳墻墾壇壈壋壓壘壙壚壞壟壠壢壩壯壺壼壽夠夢夾奐奧奩奪奬奮奼妝姍姦娛婁婦婭媧媯媼媽嫗嫵嫻嫿嬀嬈嬋嬌嬙嬡嬤嬪嬰嬸孌孫學孿宮寢實寧審寫寬寵寶將專尋對導尷屆屍屓屜屢層屨屬岡峴島峽崍崗崢崬嵐嶁嶄嶇嶔嶗嶠嶢嶧嶮嶴嶸嶺嶼巋巒巔巰帥師帳帶幀幃幗幘幟幣幫幬幹幺幾庫廁廂廄廈廚廝廟廠廡廢廣廩廬廳弒弳張強彈彌彎彙彞彥後徑從徠復徵徹恆恥悅悞悵悶惡惱惲惻愛愜愨愴愷愾慄態慍慘慚慟慣慤慪慫慮慳慶憂憊憐憑憒憚憤憫憮憲憶懇應懌懍懟懣懨懲懶懷懸懺懼懾戀戇戔戧戩戰戱戲戶拋拾挩挾捨捫掃掄掗掙掛採揀揚換揮損搖搗搵搶摑摜摟摯摳摶摻撈撏撐撓撝撟撣撥撫撲撳撻撾撿擁擄擇擊擋擓擔據擠擬擯擰擱擲擴擷擺擻擼擾攄攆攏攔攖攙攛攜攝攢攣攤攪攬敗敘敵數斂斃斕斬斷時晉晝暈暉暘暢暫曄曆曇曉曏曖曠曨曬書會朧東杴极柵桿梔梘條梟梲棄棖棗棟棧棲棶椏楊楓楨業極榪榮榲榿構槍槤槧槨槳樁樂樅樓標樞樣樸樹樺橈橋機橢橫檁檉檔檜檟檢檣檮檯檳檸檻櫃櫓櫚櫛櫝櫞櫟櫥櫧櫨櫪櫫櫬櫱櫳櫸櫻欄權欏欒欖欞欽歐歟歡歲歷歸歿殘殞殤殨殫殮殯殲殺殻殼毀毆毿氂氈氌氣氫氬氳決沒沖況洶浹涇涼淚淥淪淵淶淺渙減渦測渾湊湞湯溈準溝溫滄滅滌滎滬滯滲滷滸滻滾滿漁漚漢漣漬漲漵漸漿潁潑潔潙潛潤潯潰潷潿澀澆澇澗澠澤澦澩澮澱濁濃濕濘濟濤濫濰濱濺濼濾瀅瀆瀉瀏瀕瀘瀝瀟瀠瀦瀧瀨瀲瀾灃灄灑灕灘灝灠灣灤灧災為烏烴無煉煒煙煢煥煩煬熅熒熗熱熲熾燁燈燉燒燙燜營燦燭燴燼燾爍爐爛爭爲爺爾牆牘牽犖犢犧狀狹狽猙猶猻獁獄獅獎獨獪獫獮獰獲獵獷獸獺獻獼玀現琺琿瑋瑒瑣瑤瑩瑪瑲璉璣璦璫環璽瓊瓏瓔瓚甌產産畝畢異畵當疇疊痙痾瘂瘋瘍瘓瘞瘡瘧瘮瘲瘺瘻療癆癇癉癘癟癢癤癥癧癩癬癭癮癰癱癲發皚皰皸皺盜盞盡監盤盧眥眾睏睜睞瞘瞜瞞瞶瞼矓矚矯硜硤硨硯碩碭碸確碼磑磚磣磧磯磽礆礎礙礦礪礫礬礱祿禍禎禕禡禦禪禮禰禱禿秈稅稈稟種稱穀穌積穎穠穡穢穩穫穭窩窪窮窯窵窶窺竄竅竇竈竊竪競筆筍筧筴箋箏節範築篋篔篤篩篳簀簍簞簡簣簫簹簽簾籃籌籙籜籟籠籩籪籬籮粵糝糞糧糲糴糶糹糾紀紂約紅紆紇紈紉紋納紐紓純紕紖紗紘紙級紛紜紝紡紬細紱紲紳紵紹紺紼紿絀終組絅絆絎結絕絛絝絞絡絢給絨絰統絲絳絶絹綁綃綆綈綉綌綏經綜綞綠綢綣綫綬維綯綰綱網綳綴綸綹綺綻綽綾綿緄緇緊緋緑緒緓緔緗緘緙線緝緞締緡緣緦編緩緬緯緱緲練緶緹緻縈縉縊縋縐縑縕縗縛縝縞縟縣縧縫縭縮縱縲縳縵縶縷縹總績繃繅繆繒織繕繚繞繡繢繩繪繫繭繮繯繰繳繸繹繼繽繾纈纊續纍纏纓纖纘纜缽罈罌罰罵罷羅羆羈羋羥義習翹耬耮聖聞聯聰聲聳聵聶職聹聽聾肅脅脈脛脫脹腎腖腡腦腫腳腸膃膚膠膩膽膾膿臉臍臏臘臚臟臠臢臨臺與興舉舊艙艤艦艫艱艷芻苎苧茲荊莊莖莢莧華萇萊萬萵葉葒著葤葦葯葷蒓蒔蒞蒼蓀蓋蓮蓯蓴蓽蔔蔞蔣蔥蔦蔭蕁蕆蕎蕒蕓蕕蕘蕢蕩蕪蕭蕷薀薈薊薌薔薘薟薦薩薴薺藍藎藝藥藪藴藶藹藺蘄蘆蘇蘊蘋蘚蘞蘢蘭蘺蘿虆處虛虜號虧虯蛺蛻蜆蜡蝕蝟蝦蝸螄螞螢螻螿蟄蟈蟎蟣蟬蟯蟲蟶蟻蠅蠆蠐蠑蠟蠣蠨蠱蠶蠻衆術衕衚衛衝衹袞裊裏補裝裡製複褌褘褲褳褸褻襇襏襖襝襠襤襪襯襲見覎規覓視覘覡覥覦親覬覯覲覷覺覽覿觀觴觶觸訁訂訃計訊訌討訐訒訓訕訖託記訛訝訟訢訣訥訩訪設許訴訶診註詁詆詎詐詒詔評詖詗詘詛詞詠詡詢詣試詩詫詬詭詮詰話該詳詵詼詿誄誅誆誇誌認誑誒誕誘誚語誠誡誣誤誥誦誨說説誰課誶誹誼誾調諂諄談諉請諍諏諑諒論諗諛諜諝諞諢諤諦諧諫諭諮諱諳諶諷諸諺諼諾謀謁謂謄謅謊謎謐謔謖謗謙謚講謝謠謡謨謫謬謭謳謹謾證譎譏譖識譙譚譜譫譯議譴護譸譽譾讀變讎讒讓讕讖讜讞豈豎豐豬豶貓貝貞貟負財貢貧貨販貪貫責貯貰貲貳貴貶買貸貺費貼貽貿賀賁賂賃賄賅資賈賊賑賒賓賕賙賚賜賞賠賡賢賣賤賦賧質賫賬賭賴賵賺賻購賽賾贄贅贇贈贊贋贍贏贐贓贔贖贗贛贜赬趕趙趨趲跡踐踴蹌蹕蹣蹤蹺躂躉躊躋躍躑躒躓躕躚躡躥躦躪軀車軋軌軍軑軒軔軛軟軤軫軲軸軹軺軻軼軾較輅輇輈載輊輒輓輔輕輛輜輝輞輟輥輦輩輪輬輯輳輸輻輾輿轀轂轄轅轆轉轍轎轔轟轡轢轤辦辭辮辯農逕這連進運過達違遙遜遞遠適遲遷選遺遼邁還邇邊邏邐郟郵鄆鄉鄒鄔鄖鄧鄭鄰鄲鄴鄶鄺酇酈醖醜醞醫醬醱釀釁釃釅釋釐釒釓釔釕釗釘釙針釣釤釧釩釵釷釹釺鈀鈁鈃鈄鈈鈉鈍鈎鈐鈑鈒鈔鈕鈞鈣鈥鈦鈧鈮鈰鈳鈴鈷鈸鈹鈺鈽鈾鈿鉀鉅鉈鉉鉋鉍鉑鉕鉗鉚鉛鉞鉢鉤鉦鉬鉭鉶鉸鉺鉻鉿銀銃銅銍銑銓銖銘銚銛銜銠銣銥銦銨銩銪銫銬銱銳銷銹銻銼鋁鋃鋅鋇鋌鋏鋒鋙鋝鋟鋣鋤鋥鋦鋨鋩鋪鋭鋮鋯鋰鋱鋶鋸鋼錁錄錆錇錈錏錐錒錕錘錙錚錛錟錠錡錢錦錨錩錫錮錯録錳錶錸鍀鍁鍃鍆鍇鍈鍋鍍鍔鍘鍚鍛鍠鍤鍥鍩鍬鍰鍵鍶鍺鎂鎄鎇鎊鎔鎖鎘鎛鎡鎢鎣鎦鎧鎩鎪鎬鎮鎰鎲鎳鎵鎸鎿鏃鏇鏈鏌鏍鏐鏑鏗鏘鏜鏝鏞鏟鏡鏢鏤鏨鏰鏵鏷鏹鏽鐃鐋鐐鐒鐓鐔鐘鐙鐝鐠鐦鐧鐨鐫鐮鐲鐳鐵鐶鐸鐺鐿鑄鑊鑌鑒鑔鑕鑞鑠鑣鑥鑭鑰鑱鑲鑷鑹鑼鑽鑾鑿钁長門閂閃閆閈閉開閌閎閏閑間閔閘閡閣閥閨閩閫閬閭閱閲閶閹閻閼閽閾閿闃闆闈闊闋闌闍闐闒闓闔闕闖關闞闠闡闤闥阪陘陝陣陰陳陸陽隉隊階隕際隨險隱隴隸隻雋雖雙雛雜雞離難雲電霢霧霽靂靄靈靚靜靦靨鞀鞏鞝鞽韁韃韉韋韌韍韓韙韜韞韻響頁頂頃項順頇須頊頌頎頏預頑頒頓頗領頜頡頤頦頭頮頰頲頴頷頸頹頻頽顆題額顎顏顒顓顔願顙顛類顢顥顧顫顬顯顰顱顳顴風颭颮颯颱颳颶颸颺颻颼飀飄飆飈飛飠飢飣飥飩飪飫飭飯飲飴飼飽飾飿餃餄餅餉養餌餎餏餑餒餓餕餖餚餛餜餞餡館餱餳餶餷餺餼餾餿饁饃饅饈饉饊饋饌饑饒饗饜饞饢馬馭馮馱馳馴馹駁駐駑駒駔駕駘駙駛駝駟駡駢駭駰駱駸駿騁騂騅騌騍騎騏騖騙騤騫騭騮騰騶騷騸騾驀驁驂驃驄驅驊驌驍驏驕驗驚驛驟驢驤驥驦驪驫骯髏髒體髕髖髮鬆鬍鬚鬢鬥鬧鬩鬮鬱魎魘魚魛魢魨魯魴魷魺鮁鮃鮊鮋鮍鮎鮐鮑鮒鮓鮚鮜鮝鮞鮦鮪鮫鮭鮮鮳鮶鮺鯀鯁鯇鯉鯊鯒鯔鯕鯖鯗鯛鯝鯡鯢鯤鯧鯨鯪鯫鯴鯷鯽鯿鰁鰂鰃鰈鰉鰍鰏鰐鰒鰓鰜鰟鰠鰣鰥鰨鰩鰭鰮鰱鰲鰳鰵鰷鰹鰺鰻鰼鰾鱂鱅鱈鱉鱒鱔鱖鱗鱘鱝鱟鱠鱣鱤鱧鱨鱭鱯鱷鱸鱺鳥鳧鳩鳬鳲鳳鳴鳶鳾鴆鴇鴉鴒鴕鴛鴝鴞鴟鴣鴦鴨鴯鴰鴴鴷鴻鴿鵁鵂鵃鵐鵑鵒鵓鵜鵝鵠鵡鵪鵬鵮鵯鵲鵷鵾鶄鶇鶉鶊鶓鶖鶘鶚鶡鶥鶩鶪鶬鶯鶲鶴鶹鶺鶻鶼鶿鷀鷁鷂鷄鷈鷊鷓鷖鷗鷙鷚鷥鷦鷫鷯鷲鷳鷸鷹鷺鷽鷿鸇鸌鸏鸕鸘鸚鸛鸝鸞鹵鹹鹺鹽麗麥麩麵麽黃黌點黨黲黶黷黽黿鼉鼴齊齋齎齏齒齔齕齗齙齜齟齠齡齦齪齬齲齶齷龍龎龐龔龕龜` 368 | } -------------------------------------------------------------------------------- /Surge/JS/CamScanner.js: -------------------------------------------------------------------------------- 1 | /* 2 | CamScanner 解锁部分高级特权 3 | 4 | *************************** 5 | Quantumult X: 6 | 7 | [rewrite_local] 8 | ^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 9 | 10 | [mitm] 11 | hostname = ap*.intsig.net 12 | 13 | *************************** 14 | Surge4 or Loon: 15 | 16 | [Script] 17 | http-response https:\/\/(api|api-cs)\.intsig\.net\/purchase\/cs\/query_property\? requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/CamScanner.js 18 | 19 | [MITM] 20 | hostname = ap*.intsig.net 21 | 22 | *************************** 23 | Quantumult: 24 | 25 | [REWRITE] 26 | https:\/\/(api|api-cs)\.intsig\.net\/purchase\/cs\/query_property\? url simple-response SFRUUC8xLjEgMjAwIE9LCgp7CiAiZGF0YSI6IHsKICAicHNubF92aXBfcHJvcGVydHkiOiB7CiAgICJleHBpcnkiOiAiMTY0MzczMTIwMCIKICB9CiB9Cn0= 27 | 28 | [MITM] 29 | hostname = ap*.intsig.net 30 | 31 | **************************/ 32 | let obj = JSON.parse($response.body); 33 | obj = {"data":{"psnl_vip_property":{"expiry":"2013017600"}}}; 34 | $done({body: JSON.stringify(obj)}); -------------------------------------------------------------------------------- /Surge/JS/Google_CAPTCHA.js: -------------------------------------------------------------------------------- 1 | /******************************** 2 | Google搜索人机验证解决方案 3 | 搜索内容时遇到人机验证立即并发使用多个代理策略、策略组尝试搜索内容,并返回最优结果。 4 | 5 | 脚本作者:@NobyDa 6 | 更新时间:2024/05/19 7 | 平台兼容:Surge(iOS4.9.3+/macOS4.2.3+) / QuantumultX(1.0.26+) / Loon(3.1.9[694]+) 8 | 9 | 可在 BoxJs(低优先级)、Surge模块参数、Loon插件参数中填写筛选的代理策略、策略组的正则表达式。 10 | 所有代理策略、策略组至多筛选、使用20个,可在BoxJs中测试匹配的策略,不筛选则表示随机使用。 11 | 12 | 注意:Surge由于策略架构问题,正则表达式筛选的"代理策略"不包含"外部代理策略"; 13 | QuantumultX、Loon则无此限制,正则表达式可筛选所有"策略组"内的"代理策略"。 14 | 15 | ********************************* 16 | Surge(iOS 5.9.0+/macOS 5.5.0+) 模块: 17 | https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/GoogleCAPTCHA.sgmodule 18 | 19 | ********************************* 20 | QuantumultX(1.0.26+) 重写资源引用: 21 | https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/Snippet/GoogleCAPTCHA.snippet 22 | 23 | ********************************* 24 | Loon(3.1.9[694]+) 插件: 25 | https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_Google_CAPTCHA.plugin 26 | 27 | ********************************* 28 | BoxJs 订阅地址: 29 | https://raw.githubusercontent.com/NobyDa/Script/master/NobyDa_BoxJs.json 30 | 31 | *********************************/ 32 | 33 | const $ = new NobyDa_Tools(); 34 | $.ret = {}; 35 | 36 | !(async () => { 37 | if (($response.status || $response.statusCode) == 200) return; 38 | const req = JSON.parse(JSON.stringify($request)); 39 | const policy = await $.policy(); 40 | const regexText = (typeof $argument == 'string' && $argument) || 41 | $.data.read('GOOGLE_CAPTCHA_REGEX') || // loon plugin args. 42 | JSON.parse($.data.read('GOOGLE_CAPTCHA') || '{}').Regex || ''; // empty = all 43 | const selected = [...policy.group, ...policy.proxy] 44 | .filter((n) => n && new RegExp(regexText).test(n)) 45 | .sort(() => Math.random() - 0.5).slice(0, 20); // prevent too many TCP, filtered to random select up to 20 46 | console.log(`[INFO]: Use policy ${JSON.stringify(selected, null, 2)}`); 47 | await Promise.any([ 48 | ...selected.map( 49 | (i) => new Promise((r, e) => { 50 | if (req.headers['User-Agent']) req.headers.Cookie = `${Math.random()}`; // prevent set-cookie 51 | if (req.headers['user-agent']) req.headers.cookie = `${Math.random()}`; // h2 52 | $.http[req.method.toLowerCase()]({ 53 | policy: i, node: i, opts: { policy: i }, // policy:surge, node:loon, opts:qx 54 | ...req 55 | }).then((v) => { 56 | if (v.status == 200) { 57 | r({ policy: i, body: { ...v, status: $.isQuanX ? 'HTTP/1.1 200' : 200 } }) 58 | } else if (v.status == 429) { 59 | e(console.log(`[INFO]: Policy "${i}" need to CAPTCHA`)) 60 | } else { 61 | e(console.log(`[INFO]: Policy "${i}" unknown resp status "${v.status}"`)) 62 | } 63 | }).catch((err) => e(console.log(`[ERROR]: ${err}`))) 64 | }) 65 | ) 66 | ]).then((data) => { 67 | $.ret = data.body; 68 | console.log(`[INFO]: Use data from "${data.policy}"`); 69 | }) 70 | })() 71 | .catch((err) => console.log(`[ERROR]: ${(err && err.message) || err}`)) 72 | .finally(() => $done($.ret)); 73 | 74 | 75 | function NobyDa_Tools() { 76 | this.isLoon = typeof $loon !== "undefined"; 77 | this.isQuanX = typeof $configuration !== 'undefined'; 78 | this.isSurge = typeof $environment !== 'undefined' && $environment['surge-version']; 79 | this.isNode = typeof module !== 'undefined' && !!module.exports; 80 | this.http = Object.fromEntries( 81 | ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH"].map( 82 | (m) => [m.toLowerCase(), (opts) => { 83 | if (this.isQuanX) return new Promise((resolve, reject) => { 84 | $task.fetch({ method: m, ...opts }) 85 | .then((r) => resolve({ 86 | status: r.statusCode, headers: r.headers, body: r.body, 87 | }), e => reject(e.error)) 88 | }); 89 | if (this.isSurge || this.isLoon || this.isNode) return new Promise((resolve, reject) => { 90 | const request = this.isNode ? require("request") : $httpClient; 91 | request[m.toLowerCase()](opts, (e, r, b) => { 92 | if (e) reject(e); 93 | else resolve({ status: r.status || r.statusCode, headers: r.headers, body: b }) 94 | }) 95 | }); 96 | }] 97 | ) 98 | ); 99 | this.policy = () => { 100 | if (this.isSurge) return new Promise((r) => { 101 | $httpAPI("GET", "v1/policies", null, (v) => r({ 102 | proxy: v.proxies, 103 | group: v['policy-groups'] 104 | })) 105 | }); 106 | if (this.isQuanX) return new Promise((r) => { 107 | $configuration.sendMessage({ 108 | action: "get_customized_policy" 109 | }).then(b => r({ 110 | proxy: Object.keys(b.ret) 111 | .reduce((t, i) => [...new Set([...t, ...b.ret[i].candidates || []])], []) 112 | .filter((v) => !b.ret[v] && !['direct', 'proxy', 'reject'].includes(v)), 113 | group: Object.keys(b.ret) 114 | }), () => r({})); 115 | }); 116 | if (this.isLoon) return new Promise(async (r1) => { 117 | const config = JSON.parse($config.getConfig()); 118 | const groupData = await Promise.all(config['all_policy_groups'].map((i) => new Promise((r2) => { 119 | $config.getSubPolicies(i, (b) => { r2(JSON.parse(b || '[]')) }) 120 | }))); 121 | r1({ 122 | proxy: groupData.reduce((t, i) => [...new Set([...t, ...i.filter((v) => { 123 | return v.type == 'node' && !config['all_buildin_nodes'].includes(v.name) 124 | }).map((n) => n.name)])], []), 125 | group: config['all_policy_groups'] 126 | }) 127 | }); 128 | }; 129 | this.data = Object.fromEntries(['read', 'write'].map( 130 | (i) => [i, (v1, v2) => { 131 | if (i === 'write') { 132 | if (this.isSurge || this.isLoon) return $persistentStore.write(v1, v2); 133 | if (this.isQuanX) return $prefs.setValueForKey(v1, v2); 134 | } else if (i === 'read') { 135 | if (this.isSurge || this.isLoon) return $persistentStore.read(v1); 136 | if (this.isQuanX) return $prefs.valueForKey(v1); 137 | } 138 | }] 139 | )); 140 | } -------------------------------------------------------------------------------- /Surge/JS/Kuwo.js: -------------------------------------------------------------------------------- 1 | /* 2 | 酷我音乐 解锁会员试听及部分功能 3 | 4 | *************************** 5 | QuantumultX: 6 | 7 | [rewrite_local] 8 | ^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 9 | 10 | [mitm] 11 | hostname = vip1.kuwo.cn 12 | 13 | *************************** 14 | Surge4 or Loon: 15 | 16 | [Script] 17 | http-response ^https?:\/\/vip1\.kuwo\.cn\/(vip\/v2\/user\/vip|vip\/spi/mservice) requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Kuwo.js 18 | 19 | [MITM] 20 | hostname = vip1.kuwo.cn 21 | 22 | **************************/ 23 | 24 | var body = $response.body; 25 | var url = $request.url; 26 | var obj = JSON.parse(body); 27 | 28 | const vip = '/vip/v2/user/vip'; 29 | const time = '/vip/spi/mservice'; 30 | 31 | if (url.indexOf(vip) != -1) { 32 | obj.data["isNewUser"] = "2"; 33 | obj.data["vipLuxuryExpire"] = "1835312949000"; 34 | obj.data["time"] = "1961170340993"; 35 | obj.data["isYearUser"] = "2"; 36 | obj.data["vipmExpire"] = "1835312949000"; 37 | obj.data["vipOverSeasExpire"] = "1835312949000"; 38 | obj.data["vipExpire"] = "1835312949000"; 39 | obj.data["vip3Expire"] = "1835312949000"; 40 | body = JSON.stringify(obj); 41 | } 42 | 43 | if (url.indexOf(time) != -1) { 44 | obj["isVIPMAutoPay"] = 2; 45 | obj["isVIPLuxAutoPay"] = 2; 46 | body = JSON.stringify(obj); 47 | } 48 | 49 | $done({body}); -------------------------------------------------------------------------------- /Surge/JS/MIX.js: -------------------------------------------------------------------------------- 1 | /* 2 | MIX 解锁特权 (需恢复购买) 3 | 4 | *************************** 5 | QuantumultX: 6 | 7 | [rewrite_local] 8 | https?:\/\/cdn-bm\.camera360\.com\/api\/mix\/recovery url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/MIX.js 9 | 10 | [mitm] 11 | hostname = cdn-bm.camera360.com 12 | 13 | *************************** 14 | Surge4 or Loon: 15 | 16 | [Script] 17 | 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 18 | 19 | [MITM] 20 | hostname = cdn-bm.camera360.com 21 | 22 | **************************/ 23 | 24 | if ($response.body) { 25 | $done({ 26 | body: JSON.stringify({ 27 | "status": 200, 28 | "data": { 29 | "errorCode": 0, 30 | "orderList": [{ 31 | "quantity": "1", 32 | "purchase_date_ms": "1537703444000", 33 | "expires_date": "2028-06-06 06:06:06 Etc\/GMT", 34 | "expires_date_pst": "2028-06-06 06:06:06 America\/Los_Angeles", 35 | "is_in_intro_offer_period": "false", 36 | "transaction_id": "200000535242800", 37 | "is_trial_period": "true", 38 | "original_transaction_id": "200000535242800", 39 | "purchase_date": "2018-09-23 11:50:44 Etc\/GMT", 40 | "product_id": "com.vstudio.MIX.subscription.auto.year", 41 | "original_purchase_date_pst": "2018-09-23 04:50:44 America\/Los_Angeles", 42 | "original_purchase_date_ms": "1537703444000", 43 | "web_order_line_item_id": "200000140095730", 44 | "expires_date_ms": "1843855566000", 45 | "purchase_date_pst": "2018-09-23 04:50:44 America\/Los_Angeles", 46 | "original_purchase_date": "2018-09-23 11:50:44 Etc\/GMT" 47 | }, { 48 | "quantity": "1", 49 | "purchase_date_ms": "1538401707000", 50 | "expires_date": "2028-06-06 06:06:06 Etc\/GMT", 51 | "expires_date_pst": "2028-06-06 06:06:06 America\/Los_Angeles", 52 | "is_in_intro_offer_period": "false", 53 | "transaction_id": "200000539102583", 54 | "is_trial_period": "false", 55 | "original_transaction_id": "200000535242800", 56 | "purchase_date": "2018-10-01 13:48:27 Etc\/GMT", 57 | "product_id": "com.vstudio.MIX.subscription.auto.year", 58 | "original_purchase_date_pst": "2018-09-23 04:50:44 America\/Los_Angeles", 59 | "original_purchase_date_ms": "1537703444000", 60 | "web_order_line_item_id": "200000140095731", 61 | "expires_date_ms": "1843855566000", 62 | "purchase_date_pst": "2018-10-01 06:48:27 America\/Los_Angeles", 63 | "original_purchase_date": "2018-09-23 11:50:44 Etc\/GMT" 64 | }, { 65 | "product_id": "com.vstudio.MIX.Font.ruizigongfangcanlandaheijianonedotzero", 66 | "quantity": "1", 67 | "transaction_id": "200000577197848", 68 | "purchase_date_ms": "1546314438000", 69 | "original_purchase_date_pst": "2018-12-31 19:47:18 America\/Los_Angeles", 70 | "purchase_date_pst": "2018-12-31 19:47:18 America\/Los_Angeles", 71 | "original_purchase_date_ms": "1546314438000", 72 | "is_trial_period": "false", 73 | "original_purchase_date": "2019-01-01 03:47:18 Etc\/GMT", 74 | "original_transaction_id": "200000577197848", 75 | "purchase_date": "2019-01-01 03:47:18 Etc\/GMT" 76 | }], 77 | "autoBindingUserId": "043c8b571a3cd6c06e06db5f", 78 | "pendingRenewalInfo": [{ 79 | "product_id": "com.vstudio.MIX.subscription.auto.year", 80 | "original_transaction_id": "200000535242800", 81 | "auto_renew_product_id": "com.vstudio.MIX.subscription.auto.year", 82 | "auto_renew_status": "0" 83 | }] 84 | }, 85 | "message": "ok", 86 | "exetime": "1555653929373-1555653933781", 87 | "serverTime": 1555653933.7815001 88 | }) 89 | }); 90 | } else { 91 | $done({}) 92 | } 93 | -------------------------------------------------------------------------------- /Surge/JS/NiChi.js: -------------------------------------------------------------------------------- 1 | /* 2 | NiChi 解锁素材包 3 | 4 | *************************** 5 | QuantumultX: 6 | 7 | [rewrite_local] 8 | ^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 9 | 10 | [mitm] 11 | hostname = m*.bybutter.com 12 | 13 | *************************** 14 | Surge4 or Loon: 15 | 16 | [Script] 17 | http-response https?:\/\/m(p|ini-hk)\.bybutter\.com\/mood\/(official-templates|privileges) requires-body=1,max-size=524288,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/NiChi.js 18 | 19 | [MITM] 20 | hostname = m*.bybutter.com 21 | 22 | **************************/ 23 | 24 | var body = $response.body 25 | .replace(/preview/g, "free") 26 | .replace(/view/g, "unlimited") 27 | .replace(/true/g, "false"); 28 | $done({ body }); -------------------------------------------------------------------------------- /Surge/JS/PicsArt.js: -------------------------------------------------------------------------------- 1 | /* 2 | PicsArt 解锁高级功能 3 | 数据来自 @chxm1023 4 | 5 | *************************** 6 | QuantumultX: 7 | 8 | [rewrite_local] 9 | ^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 10 | 11 | [mitm] 12 | hostname = api.picsart.c*, api.meiease.c* 13 | 14 | *************************** 15 | Surge4 or Loon: 16 | 17 | [Script] 18 | 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 19 | 20 | [MITM] 21 | hostname = api.picsart.c*, api.meiease.c* 22 | 23 | **************************/ 24 | 25 | $done({ 26 | body: JSON.stringify({ 27 | "status": "success", 28 | "response": [ 29 | { 30 | "status": "SUBSCRIPTION_PURCHASED", 31 | "order_id": "490001314520000", 32 | "original_order_id": "490001314520000", 33 | "is_trial": true, 34 | "plan_meta": { 35 | "storage_limit_in_mb": 20480, 36 | "frequency": "yearly", 37 | "scope_id": "full", 38 | "id": "com.picsart.editor.subscription_yearly", 39 | "product_id": "subscription_yearly", 40 | "level": 2000, 41 | "auto_renew_product_id": "com.picsart.editor.subscription_yearly", 42 | "type": "renewable", 43 | "tier_id": "gold_old", 44 | "permissions": [ 45 | "premium_tools_standard", 46 | "premium_tools_ai" 47 | ], 48 | "description": "china" 49 | }, 50 | "limitation": { 51 | "max_count": 5, 52 | "limits_exceeded": false 53 | }, 54 | "reason": "ok", 55 | "subscription_id": "com.picsart.editor.subscription_yearly", 56 | "is_eligible_for_introductory": false, 57 | "purchase_date": 1687020148000, 58 | "expire_date": 4092599349000 59 | } 60 | ] 61 | }) 62 | }); -------------------------------------------------------------------------------- /Surge/JS/Polarr.js: -------------------------------------------------------------------------------- 1 | /* 2 | Polarr泼辣修图 解锁特权 (需登陆) 3 | 4 | *************************** 5 | QuantumultX: 6 | 7 | [rewrite_local] 8 | ^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 9 | 10 | [mitm] 11 | hostname = api.polaxiong.com 12 | 13 | *************************** 14 | Surge4 or Loon: 15 | 16 | [Script] 17 | 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 18 | 19 | [MITM] 20 | hostname = api.polaxiong.com 21 | 22 | **************************/ 23 | 24 | const statusCode = typeof $task !== "undefined" ? "HTTP/1.1 200 OK" : 200; 25 | const response = { status: statusCode, headers: $response.headers }; 26 | 27 | if ($response.body && $request.url.includes("v1/payments/profiles/@me/subscription")) { 28 | response.body = JSON.stringify({ 29 | "isSubscribed": true, 30 | "planId": "co.polarr.ppe.premium.studio.yearly", 31 | "subscriptionProduct": "yearly", 32 | "isTrial": false, 33 | "app": "PPE", 34 | "isUnlimited": true, 35 | "expiryDate": "2053-08-17T19:38:37.000Z", 36 | "planType": "yearly", 37 | "planTier": "studio", 38 | "startDate": "2023-08-17T19:38:37.000Z", 39 | "subscriptionTier": "studio", 40 | "paymentChannel": "AppleIapSubscription", 41 | "membershipExpiryDate": "2053-08-17T19:38:37.000Z" 42 | }); 43 | } 44 | 45 | if ($response.body && $request.url.includes("v1/payments/appleiap/receipts/confirmation")) { 46 | response.body = JSON.stringify({ 47 | "app": "PPE", 48 | "planType": "yearly", 49 | "planTier": "studio", 50 | "isUnlimited": true, 51 | "membershipExpiryDate": "2053-08-17T19:38:37.000Z" 52 | }); 53 | } 54 | 55 | $done(response) -------------------------------------------------------------------------------- /Surge/JS/Super.js: -------------------------------------------------------------------------------- 1 | /*皮皮虾去广告和水印 by Liquor030 2 | 如果只需要去广告功能请在[URL Rewrite]中添加 3 | 4 | # Remove Super's Ad (By Liquor030) 5 | app_name=super&([\S]*)aid=\d+ app_name=super_pro&$1aid=1412 header 6 | 7 | 可大幅改善使用体验,强烈建议添加并禁用该脚本,在需要的时候开启脚本去水印!! 8 | ===================================== 9 | Feed: /feed/stream 10 | 回复: /comment/cell_reply 11 | 评论: /cell/cell_comment 12 | Detail: /cell/detail 13 | 用户插眼: /ward/list 14 | 用户收藏: /user/favorite 15 | 用户评论: /user/cell_coment 16 | 用户feed: /user/cell_userfeed 17 | 用户发帖: /user/publish_list 18 | 19 | ************************** 20 | QuantumultX: 21 | 22 | [rewrite_local] 23 | ^https?://.*\.snssdk\.com/bds/(feed/stream|comment/cell_reply|cell/cell_comment|cell/detail|ward/list|user/favorite|user/cell_coment|user/cell_userfeed|user/publish_list) url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Super.js 24 | 25 | [mitm] 26 | hostname = *.snssdk.com 27 | 28 | ************************** 29 | Surge4 or Loon: 30 | 31 | [Script] 32 | http-response ^https?://.*\.snssdk\.com/bds/(feed/stream|comment/cell_reply|cell/cell_comment|cell/detail|ward/list|user/favorite|user/cell_coment|user/cell_userfeed|user/publish_list) requires-body=1,max-size=-1,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Super.js 33 | 34 | [MITM] 35 | hostname = *.snssdk.com 36 | 37 | **************************/ 38 | 39 | var body = $response.body.replace(/id\":([0-9]{15,})/g, 'id":"$1str"'); 40 | body = JSON.parse(body); 41 | if (body.data.data) { 42 | obj = body.data.data; 43 | } else if (body.data.replies) { 44 | obj = body.data.replies; 45 | } else if (body.data.cell_comments) { 46 | obj = body.data.cell_comments; 47 | } else { 48 | obj = null; 49 | } 50 | 51 | if (obj instanceof Array) { 52 | if (obj != null) { 53 | for (var i in obj) { 54 | if (obj[i].ad_info != null) { 55 | obj.splice(i, 1); 56 | } 57 | if (obj[i].item != null) { 58 | if (obj[i].item.video != null) { 59 | obj[i].item.video.video_download.url_list = obj[i].item.origin_video_download.url_list; 60 | } 61 | for (var j in obj[i].item.comments) { 62 | if (obj[i].item.comments[j].video != null) { 63 | obj[i].item.comments[j].video_download.url_list = obj[i].item.comments[j].video.url_list; 64 | } 65 | } 66 | } 67 | if (obj[i].comment_info != null) { 68 | if (obj[i].comment_info.video != null) { 69 | obj[i].comment_info.video_download.url_list = obj[i].comment_info.video.url_list; 70 | } 71 | } 72 | } 73 | } 74 | } else { 75 | if (obj.item != null) { 76 | if (obj.item.video != null) { 77 | obj.item.video.video_download.url_list = obj.item.origin_video_download.url_list; 78 | } 79 | for (var j in obj.item.comments) { 80 | if (obj.item.comments[j].video != null) { 81 | obj.item.comments[j].video_download.url_list = obj.item.comments[j].video.url_list; 82 | } 83 | } 84 | } 85 | if (obj.comment_info != null) { 86 | if (obj.comment_info.video != null) { 87 | obj.comment_info.video_download.url_list = obj.comment_info.video.url_list; 88 | } 89 | } 90 | } 91 | body = JSON.stringify(body); 92 | body = body.replace(/id\":\"([0-9]{15,})str\"/g, 'id":$1'); 93 | body = body.replace(/\"can_download\":false/g, '"can_download":true'); 94 | body = body.replace(/tplv-ppx-logo.image/g, '0x0.gif'); 95 | body = body.replace(/tplv-ppx-logo/g, '0x0'); 96 | $done({ 97 | body 98 | }); 99 | -------------------------------------------------------------------------------- /Surge/JS/VUE.js: -------------------------------------------------------------------------------- 1 | /* 2 | VUE Vlog 解锁高级功能 (需登录) 3 | 4 | *************************** 5 | QuantumultX: 6 | 7 | [rewrite_local] 8 | ^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 9 | 10 | [mitm] 11 | hostname = api.vuevideo.net 12 | 13 | *************************** 14 | Surge4 or Loon: 15 | 16 | [Script] 17 | http-response https:\/\/api\.vuevideo\.net\/api\/v1\/(users\/.+\/profile|subtitle\/prepare) requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/VUE.js 18 | 19 | [MITM] 20 | hostname = api.vuevideo.net 21 | 22 | **************************/ 23 | var body = $response.body 24 | .replace(/\"isPremium\":false/, "\"isPremium\":true") 25 | .replace(/\"valid\":false/, "\"valid\":true"); 26 | $done({ body }); -------------------------------------------------------------------------------- /Surge/JS/Wps.js: -------------------------------------------------------------------------------- 1 | /* 2 | WPS Office 解锁部分功能 3 | 4 | *************************** 5 | QuantumultX: 6 | 7 | [rewrite_local] 8 | ^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 9 | 10 | [mitm] 11 | hostname = *account.wps.cn, *account.wps.com 12 | 13 | *************************** 14 | Surge4 or Loon: 15 | 16 | [Script] 17 | 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 18 | 19 | [MITM] 20 | hostname = *account.wps.cn, *account.wps.com 21 | 22 | **************************/ 23 | 24 | var body = JSON.parse($response.body); 25 | var obj = { 26 | exp: 0, 27 | level: 3, 28 | privilege: [ 29 | { spid: "data_recover", times: 0, expire_time: 1846256142 }, 30 | { spid: "ocr", times: 0, expire_time: 1846256142 }, 31 | { spid: "pdf2doc", times: 0, expire_time: 1846256142 }, 32 | { spid: "pdf_merge", times: 0, expire_time: 1846256142 }, 33 | { spid: "pdf_sign", times: 0, expire_time: 1846256142 }, 34 | { spid: "pdf_split", times: 0, expire_time: 1846256142 } 35 | ], 36 | result: "ok", 37 | total_buy: 0, 38 | total_cost: -30, 39 | userid: body.userid, 40 | vip: { 41 | name: "超级会员", 42 | has_ad: 0, 43 | memberid: 40, 44 | expire_time: 1846256142, 45 | enabled: [ 46 | { memberid: 40, name: "超级会员", expire_time: 1846256142 }, 47 | { memberid: 20, name: "WPS会员", expire_time: 1846256142 }, 48 | { memberid: 12, name: "稻壳会员", expire_time: 1846256142 } 49 | ] 50 | }, 51 | wealth: 0, 52 | expire_time: 1846256142 53 | }; 54 | 55 | $done({ body: JSON.stringify(obj) }); -------------------------------------------------------------------------------- /Surge/JS/jibjab.js: -------------------------------------------------------------------------------- 1 | /* 2 | JibJab 解锁高级功能 3 | 4 | *************************** 5 | QuantumultX: 6 | 7 | [rewrite_local] 8 | https:\/\/origin-prod-phoenix\.jibjab\.com\/v1\/user url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/jibjab.js 9 | 10 | [mitm] 11 | hostname = origin-prod-phoenix.jibjab.com 12 | 13 | *************************** 14 | Surge4 or Loon: 15 | 16 | [Script] 17 | http-response https:\/\/origin-prod-phoenix\.jibjab\.com\/v1\/user requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/jibjab.js 18 | 19 | [MITM] 20 | hostname = origin-prod-phoenix.jibjab.com 21 | 22 | **************************/ 23 | 24 | let obj = JSON.parse($response.body); 25 | obj.data.attributes["is-paid"] = true; 26 | obj.data.attributes["email"] = "禁止牟利,TG频道@NobyDa"; 27 | $done({body: JSON.stringify(obj)}); 28 | -------------------------------------------------------------------------------- /Surge/JS/luqi.js: -------------------------------------------------------------------------------- 1 | /* 2 | 陆琪讲故事 解锁电台 3 | 4 | *************************** 5 | QuantumultX: 6 | 7 | [rewrite_local] 8 | ^https:\/\/www\.luqijianggushi\.com\/api\/v2\/user\/get url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/luqi.js 9 | 10 | [mitm] 11 | hostname = www.luqijianggushi.com 12 | 13 | *************************** 14 | Surge4 or Loon: 15 | 16 | [Script] 17 | http-response ^https:\/\/www\.luqijianggushi\.com\/api\/v2\/user\/get requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/luqi.js 18 | 19 | [MITM] 20 | hostname = www.luqijianggushi.com 21 | 22 | **************************/ 23 | 24 | let obj = JSON.parse($response.body); 25 | obj.data.is_vip = 1; 26 | obj.data.vip_endtime = 1630296877; 27 | $done({body: JSON.stringify(obj)}); 28 | -------------------------------------------------------------------------------- /Surge/JS/vivavideo.js: -------------------------------------------------------------------------------- 1 | /* 2 | 小影 解锁高级功能 3 | 4 | *************************** 5 | QuantumultX: 6 | 7 | [rewrite_local] 8 | ^https:\/\/api-use\.intsvs\.com\/api\/rest\/u\/vipVerifyReceipt url script-response-body https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/vivavideo.js 9 | 10 | [mitm] 11 | hostname = api-use.intsvs.com 12 | 13 | *************************** 14 | Surge4 or Loon: 15 | 16 | [Script] 17 | 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 18 | 19 | [MITM] 20 | hostname = api-use.intsvs.com 21 | 22 | **************************/ 23 | 24 | var obj = JSON.parse($response.body); 25 | obj = { 26 | "autoRenewProductId": "premium_platinum_yearly", 27 | "iosDeviceProductVo": { 28 | "premiumVipWeekly": 3, 29 | "premiumGoldMonthly": 3, 30 | "premiumPlatinumMonthly": 3, 31 | "premiumGoldYearly": 3, 32 | "premiumPlatinumYearly": 2, 33 | "premiumPlatinumHalfYearly": 3, 34 | "premiumVipYearly": 3 35 | }, 36 | "isTrialPeriod": true, 37 | "endTime": 4081109070000, 38 | "platform": 2, 39 | "vipType": "premium_platinum_yearly", 40 | "duidDgest": "DIIe86X35", 41 | "autoRenewStatus": 1, 42 | "startTime": 1556241871000, 43 | "systemDate": 1556965441014 44 | }; 45 | 46 | $done({body: JSON.stringify(obj)}); -------------------------------------------------------------------------------- /Surge/Module/BahamutAnimeAds.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=动画疯 2 | #!desc=屏蔽播放广告 (黑屏25秒自动播放) 3 | #!system=ios 4 | 5 | [Script] 6 | 动画疯(屏蔽广告) = 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 7 | 8 | [MITM] 9 | hostname = %APPEND% api.gamer.com.tw -------------------------------------------------------------------------------- /Surge/Module/BahamutDailyBonus.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=🐻 巴哈姆特 [签到] 2 | #!desc=每日定时签到,包含主站签到、公会签到、动画疯答题等;模块参数可调整签到时间。\n使用前需要进入BoxJs填写账号密码,BoxJs订阅链接可查看脚本注释。 3 | #!arguments=定时签到:20 8 * * * 4 | #!arguments-desc=定时签到:Cron表达式,默认每天早上 08:20 执行。(如需动画疯答题,不建议在凌晨0:00-0:30执行) 5 | #!category=🐻 NobyDa 6 | 7 | [Script] 8 | 巴哈姆特[签到] = type=cron,cronexp="{{{定时签到}}}",wake-system=1,script-update-interval=0,timeout=300,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Bahamut/BahamutDailyBonus.js -------------------------------------------------------------------------------- /Surge/Module/BiliComicsDailyBonus.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=🐻 哔哩哔哩漫画 [签到] 2 | #!desc=每日定时签到,模块参数可调整签到时间。\n打开哔哩哔哩漫画APP点击"我的"即可获取cookie. 3 | #!arguments=定时签到:0 9 * * *,禁用脚本:哔哩漫画[Cookie],禁用MITM:hostname 4 | #!arguments-desc=定时签到:Cron表达式,默认每天早上 09:00 执行。\n\n禁用脚本:禁用获取Cookie脚本,输入 # 表示禁用。\n\n禁用MITM:禁用MITM主机名,输入 # 表示禁用。 5 | #!category=🐻 NobyDa 6 | 7 | [Script] 8 | 哔哩漫画[签到] = 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 9 | 10 | {{{禁用脚本}}} = 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 11 | 12 | [MITM] 13 | {{{禁用MITM}}} = %APPEND% app.bilibili.com -------------------------------------------------------------------------------- /Surge/Module/BiliComicsExchangePoints.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=🐻 哔哩哔哩漫画 [积分抢购] 2 | #!desc=定时抢购积分商城物品,模块参数可调整抢购设置,该模块需使用"哔哩哔哩漫画签到模块"获取Cookie。 3 | #!arguments=定时抢购:0-59 0 0 * * 0-1,商品名称:【超特惠】限量-0点秒杀,抢购数量:0,抢购次数:100 4 | #!arguments-desc=定时抢购:Cron表达式,默认每周日、每周一的凌晨 0:00:00 - 0:01:59 之间每秒执行一次。\n\n商品名称:默认抢购商品名"【超特惠】限量-0点秒杀"\n\n抢购数量:默认为用户积分可抢购的最大值(以0表示)\n\n抢购次数:抢购失败时重试次数,默认100次 5 | #!category=🐻 NobyDa 6 | 7 | [Script] 8 | 哔哩漫画[积分抢购] = 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={{{抢购次数}}} -------------------------------------------------------------------------------- /Surge/Module/CtripDailyBonus.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=🐻 携程旅行 [签到] 2 | #!desc=每日定时签到,支持多账号。\n登陆"携程旅行"微信小程序或"携程网页版"(https://m.ctrip.com/)可获取账号授权,填写模块参数可禁用脚本。 3 | #!arguments=定时签到:30 8 * * *,禁用脚本:携程旅行[授权],禁用MITM:hostname 4 | #!arguments-desc=定时签到:Cron表达式,默认每日 8:30 执行。\n\n禁用脚本:禁用获取授权脚本,输入 # 表示禁用。\n\n禁用MITM:禁用MITM主机名,输入 # 表示禁用。 5 | #!category=🐻 NobyDa 6 | 7 | [Script] 8 | 携程旅行[签到] = 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 9 | 10 | {{{禁用脚本}}} = 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 11 | 12 | [MITM] 13 | {{{禁用MITM}}} = %APPEND% m.ctrip.com -------------------------------------------------------------------------------- /Surge/Module/DisneyRating.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=Disney+评分 2 | #!desc=Disney+剧集页显示IMDb / 烂番茄 / 豆瓣评分 3 | #!arguments=脚本引擎:jsc,调试模式:0 4 | #!arguments-desc=脚本引擎:jsc/webview/auto,默认jsc。\n\n调试模式:1/0,开启/关闭。 5 | #!category=🐻 NobyDa 6 | 7 | [Script] 8 | 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={{{脚本引擎}}} 9 | 10 | [MITM] 11 | hostname = %APPEND% disney.api.edge.bamgrid.com -------------------------------------------------------------------------------- /Surge/Module/GetCookie.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=🐻 签到脚本Cookie获取 2 | #!desc=该模块适用于NobyDa定时签到脚本的Cookie获取. 集成: 爱奇艺, 哔哩哔哩漫画, 百度贴吧, 快看漫画, 携程旅行。 3 | #!system=ios 4 | 5 | [Script] 6 | 爱奇艺Cookie = type=http-request,pattern=^https:\/\/passport\.iqiyi\.com\/apis\/user\/,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js 7 | 8 | 哔哩漫画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 9 | 10 | 百度贴吧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 11 | 12 | 快看漫画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 13 | 14 | 携程旅行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 15 | 16 | [MITM] 17 | hostname = %APPEND% passport.iqiyi.com, app.bilibili.com, c.tieba.baidu.com, tiebac.baidu.com, api.kkmh.com, m.ctrip.com -------------------------------------------------------------------------------- /Surge/Module/GoogleCAPTCHA.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=Google人机验证 2 | #!desc=Google搜索内容时并发使用多个策略/策略组,以避免可能出现的人机验证。注意:需要在模块参数填写策略/策略组名的正则表达式。 3 | #!arguments=策略正则,脚本引擎:auto 4 | #!arguments-desc=策略正则:策略/策略组名的正则表达式,例如:\n^(🇸🇬|🇭🇰)\s.*\d+$ 如需同时使用所有策略/策略组可使用 .+ 表示。\n\n脚本引擎:jsc/webview/auto,默认auto。 5 | #!category=🐻 NobyDa 6 | 7 | [Script] 8 | 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={{{策略正则}}} 9 | 10 | [MITM] 11 | hostname = %APPEND% www.google.com* -------------------------------------------------------------------------------- /Surge/Module/HuiJuDongManAds.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=荟聚动漫 2 | #!desc=去除大多数弹屏以及底栏广告, 由于有广告缓存, 因此可能需要卸载App重装. @NobyDa 3 | 4 | # Update at 2022/07/11 5 | 6 | [Rule] 7 | #底栏 8 | DOMAIN,googleads.g.doubleclick.net,REJECT-TINYGIF 9 | DOMAIN,www.19831110.com,REJECT-TINYGIF 10 | #HTTP 11 | AND,((USER-AGENT,%E8%8D%9F%E8%81%9A%E5%8A%A8%E6%BC%AB*), (URL-REGEX,\/ad)),REJECT-TINYGIF 12 | #开屏 13 | DOMAIN-SUFFIX,admobile.top,REJECT-TINYGIF 14 | 15 | [URL Rewrite] 16 | #弹屏, 搜索, 以及底栏白屏广告 17 | ^https?:\/\/os8\.pw\/(adConfigs|appConfiguration\/getAd) - reject 18 | ^http:\/\/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/goad\/ad\/ - reject 19 | ^https?:\/\/api-access\.pangolin-sdk-toutiao\.com\/api\/ad\/ - reject 20 | ^https?:\/\/sf\d-ttcdn-tos\.pstatp\.com\/obj\/ad - reject 21 | ^https?:\/\/www\.51devapp\.com\/adconfigs - reject 22 | ^https?:\/\/.+?\.snssdk\.com\/ad\/ - reject 23 | 24 | [MITM] 25 | 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 -------------------------------------------------------------------------------- /Surge/Module/IPA_install.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=IPA应用辅助安装器 2 | #!desc=该模块可在iOS端辅助安装商店版或已签名IPA(需使用快捷指令 + Shu/Jsbox/pythonista), 查看脚本注释以了解具体方法; 安装演示可查看TG频道 @NobyDa 3 | 4 | 5 | [Script] 6 | 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 7 | 8 | [MITM] 9 | hostname = %APPEND% nobyda.app -------------------------------------------------------------------------------- /Surge/Module/KuaiKanComicsDailyBonus.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=🐻 快看漫画 [签到] 2 | #!desc=每日定时签到,模块参数可调整签到时间。\n打开快看漫画APP点击"我的"即可获取cookie. 3 | #!arguments=定时签到:10 9 * * *,禁用脚本:快看漫画[Cookie],禁用MITM:hostname 4 | #!arguments-desc=定时签到:Cron表达式,默认每天早上 09:10 执行。\n\n禁用脚本:禁用获取Cookie脚本,输入 # 表示禁用。\n\n禁用MITM:禁用MITM主机名,输入 # 表示禁用。 5 | #!category=🐻 NobyDa 6 | 7 | [Script] 8 | 快看漫画[签到] = 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 9 | 10 | {{{禁用脚本}}} = 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 11 | 12 | [MITM] 13 | {{{禁用MITM}}} = %APPEND% api.kkmh.com -------------------------------------------------------------------------------- /Surge/Module/NewBing.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=New Bing for other browsers 2 | #!desc=Unlock browser restrictions for new bing AI search. 3 | 4 | [Header Rewrite] 5 | ^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" 6 | 7 | [MITM] 8 | hostname = %APPEND% www.bing.com -------------------------------------------------------------------------------- /Surge/Module/TestFlightAccount.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=TestFlight账户管理 2 | #!desc=自动存储/合并多个TestFlight账户列表, 并可导出/分享TestFlight APP. 3 | #!arguments=请求超时:30,启用缓存:1,使用iOS列表:0,脚本引擎:jsc,调试模式:0 4 | #!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,开启/关闭。用于调试脚本。 5 | #!category=🐻 NobyDa 6 | 7 | [General] 8 | skip-proxy = %APPEND% iosapps.itunes.apple.com 9 | 10 | [Script] 11 | 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={{{脚本引擎}}} 12 | 13 | [MITM] 14 | hostname = %APPEND% testflight.apple.com -------------------------------------------------------------------------------- /Surge/Module/TestFlightDownload.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=TestFlight区域限制解除 2 | #!desc=该模块适用于更新TestFlight App时, 提示"APP不可用"问题. 3 | 4 | [General] 5 | skip-proxy = %APPEND% iosapps.itunes.apple.com 6 | 7 | [Script] 8 | TF下载修正 = type=http-request,pattern=^https?:\/\/testflight\.apple\.com\/v\d\/accounts\/.+?\/install$,requires-body=1,script-update-interval=-1,max-size=0,script-path=https://gist.githubusercontent.com/NobyDa/9be418b93afc5e9c8a8f4d28ae403cf2/raw/TF_Download.js 9 | 10 | [MITM] 11 | hostname = %APPEND% testflight.apple.com -------------------------------------------------------------------------------- /Surge/Module/TieBaDailyBonus.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=🐻 百度贴吧 [签到] 2 | #!desc=每日定时签到,模块参数可调整签到时间。\n打开百度贴吧APP点击"我的"即可获取cookie. 3 | #!arguments=定时签到:40 8 * * *,禁用脚本:百度贴吧[Cookie],禁用MITM:hostname 4 | #!arguments-desc=定时签到:Cron表达式,默认每天早上 08:40 执行。\n\n禁用脚本:禁用获取Cookie脚本,输入 # 表示禁用。\n\n禁用MITM:禁用MITM主机名,输入 # 表示禁用。 5 | #!category=🐻 NobyDa 6 | 7 | [Script] 8 | 百度贴吧[签到] = 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 9 | 10 | {{{禁用脚本}}} = 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 11 | 12 | [MITM] 13 | {{{禁用MITM}}} = %APPEND% c.tieba.baidu.com, tiebac.baidu.com -------------------------------------------------------------------------------- /Surge/Module/iQIYIDailyBonus.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=🐻 爱奇艺 [会员签到] 2 | #!desc=每日定时签到,模块参数可调整签到时间。\n登陆爱奇艺网页版 https://m.ctrip.com/ 使用密码登录可获取签到Cookie. 3 | #!arguments=定时签到:10 9 * * *,禁用脚本:爱奇艺[Cookie],禁用MITM:hostname 4 | #!arguments-desc=定时签到:Cron表达式,默认每天早上 09:10 执行。\n\n禁用脚本:禁用获取Cookie脚本,输入 # 表示禁用。\n\n禁用MITM:禁用MITM主机名,输入 # 表示禁用。 5 | #!category=🐻 NobyDa 6 | 7 | [Script] 8 | 爱奇艺[会员签到] = 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 9 | 10 | {{{禁用脚本}}} = type=http-request,pattern=^https:\/\/passport\.iqiyi\.com\/apis\/user\/,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js 11 | 12 | [MITM] 13 | {{{禁用MITM}}} = %APPEND% passport.iqiyi.com -------------------------------------------------------------------------------- /Surge/WeChat.list: -------------------------------------------------------------------------------- 1 | # 该规则集包含绝大部分微信/WeChat网络请求 (IPv4/IPv6) 2 | # 请注意,该规则集除 Surge 之外不应该使用 (由于双栈问题且考虑到规则数量,部分子规则写法仅与Surge兼容) 3 | 4 | DOMAIN-KEYWORD,101.226.211. 5 | DOMAIN-KEYWORD,101.226.222. 6 | DOMAIN-KEYWORD,101.226.226. 7 | DOMAIN-KEYWORD,101.32.104. 8 | DOMAIN-KEYWORD,101.32.118. 9 | DOMAIN-KEYWORD,101.32.133. 10 | DOMAIN-KEYWORD,101.33.110. 11 | DOMAIN-KEYWORD,101.89.15. 12 | DOMAIN-KEYWORD,101.89.38. 13 | DOMAIN-KEYWORD,101.91.37. 14 | DOMAIN-KEYWORD,101.91.69. 15 | DOMAIN-KEYWORD,101.91.71. 16 | DOMAIN-KEYWORD,106.225.231. 17 | DOMAIN-KEYWORD,109.244.169. 18 | DOMAIN-KEYWORD,110.52.193. 19 | DOMAIN-KEYWORD,110.53.246. 20 | DOMAIN-KEYWORD,111.30.164. 21 | DOMAIN-KEYWORD,111.45.68. 22 | DOMAIN-KEYWORD,111.45.69. 23 | DOMAIN-KEYWORD,111.45.70. 24 | DOMAIN-KEYWORD,112.53.25. 25 | DOMAIN-KEYWORD,112.53.36. 26 | DOMAIN-KEYWORD,112.60.0. 27 | DOMAIN-KEYWORD,112.60.13. 28 | DOMAIN-KEYWORD,112.60.14. 29 | DOMAIN-KEYWORD,112.60.8. 30 | DOMAIN-KEYWORD,112.65.193. 31 | DOMAIN-KEYWORD,112.90.43. 32 | DOMAIN-KEYWORD,113.105.154. 33 | DOMAIN-KEYWORD,113.105.165. 34 | DOMAIN-KEYWORD,113.105.166. 35 | DOMAIN-KEYWORD,113.96.154. 36 | DOMAIN-KEYWORD,113.96.156. 37 | DOMAIN-KEYWORD,113.96.16. 38 | DOMAIN-KEYWORD,113.96.18. 39 | DOMAIN-KEYWORD,113.96.202. 40 | DOMAIN-KEYWORD,113.96.208. 41 | DOMAIN-KEYWORD,113.96.209. 42 | DOMAIN-KEYWORD,113.96.210. 43 | DOMAIN-KEYWORD,113.96.232. 44 | DOMAIN-KEYWORD,113.96.233. 45 | DOMAIN-KEYWORD,113.96.237. 46 | DOMAIN-KEYWORD,113.96.83. 47 | DOMAIN-KEYWORD,113.96.98. 48 | DOMAIN-KEYWORD,115.231.229. 49 | DOMAIN-KEYWORD,115.238.197. 50 | DOMAIN-KEYWORD,116.128.133. 51 | DOMAIN-KEYWORD,116.128.163. 52 | DOMAIN-KEYWORD,116.253.60. 53 | DOMAIN-KEYWORD,116.253.61. 54 | DOMAIN-KEYWORD,117.135.133. 55 | DOMAIN-KEYWORD,117.184.242. 56 | DOMAIN-KEYWORD,117.187.243. 57 | DOMAIN-KEYWORD,117.41.224. 58 | DOMAIN-KEYWORD,119.147.190. 59 | DOMAIN-KEYWORD,119.147.227. 60 | DOMAIN-KEYWORD,119.147.83. 61 | DOMAIN-KEYWORD,119.188.155. 62 | DOMAIN-KEYWORD,119.39.81. 63 | DOMAIN-KEYWORD,120.221.179. 64 | DOMAIN-KEYWORD,120.232.27. 65 | DOMAIN-KEYWORD,120.232.33. 66 | DOMAIN-KEYWORD,120.232.65. 67 | DOMAIN-KEYWORD,120.232.68. 68 | DOMAIN-KEYWORD,120.233.36. 69 | DOMAIN-KEYWORD,120.237.199. 70 | DOMAIN-KEYWORD,120.241.149. 71 | DOMAIN-KEYWORD,120.241.150. 72 | DOMAIN-KEYWORD,120.241.17. 73 | DOMAIN-KEYWORD,120.241.186. 74 | DOMAIN-KEYWORD,120.241.189. 75 | DOMAIN-KEYWORD,120.241.190. 76 | DOMAIN-KEYWORD,120.241.21. 77 | DOMAIN-KEYWORD,120.241.25. 78 | DOMAIN-KEYWORD,120.241.92. 79 | DOMAIN-KEYWORD,121.12.115. 80 | DOMAIN-KEYWORD,121.14.142. 81 | DOMAIN-KEYWORD,121.14.98. 82 | DOMAIN-KEYWORD,121.51.130. 83 | DOMAIN-KEYWORD,122.225.36. 84 | DOMAIN-KEYWORD,122.246.25. 85 | DOMAIN-KEYWORD,123.150.208. 86 | DOMAIN-KEYWORD,123.150.76. 87 | DOMAIN-KEYWORD,123.151.190. 88 | DOMAIN-KEYWORD,123.161.61. 89 | DOMAIN-KEYWORD,123.184.36. 90 | DOMAIN-KEYWORD,124.232.162. 91 | DOMAIN-KEYWORD,129.226.107. 92 | DOMAIN-KEYWORD,129.226.3. 93 | DOMAIN-KEYWORD,14.17.41. 94 | DOMAIN-KEYWORD,14.17.73. 95 | DOMAIN-KEYWORD,14.18.175. 96 | DOMAIN-KEYWORD,14.18.178. 97 | DOMAIN-KEYWORD,14.18.180. 98 | DOMAIN-KEYWORD,14.18.200. 99 | DOMAIN-KEYWORD,14.18.245. 100 | DOMAIN-KEYWORD,14.215.138. 101 | DOMAIN-KEYWORD,14.215.158. 102 | DOMAIN-KEYWORD,14.215.166. 103 | DOMAIN-KEYWORD,14.215.167. 104 | DOMAIN-KEYWORD,14.215.85. 105 | DOMAIN-KEYWORD,14.22.0. 106 | DOMAIN-KEYWORD,14.22.33. 107 | DOMAIN-KEYWORD,14.22.4. 108 | DOMAIN-KEYWORD,14.22.5. 109 | DOMAIN-KEYWORD,14.29.100. 110 | DOMAIN-KEYWORD,14.29.101. 111 | DOMAIN-KEYWORD,150.109.90. 112 | DOMAIN-KEYWORD,157.148.33. 113 | DOMAIN-KEYWORD,157.148.42. 114 | DOMAIN-KEYWORD,157.148.45. 115 | DOMAIN-KEYWORD,157.148.51. 116 | DOMAIN-KEYWORD,157.148.55. 117 | DOMAIN-KEYWORD,157.255.135. 118 | DOMAIN-KEYWORD,157.255.173. 119 | DOMAIN-KEYWORD,157.255.174. 120 | DOMAIN-KEYWORD,157.255.192. 121 | DOMAIN-KEYWORD,157.255.243. 122 | DOMAIN-KEYWORD,157.255.244. 123 | DOMAIN-KEYWORD,157.255.245. 124 | DOMAIN-KEYWORD,163.177.81. 125 | DOMAIN-KEYWORD,163.177.89. 126 | DOMAIN-KEYWORD,163.177.90. 127 | DOMAIN-KEYWORD,175.6.13. 128 | DOMAIN-KEYWORD,180.111.199. 129 | DOMAIN-KEYWORD,180.163.25. 130 | DOMAIN-KEYWORD,180.96.0. 131 | DOMAIN-KEYWORD,180.96.2. 132 | DOMAIN-KEYWORD,180.97.8. 133 | DOMAIN-KEYWORD,183.131.56. 134 | DOMAIN-KEYWORD,183.131.57. 135 | DOMAIN-KEYWORD,183.192.169. 136 | DOMAIN-KEYWORD,183.194.238. 137 | DOMAIN-KEYWORD,183.232.175. 138 | DOMAIN-KEYWORD,183.232.246. 139 | DOMAIN-KEYWORD,183.232.94. 140 | DOMAIN-KEYWORD,183.232.95. 141 | DOMAIN-KEYWORD,183.232.96. 142 | DOMAIN-KEYWORD,183.240.115. 143 | DOMAIN-KEYWORD,183.240.118. 144 | DOMAIN-KEYWORD,183.240.48. 145 | DOMAIN-KEYWORD,183.240.56. 146 | DOMAIN-KEYWORD,183.240.80. 147 | DOMAIN-KEYWORD,183.240.81. 148 | DOMAIN-KEYWORD,183.3.226. 149 | DOMAIN-KEYWORD,183.3.233. 150 | DOMAIN-KEYWORD,183.3.234. 151 | DOMAIN-KEYWORD,183.3.235. 152 | DOMAIN-KEYWORD,183.47.101. 153 | DOMAIN-KEYWORD,183.47.115. 154 | DOMAIN-KEYWORD,183.47.117. 155 | DOMAIN-KEYWORD,183.47.97. 156 | DOMAIN-KEYWORD,183.60.131. 157 | DOMAIN-KEYWORD,183.60.155. 158 | DOMAIN-KEYWORD,183.61.13. 159 | DOMAIN-KEYWORD,203.205.232. 160 | DOMAIN-KEYWORD,203.205.235. 161 | DOMAIN-KEYWORD,203.205.253. 162 | DOMAIN-KEYWORD,203.205.254. 163 | DOMAIN-KEYWORD,211.95.137. 164 | DOMAIN-KEYWORD,211.95.138. 165 | DOMAIN-KEYWORD,218.68.88. 166 | DOMAIN-KEYWORD,218.68.90. 167 | DOMAIN-KEYWORD,219.135.59. 168 | DOMAIN-KEYWORD,220.194.91. 169 | DOMAIN-KEYWORD,220.194.93. 170 | DOMAIN-KEYWORD,220.249.243. 171 | DOMAIN-KEYWORD,221.181.99. 172 | DOMAIN-KEYWORD,223.166.152. 173 | DOMAIN-KEYWORD,27.19.222. 174 | DOMAIN-KEYWORD,36.136.108. 175 | DOMAIN-KEYWORD,36.152.4. 176 | DOMAIN-KEYWORD,36.155.202. 177 | DOMAIN-KEYWORD,36.158.189. 178 | DOMAIN-KEYWORD,36.158.242. 179 | DOMAIN-KEYWORD,36.250.230. 180 | DOMAIN-KEYWORD,42.187.131. 181 | DOMAIN-KEYWORD,42.187.182. 182 | DOMAIN-KEYWORD,42.187.184. 183 | DOMAIN-KEYWORD,42.202.141. 184 | DOMAIN-KEYWORD,58.144.193. 185 | DOMAIN-KEYWORD,58.144.248. 186 | DOMAIN-KEYWORD,58.250.136. 187 | DOMAIN-KEYWORD,58.251.100. 188 | DOMAIN-KEYWORD,58.251.111. 189 | DOMAIN-KEYWORD,58.251.117. 190 | DOMAIN-KEYWORD,58.251.80. 191 | DOMAIN-KEYWORD,58.251.81. 192 | DOMAIN-KEYWORD,58.251.82. 193 | DOMAIN-KEYWORD,58.49.138. 194 | DOMAIN-KEYWORD,59.36.89. 195 | DOMAIN-KEYWORD,59.36.97. 196 | DOMAIN-KEYWORD,59.37.96. 197 | DOMAIN-KEYWORD,59.37.97. 198 | DOMAIN-KEYWORD,60.13.97. 199 | DOMAIN-KEYWORD,61.151.165. 200 | DOMAIN-KEYWORD,61.151.167. 201 | DOMAIN-KEYWORD,61.151.168. 202 | DOMAIN-KEYWORD,61.151.183. 203 | DOMAIN-KEYWORD,61.151.206. 204 | DOMAIN-KEYWORD,61.151.207. 205 | DOMAIN-KEYWORD,61.190.114. 206 | DOMAIN-KEYWORD,61.191.60. 207 | DOMAIN-KEYWORD,61.241.31. 208 | DOMAIN-KEYWORD,61.241.44. 209 | DOMAIN-KEYWORD,61.241.47. 210 | DOMAIN-KEYWORD,61.241.49. 211 | DOMAIN-KEYWORD,43.156.86. 212 | DOMAIN-KEYWORD,43.156.222. 213 | 214 | # WeChat Pay SDK 215 | DOMAIN-KEYWORD,101.226.129. 216 | DOMAIN-KEYWORD,101.227.162. 217 | DOMAIN-KEYWORD,101.89.50. 218 | DOMAIN-KEYWORD,101.91.22. 219 | DOMAIN-KEYWORD,101.91.34. 220 | DOMAIN-KEYWORD,101.91.5. 221 | DOMAIN-KEYWORD,111.0.26. 222 | DOMAIN-KEYWORD,116.128.171. 223 | DOMAIN-KEYWORD,120.204.0. 224 | DOMAIN-KEYWORD,120.204.10. 225 | DOMAIN-KEYWORD,121.51.124. 226 | DOMAIN-KEYWORD,140.207.119. 227 | DOMAIN-KEYWORD,175.27.0. 228 | DOMAIN-KEYWORD,180.163.15. 229 | DOMAIN-KEYWORD,180.163.26. 230 | DOMAIN-KEYWORD,182.254.78. 231 | DOMAIN-KEYWORD,182.254.92. 232 | DOMAIN-KEYWORD,183.195.236. 233 | DOMAIN-KEYWORD,183.3.224. 234 | DOMAIN-KEYWORD,203.205.234. 235 | DOMAIN-KEYWORD,220.196.144. 236 | DOMAIN-KEYWORD,221.181.97. 237 | DOMAIN-KEYWORD,58.247.204. 238 | DOMAIN-KEYWORD,58.247.205. 239 | IP-CIDR6,2402:4E00:1900:1700:0:9554:1AD0:140A/128,no-resolve 240 | IP-CIDR6,2402:4e00:1020:10fb:0:9466::/112,no-resolve 241 | IP-CIDR6,2402:4e00:1430:2264:0:9467::/96,no-resolve 242 | IP-CIDR6,2402:4e00:8010::/112,no-resolve 243 | IP-CIDR6,2402:4e00:8020:101::2:0/112,no-resolve 244 | IP-CIDR6,2408:80f1:31:50::/112,no-resolve 245 | IP-CIDR6,2409:8c1e:8fd0:50::/112,no-resolve 246 | IP-CIDR6,240e:e1:a900:50::/112,no-resolve 247 | 248 | # Unknown UDP 249 | IP-CIDR,111.30.160.0/20,no-resolve 250 | IP-CIDR,112.53.11.0/24,no-resolve 251 | IP-CIDR,112.53.20.0/24,no-resolve 252 | 253 | # China Unicom IPv6 (WeChat) 254 | IP-CIDR6,2408:80F1:21::/48,no-resolve 255 | IP-CIDR6,2408:80F1:31::/48,no-resolve 256 | IP-CIDR6,2408:8711:10:10::/112,no-resolve 257 | IP-CIDR6,2408:8752:0:10::/60,no-resolve 258 | IP-CIDR6,2408:8752:0:2:30::/112,no-resolve 259 | IP-CIDR6,2408:8752:0:30::/64,no-resolve 260 | IP-CIDR6,2408:8752:0:F::/64,no-resolve 261 | IP-CIDR6,2408:8756:F50::/48,no-resolve 262 | IP-CIDR6,2408:8756:2CF2:19::/112,no-resolve 263 | IP-CIDR6,2408:8756:2CFF:10::/60,no-resolve 264 | IP-CIDR6,2408:8756:3AF0:10::/112,no-resolve 265 | IP-CIDR6,2408:8756:3AF0:2013::/112,no-resolve 266 | IP-CIDR6,2408:8763:0:200::/60,no-resolve 267 | 268 | # China Mobile IPv6 (WeChat) 269 | IP-CIDR6,2409:8702:4860:10::/112,no-resolve 270 | IP-CIDR6,2409:8754:F111::/60,no-resolve 271 | IP-CIDR6,2409:8C02:24C:45::/72,no-resolve 272 | IP-CIDR6,2409:8C1E:75B0:1010::/112,no-resolve 273 | IP-CIDR6,2409:8C1E:75B0:13::/112,no-resolve 274 | IP-CIDR6,2409:8C1E:8F60::/60,no-resolve 275 | IP-CIDR6,2409:8C1E:8F60:BB::/72,no-resolve 276 | IP-CIDR6,2409:8C1E:8FD0::/56,no-resolve 277 | IP-CIDR6,2409:8C20:818:110::/60,no-resolve 278 | IP-CIDR6,2409:8C34:2220:20::/60,no-resolve 279 | IP-CIDR6,2409:8C34:22A0:10::/60,no-resolve 280 | IP-CIDR6,2409:8C34:D00:200::/60,no-resolve 281 | IP-CIDR6,2409:8C38:80:150::/72,no-resolve 282 | IP-CIDR6,2409:8C50:2400::/60,no-resolve 283 | IP-CIDR6,2409:8C50:A00:2122::/72,no-resolve 284 | IP-CIDR6,2409:8C54:1003:1019::/112,no-resolve 285 | IP-CIDR6,2409:8C54:1003:10::/112,no-resolve 286 | IP-CIDR6,2409:8C54:1050:10::/112,no-resolve 287 | IP-CIDR6,2409:8C54:1801:10::/60,no-resolve 288 | IP-CIDR6,2409:8C54:1821:70::/60,no-resolve 289 | IP-CIDR6,2409:8C54:2000:400::/60,no-resolve 290 | IP-CIDR6,2409:8C54:2800:9110::/60,no-resolve 291 | IP-CIDR6,2409:8C54:5100::/56,no-resolve 292 | IP-CIDR6,2409:8C54:810:208:2D::/112,no-resolve 293 | IP-CIDR6,2409:8C54:871::/60,no-resolve 294 | IP-CIDR6,2409:8C5C:110:63::/72,no-resolve 295 | 296 | # China Telecom IPv6 (WeChat) 297 | IP-CIDR6,240E:928:1400:10::/112,no-resolve 298 | IP-CIDR6,240E:965:802:620::/60,no-resolve 299 | IP-CIDR6,240E:93C:8:10::/60,no-resolve 300 | IP-CIDR6,240E:95C:2003:20::/60,no-resolve 301 | IP-CIDR6,240E:95C:3003:14::/60,no-resolve 302 | IP-CIDR6,240E:96C:6400:700::/60,no-resolve 303 | IP-CIDR6,240E:97C:18:601::/64,no-resolve 304 | IP-CIDR6,240E:97C:18:910::/60,no-resolve 305 | IP-CIDR6,240E:97C:2F::/60,no-resolve 306 | IP-CIDR6,240E:97D:4:1E00::/60,no-resolve 307 | IP-CIDR6,240E:97D:2010:100::/60,no-resolve 308 | IP-CIDR6,240E:97F:3000:1102::/64,no-resolve 309 | IP-CIDR6,240E:CF:8800::/56,no-resolve 310 | IP-CIDR6,240E:E1:A800::/46,no-resolve 311 | IP-CIDR6,240E:E1:A900::/48,no-resolve 312 | IP-CIDR6,240E:E1:AA00::/48,no-resolve 313 | IP-CIDR6,240E:E9:6003::/48,no-resolve 314 | IP-CIDR6,240E:F7:4F00:1F10::/60,no-resolve 315 | IP-CIDR6,240E:F7:A070:100::/60,no-resolve 316 | IP-CIDR6,240E:F7:A070:403::/60,no-resolve 317 | IP-CIDR6,240E:FF:9018:100::/60,no-resolve 318 | IP-CIDR6,240E:FF:F100::/44,no-resolve 319 | 320 | DOMAIN,apd-pcdnwxlogin.teg.tencent-cloud.net 321 | DOMAIN,btrace.qq.com 322 | DOMAIN,dldir1.qq.com 323 | DOMAIN,slife.xy-asia.com 324 | DOMAIN,soup.v.qq.com 325 | DOMAIN,vweixinf.tc.qq.com 326 | DOMAIN,weixin110.qq.com 327 | DOMAIN,wup.imtt.qq.com 328 | DOMAIN,wx.tenpay.com 329 | DOMAIN,wxapp.tc.qq.com 330 | DOMAIN-SUFFIX,iot-tencent.com 331 | DOMAIN-SUFFIX,map.qq.com 332 | DOMAIN-SUFFIX,qlogo.cn 333 | DOMAIN-SUFFIX,qpic.cn 334 | DOMAIN-SUFFIX,servicewechat.com 335 | DOMAIN-SUFFIX,vweixinthumb.tc.qq.com 336 | DOMAIN-SUFFIX,wechat.com 337 | DOMAIN-SUFFIX,wechatos.net 338 | DOMAIN-SUFFIX,weixin.com 339 | DOMAIN-SUFFIX,weixin.qq.com 340 | DOMAIN-SUFFIX,wx.gtimg.com 341 | DOMAIN-SUFFIX,wx.qq.com 342 | DOMAIN-SUFFIX,wxs.qq.com 343 | 344 | # Device positioning 345 | DOMAIN-SUFFIX,analytics.map.qq.com 346 | DOMAIN-SUFFIX,apis.map.qq.com 347 | DOMAIN-SUFFIX,cc.map.qq.com 348 | DOMAIN-SUFFIX,indoorroad.map.qq.com 349 | DOMAIN-SUFFIX,lbs.gtimg.com 350 | DOMAIN-SUFFIX,lbs.map.qq.com 351 | DOMAIN-SUFFIX,nlp.map.qq.com 352 | DOMAIN-SUFFIX,rttgps.map.qq.com 353 | DOMAIN-SUFFIX,ue.indoorloc.map.qq.com 354 | DOMAIN-SUFFIX,up-hl.3g.qq.com 355 | DOMAIN-SUFFIX,yun-hl.3g.qq.com 356 | 357 | USER-AGENT,WeChat* 358 | USER-AGENT,MicroMessenger* 359 | -------------------------------------------------------------------------------- /Time-based-One-Time-Password/README.md: -------------------------------------------------------------------------------- 1 | ## Desc 2 | 3 | A time-based one-time password algorithm(TOTP), implemented entirely 100% in Javascript. 4 | 5 | This script complies with [RFC6238](https://datatracker.ietf.org/doc/html/rfc6238) specification and can be run in Surge, QuantumultX, Loon, Shadowrocket. 6 | 7 | 8 | 9 | ## Usage 10 | 11 | ```javascript 12 | const key = 'YOURCLIENTTOKEN'; //TOTP key 13 | const totp = TOTP(key); //Return a six-digit one-time password. 14 | 15 | console.log(totp); //Print log 16 | ``` 17 | 18 | 19 | 20 | ## Acknowledgements 21 | 22 | This script is adapted from https://jsfiddle.net/russau/rbyjk774 and uses Brian Turek's [jsSHA](https://github.com/caligatio/jsSHA/). 23 | 24 | -------------------------------------------------------------------------------- /Time-based-One-Time-Password/TOTP.min.js: -------------------------------------------------------------------------------- 1 | function TOTP(token){function t(e,a,d){var g=0,c=[],b=0,f,k,l,h,m,w,n,y,p=!1,q=[],t=[],v,u=!1;d=d||{};f=d.encoding||"UTF8";v=d.numRounds||1;l=z(a,f);if(v!==parseInt(v,10)||1>v)throw Error("numRounds must a integer >= 1");if("SHA-1"===e)m=512,w=A,n=H,h=160,y=function(a){return a.slice()};else throw Error("Chosen SHA variant is not supported");k=x(e);this.setHMACKey=function(a,b,c){var d;if(!0===p)throw Error("HMAC key already set");if(!0===u)throw Error("Cannot set HMAC key after calling update");f=(c||{}).encoding||"UTF8";b=z(b,f)(a);a=b.binLen;b=b.value;d=m>>>3;c=d/4-1;if(da/8){for(;b.length<=c;)b.push(0);b[c]&=4294967040}for(a=0;a<=c;a+=1)q[a]=b[a]^909522486,t[a]=b[a]^1549556828;k=w(q,k);g=m;p=!0};this.update=function(a){var d,e,f,h=0,n=m>>>5;d=l(a,c,b);a=d.binLen;e=d.value;d=a>>>5;for(f=0;f>>5);b=a%m;u=!0};this.getHash=function(a,d){var f,l,m,r;if(!0===p)throw Error("Cannot call getHash after setting HMAC key");m=B(d);switch(a){case"HEX":f=function(a){return C(a,h,m)};break;case"B64":f=function(a){return D(a,h,m)};break;case"BYTES":f=function(a){return E(a,h)};break;case"ARRAYBUFFER":try{l=new ArrayBuffer(0)}catch(I){throw Error("ARRAYBUFFER not supported by this environment");}f=function(a){return F(a,h)};break;default:throw Error("format must be HEX, B64, BYTES, or ARRAYBUFFER");}r=n(c.slice(),b,g,y(k),h);for(l=1;l>>3;if(0!==g%2)throw Error("String of HEX type must be in byte increments");for(c=0;c>>1)+l;for(f=k>>>2;a.length<=f;)a.push(0);a[f]|=b<<8*(3-k%4)}return{value:a,binLen:4*g+d}}function K(e,a,d){var g=[],c,b,f,k,g=a||[0];d=d||0;b=d>>>3;for(c=0;c>>2,g.length<=f&&g.push(0),g[f]|=a<<8*(3-k%4);return{value:g,binLen:8*e.length+d}}function L(e,a,d){var g=[],c=0,b,f,k,l,h,m,g=a||[0];d=d||0;a=d>>>3;if(-1===e.search(/^[a-zA-Z0-9=+\/]+$/))throw Error("Invalid character in base-64 string");f=e.indexOf("=");e=e.replace(/\=/g,"");if(-1!==f&&f=s.length){s=Array(l+1-s.length).join(p)+s}return s}return(function(s){var k=V(s);var e=Math.round(new Date().getTime()/1000.0);var r=T(X(Math.floor(e/30)),16,'0');var j=new t("SHA-1","HEX");j.setHMACKey(k,"HEX");j.update(r);var h=j.getHMAC("HEX");var o=parseInt(h.substring(h.length-1),16);var p=(parseInt(h.substr(o*2,8),16)&parseInt('7fffffff',16))+'';var z=p.substr(p.length-6,6);return z})(token)}; --------------------------------------------------------------------------------