├── 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))[1] || '' : '';
161 | const numRaters = s ? s[0].split(/(\d+)\u4eba\u8bc4\u4ef7/)[1] || '' : '';
162 | const rating_message = `Douban: ⭐️ ${average ? average + "/10" : "N/A"} ${!numRaters ? "" : parseFloat(numRaters).toLocaleString()}`;
163 | return average && rating_message;
164 | }
165 |
166 | function get_country_message(data) {
167 | const country = data;
168 | const countrys = country.split(", ");
169 | let emoji_country = "";
170 | countrys.forEach(item => {
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],
240 | folk: s[i].split(/(\d+\u4eba\u8bc4\u4ef7)/)[1],
241 | id: s[i].split(/sid:(\d+)/)[1],
242 | year: s[i].split(/(\d+)<\/span>$/)[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>>2;g.length<=b;)g.push(0);g[b]|=(l>>>16-8*k&255)<<8*(3-m%4);c+=1}}return{value:g,binLen:8*c+d}}function M(e,a,d){var g=[],c,b,f,g=a||[0];d=d||0;c=d>>>3;for(a=0;a>>2,g.length<=b&&g.push(0),g[b]|=e[a]<<8*(3-f%4);return{value:g,binLen:8*e.byteLength+d}}function C(e,a,d){var g="";a/=8;var c,b;for(c=0;c>>2]>>>8*(3-c%4),g+="0123456789abcdef".charAt(b>>>4&15)+"0123456789abcdef".charAt(b&15);return d.outputUpper?g.toUpperCase():g}function D(e,a,d){var g="",c=a/8,b,f,k;for(b=0;b>>2]:0,k=b+2>>2]:0,k=(e[b>>>2]>>>8*(3-b%4)&255)<<16|(f>>>8*(3-(b+1)%4)&255)<<8|k>>>8*(3-(b+2)%4)&255,f=0;4>f;f+=1)8*b+6*f<=a?g+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(k>>>6*(3-f)&63):g+=d.b64Pad;return g}function E(e,a){var d="",g=a/8,c,b;for(c=0;c>>2]>>>8*(3-c%4)&255,d+=String.fromCharCode(b);return d}function F(e,a){var d=a/8,g,c=new ArrayBuffer(d);for(g=0;g>>2]>>>8*(3-g%4)&255;return c}function B(e){var a={outputUpper:!1,b64Pad:"=",shakeLen:-1};e=e||{};a.outputUpper=e.outputUpper||!1;!0===e.hasOwnProperty("b64Pad")&&(a.b64Pad=e.b64Pad);if("boolean"!==typeof a.outputUpper)throw Error("Invalid outputUpper formatting option");if("string"!==typeof a.b64Pad)throw Error("Invalid b64Pad formatting option");return a}function z(e,a){var d;switch(a){case"UTF8":case"UTF16BE":case"UTF16LE":break;default:throw Error("encoding must be UTF8, UTF16BE, or UTF16LE");}switch(e){case"HEX":d=J;break;case"TEXT":d=function(d,c,b){var f=[],e=[],l=0,h,m,q,n,p,f=c||[0];c=b||0;q=c>>>3;if("UTF8"===a)for(h=0;hb?e.push(b):2048>b?(e.push(192|b>>>6),e.push(128|b&63)):55296>b||57344<=b?e.push(224|b>>>12,128|b>>>6&63,128|b&63):(h+=1,b=65536+((b&1023)<<10|d.charCodeAt(h)&1023),e.push(240|b>>>18,128|b>>>12&63,128|b>>>6&63,128|b&63)),m=0;m>>2;f.length<=n;)f.push(0);f[n]|=e[m]<<8*(3-p%4);l+=1}else if("UTF16BE"===a||"UTF16LE"===a)for(h=0;h>>8);p=l+q;for(n=p>>>2;f.length<=n;)f.push(0);f[n]|=b<<8*(2-p%4);l+=2}return{value:f,binLen:8*l+c}};break;case"B64":d=L;break;case"BYTES":d=K;break;case"ARRAYBUFFER":try{d=new ArrayBuffer(0)}catch(g){throw Error("ARRAYBUFFER not supported by this environment");}d=M;break;default:throw Error("format must be HEX, TEXT, B64, BYTES, or ARRAYBUFFER");}return d}function p(e,a){return e<>>32-a}function q(e,a){var d=(e&65535)+(a&65535);return((e>>>16)+(a>>>16)+(d>>>16)&65535)<<16|d&65535}function u(e,a,d,g,c){var b=(e&65535)+(a&65535)+(d&65535)+(g&65535)+(c&65535);return((e>>>16)+(a>>>16)+(d>>>16)+(g>>>16)+(c>>>16)+(b>>>16)&65535)<<16|b&65535}function x(e){var a=[];if("SHA-1"===e)a=[1732584193,4023233417,2562383102,271733878,3285377520];else throw Error("No SHA variants supported");return a}function A(e,a){var d=[],g,c,b,f,k,l,h;g=a[0];c=a[1];b=a[2];f=a[3];k=a[4];for(h=0;80>h;h+=1)d[h]=16>h?e[h]:p(d[h-3]^d[h-8]^d[h-14]^d[h-16],1),l=20>h?u(p(g,5),c&b^~c&f,k,1518500249,d[h]):40>h?u(p(g,5),c^b^f,k,1859775393,d[h]):60>h?u(p(g,5),c&b^c&f^b&f,k,2400959708,d[h]):u(p(g,5),c^b^f,k,3395469782,d[h]),k=f,f=b,b=p(c,30),c=g,g=l;a[0]=q(g,a[0]);a[1]=q(c,a[1]);a[2]=q(b,a[2]);a[3]=q(f,a[3]);a[4]=q(k,a[4]);return a}function H(e,a,d,g){var c;for(c=(a+65>>>9<<4)+15;e.length<=c;)e.push(0);e[a>>>5]|=128<<24-a%32;a+=d;e[c]=a&4294967295;e[c-1]=a/4294967296|0;a=e.length;for(c=0;c=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)};
--------------------------------------------------------------------------------