├── CONF
├── Mac-Loon.conf
├── Loon.conf
├── Mac-Shadowrocket.conf
└── Shadowrocket.conf
├── JS
├── Loon plugin control.js
├── MingyuSteps.js
├── NodeUnlockDetection.js
├── PullToRefresh.js
├── Steps Update.js
├── TF Account Management.js
├── TF Detection.js
├── TF relief area.js
├── ZiyiSteps.js
├── aliyu.js
├── atoken.js
├── barkip.js
├── busuanzi2.js
├── ghptran1.js
├── install.sh
├── layui-dark.js
├── nodeseek.js
├── pwa.html
├── pwa.js
├── pwabeta.js
├── pwaghp.js
├── pwahubp.js
├── pwamini.js
├── tes.js
└── webmailin.js
├── LIST
├── beta-direct.list
├── cf.list
├── ymy-direct.list
└── ymy-proxy.list
├── MODULE
├── Auto TF.module
├── TF.module
├── TikTok.module
└── aliyun.module
├── PLUGIN
├── 111.plugin
├── Auto TF.plugin
├── BiliBili.plugin
├── Bing AI.plugin
├── GlobalProxy.plugin
├── Host Speed.plugin
├── JD price comparison.plugin
├── Loon plugin control.plugin
├── Node detection tool.plugin
├── NodeUnlockDetection.public
├── ProxyAPI.plugin
├── Steps Update Love.plugin
├── Steps Update Nolove.plugin
├── TF Account Management.plugin
├── TF Detection.plugin
├── TF monitoring.plugin
├── TF relief area.plugin
├── TikTok JP.plugin
├── Warp detection tool.plugin
├── aisiiiii.plugin
├── aliyun auto.plugin
├── aliyun.plugin
├── aliyuntoken.plugin
├── caiyun.plugin
├── cloudflare.public
├── kongzh.plugin
├── talka.public
└── xn--09ad.xn--y9a3aq.plugin
└── README.md
/CONF/ Mac-Loon.conf:
--------------------------------------------------------------------------------
1 | # @Yu https://t.me/ymyuuu
2 | # Last updated: 2024-09-04
3 |
4 | [General]
5 | doh-server = https://ymy.dns.dash.nyc.mn:20443/dns-query
6 | domain-reject-mode = DNS
7 | udp-fallback-mode = REJECT
8 | internet-test-url = http://cp.cloudflare.com/generate_204
9 | ipv6 = true
10 | skip-proxy = localhost,*.local
11 | bypass-tun = localhost,*.local
12 | dns-server = system,119.29.29.29,119.28.28.28
13 | allow-wifi-access = false
14 | wifi-access-http-port = 7222
15 | wifi-access-socks5-port = 7221
16 | proxy-test-url = http://cp.cloudflare.com/generate_204
17 | test-timeout = 2
18 | interface-mode = auto
19 | switch-node-after-failure-times = 1
20 | disable-stun = true
21 | sni-sniffing = true
22 | resource-parser = https://gitlab.com/lodepuly/vpn_tool/-/raw/master/Resource/Script/Sub-Store/sub-store-parser_for_loon.js
23 |
24 |
25 | [Proxy]
26 |
27 | [Remote Proxy]
28 |
29 | [Remote Filter]
30 | All = NameRegex, FilterKey = ".*"
31 | All but none CF = NameRegex, FilterKey = "^(?!.*Sub|CFW|CFS5)"
32 | Only CF = NameRegex, FilterKey = "Sub|CFW|CFS5"
33 | Locals = NameRegex,Local, FilterKey = ".*"
34 |
35 | [Proxy Group]
36 | General = select,Fast,Fast-Other,All,url = http://cp.cloudflare.com/generate_204,img-url = https://raw.githubusercontent.com/fmz200/wool_scripts/main/icons/apps/FishChips_03.png
37 | Other = select,Fast,Fast-Other,All,url = http://cp.cloudflare.com/generate_204,img-url = https://raw.githubusercontent.com/lige47/QuanX-icon-rule/main/icon/dog.png
38 | Fast = url-test,Only CF,url = http://www.gstatic.com/generate_204,interval = 10,img-url = https://raw.githubusercontent.com/fmz200/wool_scripts/main/icons/apps/FishChips_02.png
39 | Fast-Other = url-test,All but none CF,url = http://www.gstatic.com/generate_204,interval = 10,img-url = https://raw.githubusercontent.com/fmz200/wool_scripts/main/icons/lige47/rocket(1).png
40 |
41 | [Rule]
42 | GEOIP,cn,DIRECT
43 | FINAL,General
44 |
45 | [Remote Rule]
46 | https://gitlab.com/lodepuly/vpn_tool/-/raw/master/Tool/Loon/Rule/Filen.list, policy=DIRECT, tag=Filen.list, enabled=false
47 | https://raw.githubusercontent.com/ymyuuu/config/main/LIST/ymy-proxy.list, policy=Other, tag=DIY-PROXY, enabled=true
48 | https://raw.githubusercontent.com/ymyuuu/config/main/LIST/ymy-direct.list, policy=DIRECT, tag=DIY-DIRECT, enabled=true
49 | https://whatshub.top/rule/Apple.list, policy=DIRECT, tag=Apple, enabled=true
50 | https://whatshub.top/rule/ai.list, policy=Other, tag=人工智能, enabled=true
51 | https://whatshub.top/rule/Telegram.list, policy=Other, tag=Telegram, enabled=true
52 | https://whatshub.top/rule/Cloudflare.list, policy=Other, tag=Cloudflare, enabled=true
53 | https://raw.githubusercontent.com/GMOogway/shadowrocket-rules/master/sr_direct_list.module, policy=DIRECT, tag=DIRECT, enabled=true
54 | https://raw.githubusercontent.com/GMOogway/shadowrocket-rules/master/sr_proxy_list.module, policy=General, tag=PROXY, enabled=false
55 |
56 |
57 | [Host]
58 | [Rewrite]
59 | [Remote Rewrite]
60 | [Script]
61 | [Remote Script]
62 | [Plugin]
63 | https://proxy.030101.xyz/raw.githubusercontent.com/ymyuuu/config/main/PLUGIN/Host%20Speed.plugin, enabled=false
64 | https://raw.githubusercontent.com/ymyuuu/config/main/PLUGIN/GlobalProxy.plugin, enabled=true
65 |
66 | [Mitm]
67 | enable = false
68 | skip-server-cert-verify = true
69 |
--------------------------------------------------------------------------------
/CONF/Loon.conf:
--------------------------------------------------------------------------------
1 | # @Yu https://t.me/ymyuuu
2 | # Last updated: 2024-09-04
3 |
4 | [General]
5 | doh-server = https://ymy.dns.dash.nyc.mn:20443/dns-query
6 | domain-reject-mode = DNS
7 | udp-fallback-mode = REJECT
8 | internet-test-url = http://cp.cloudflare.com/generate_204
9 | ipv6 = true
10 | skip-proxy = localhost,*.local
11 | bypass-tun = localhost,*.local
12 | dns-server = system,119.29.29.29,119.28.28.28
13 | allow-wifi-access = false
14 | wifi-access-http-port = 7222
15 | wifi-access-socks5-port = 7221
16 | proxy-test-url = http://cp.cloudflare.com/generate_204
17 | test-timeout = 2
18 | interface-mode = auto
19 | switch-node-after-failure-times = 1
20 | disable-stun = true
21 | sni-sniffing = true
22 | resource-parser = https://gitlab.com/lodepuly/vpn_tool/-/raw/master/Resource/Script/Sub-Store/sub-store-parser_for_loon.js
23 |
24 | [Proxy]
25 |
26 | [Remote Proxy]
27 |
28 | [Remote Filter]
29 | All = NameRegex, FilterKey = ".*"
30 | All but none CF = NameRegex, FilterKey = "^(?!.*Sub|CFW|CFS5)"
31 | Only CF = NameRegex, FilterKey = "Sub|CFW|CFS5"
32 | Locals = NameRegex,Local, FilterKey = ".*"
33 |
34 | [Proxy Group]
35 | General = select,Fast,Fast-Other,All but none CF,url = http://cp.cloudflare.com/generate_204,img-url = https://raw.githubusercontent.com/fmz200/wool_scripts/main/icons/apps/FishChips_03.png
36 | Other = select,Fast,Fast-Other,All but none CF,url = http://cp.cloudflare.com/generate_204,img-url = https://raw.githubusercontent.com/lige47/QuanX-icon-rule/main/icon/dog.png
37 | Fast = url-test,Only CF,url = http://cp.cloudflare.com/generate_204,interval = 60,img-url = https://raw.githubusercontent.com/fmz200/wool_scripts/main/icons/apps/FishChips_02.png
38 | Fast-Other = url-test,All but none CF,url = http://cp.cloudflare.com/generate_204,interval = 60,img-url = https://raw.githubusercontent.com/fmz200/wool_scripts/main/icons/lige47/rocket(1).png
39 | # Auto Fast = url-test,All nodes,url = http://www.apple.com/library/test/success.html,interval = 60,img-url = https://raw.githubusercontent.com/fmz200/wool_scripts/main/icons/Twoandz9/MIlk.png
40 |
41 | [Proxy Chain]
42 | [Rule]
43 | GEOIP,cn,DIRECT
44 | FINAL,General
45 |
46 | [Remote Rule]
47 | https://raw.githubusercontent.com/ymyuuu/config/main/LIST/ymy-direct.list, policy=DIRECT, tag=DIY-DIRECT, enabled=true
48 | https://raw.githubusercontent.com/ymyuuu/config/main/LIST/ymy-proxy.list, policy=Other, tag=DIY-PROXY, enabled=true
49 | https://whatshub.top/rule/Apple.list, policy=DIRECT, tag=Apple, enabled=true
50 | https://whatshub.top/rule/ChatGPT.list, policy=Other, tag=人工智能, enabled=true
51 | https://whatshub.top/rule/Telegram.list, policy=Other, tag=Telegram, enabled=true
52 | https://whatshub.top/rule/Cloudflare.list, policy=Other, tag=Cloudflare, enabled=true
53 | https://whatshub.top/rule/AntiAD.list, policy=REJECT, tag=去广告, enabled=true
54 | https://raw.githubusercontent.com/GMOogway/shadowrocket-rules/master/sr_direct_list.module, policy=DIRECT, tag=DIRECT, enabled=true
55 | https://raw.githubusercontent.com/GMOogway/shadowrocket-rules/master/sr_proxy_list.module, policy=General, tag=PROXY, enabled=false
56 |
57 | [Host]
58 | [Rewrite]
59 | [Remote Rewrite]
60 | [Script]
61 | [Remote Script]
62 | [Plugin]
63 | https://gitlab.com/lodepuly/vpn_tool/-/raw/master/Tool/Loon/Plugin/PinDuoDuo_remove_ads.plugin, enabled=true
64 | https://gitlab.com/lodepuly/vpn_tool/-/raw/master/Tool/Loon/Plugin/WARP_Node_Query.plugin, enabled=true
65 | https://whatshub.top/plugin/adultraplus.plugin, enabled=true
66 | https://raw.githubusercontent.com/chxm1023/Script_X/main/Collections.plugin, enabled=true
67 | https://gitlab.com/lodepuly/vpn_tool/-/raw/master/Tool/Loon/Plugin/YouTube_remove_ads.plugin, enabled=true
68 | https://raw.githubusercontent.com/ymyuuu/config/main/PLUGIN/GlobalProxy.plugin, enabled=true
69 | https://raw.githubusercontent.com/VirgilClyne/GetSomeFries/main/plugin/General.plugin, enabled=true
70 | https://gitlab.com/lodepuly/vpn_tool/-/raw/master/Tool/Loon/Plugin/12306_remove_ads.plugin, enabled=true
71 | https://gitlab.com/lodepuly/vpn_tool/-/raw/master/Tool/Loon/Plugin/Node_detection_tool.plugin, enabled=true
72 |
73 | [Mitm]
74 | enable = false
75 | skip-server-cert-verify = true
76 |
--------------------------------------------------------------------------------
/CONF/Mac-Shadowrocket.conf:
--------------------------------------------------------------------------------
1 | # Shadowrocket: 2023-12-12 01:36:29
2 |
3 | [General]
4 | bypass-system = true
5 | dns-server = quic://mingyudns.030101.xyz:853,https://mingyudns.030101.xyz:444/dns-query
6 | fallback-dns-server = system
7 | ipv6 = true
8 | prefer-ipv6 = true
9 | dns-fallback-system = false
10 | dns-direct-system = false
11 | tun-included-routes = localhost,*.local
12 | skip-proxy = localhost,*.local
13 | tun-excluded-routes = localhost,*.local
14 | always-real-ip = *.apple.com,*.iCloud.com
15 | icmp-auto-reply = true
16 | always-reject-url-rewrite = false
17 | private-ip-answer = true
18 |
19 | [Proxy Group]
20 | General = select,FAST,FAST-OTHER,interval=86400,timeout=5,select=0,url=http://spurl.030101.xyz/
21 | Other = select,FAST,FAST-OTHER,interval=86400,timeout=5,select=1,url=http://spurl.030101.xyz/
22 | Fast = url-test,url=http://spurl.030101.xyz/,interval=10,tolerance=0,timeout=5,select=0,policy-regex-filter=^(?!.*✅).*$
23 | Fast-other = url-test,url=http://spurl.030101.xyz/,interval=10,tolerance=0,timeout=5,select=0,policy-regex-filter=✅
24 |
25 | [Rule]
26 | # DIY
27 | RULE-SET,https://raw.githubusercontent.com/ymyuuu/config/main/LIST/ymy-proxy.list,OTHER
28 | RULE-SET,https://raw.githubusercontent.com/ymyuuu/config/main/LIST/ymy-direct.list,DIRECT
29 | # 单独分流
30 | RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Loon/Speedtest/Speedtest.list,GENERAL
31 | # 规则修正
32 | RULE-SET,https://cdn.jsdelivr.net/gh/GMOogway/shadowrocket-rules@master/sr_proxy_list.module,GENERAL
33 | RULE-SET,https://cdn.jsdelivr.net/gh/GMOogway/shadowrocket-rules@master/sr_direct_list.module,DIRECT
34 |
35 | GEOIP,CN,DIRECT
36 | FINAL,GENERAL
37 |
38 | [URL Rewrite]
39 | ^https?://(www.)?g.cn https://www.google.com 302
40 | ^https?://(www.)?google.cn https://www.google.com 302
41 | (?<=_region=)CN(?=&) JP 307
42 | (?<=&mcc_mnc=)4 2 307
43 | ^(https?:\/\/(tnc|dm)[\w-]+\.\w+\.com\/.+)(\?)(.+) $1$3 302
44 | (^https?:\/\/*\.\w{4}okv.com\/.+&.+)(\d{2}\.3\.\d)(.+) $118.0$3 302
45 |
46 | [MITM]
47 | ca-passphrase = Shadowrocket
48 | ca-p12 =
49 | enable = true
50 | hostname = *.google.cn,*.tiktokv.com,*.byteoversea.com,*.tik-tokapi.com
51 |
--------------------------------------------------------------------------------
/CONF/Shadowrocket.conf:
--------------------------------------------------------------------------------
1 | # Shadowrocket: 2023-12-12 01:36:29
2 |
3 | [General]
4 | bypass-system = true
5 | dns-server = quic://mingyudns.030101.xyz:853,https://mingyudns.030101.xyz:444/dns-query
6 | fallback-dns-server = system
7 | ipv6 = true
8 | prefer-ipv6 = true
9 | dns-fallback-system = false
10 | dns-direct-system = false
11 | tun-included-routes = localhost,*.local
12 | skip-proxy = localhost,*.local
13 | tun-excluded-routes = localhost,*.local
14 | always-real-ip = *.apple.com,*.iCloud.com
15 | icmp-auto-reply = true
16 | always-reject-url-rewrite = false
17 | private-ip-answer = true
18 |
19 | [Proxy Group]
20 | General = select,FAST,FAST-OTHER,interval=86400,timeout=5,select=0,url=http://spurl.030101.xyz/
21 | Other = select,FAST,FAST-OTHER,interval=86400,timeout=5,select=1,url=http://spurl.030101.xyz/
22 | Fast = url-test,url=http://spurl.030101.xyz/,interval=120,tolerance=0,timeout=5,select=0,policy-regex-filter=^(?!.*✅).*$
23 | Fast-other = url-test,url=http://spurl.030101.xyz/,interval=120,tolerance=0,timeout=5,select=0,policy-regex-filter=✅
24 |
25 | [Rule]
26 | # DIY
27 | RULE-SET,https://raw.githubusercontent.com/ymyuuu/config/main/LIST/ymy-proxy.list,OTHER
28 | RULE-SET,https://raw.githubusercontent.com/ymyuuu/config/main/LIST/ymy-direct.list,DIRECT
29 | # 单独分流
30 | RULE-SET,https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Loon/Speedtest/Speedtest.list,GENERAL
31 | # 规则修正
32 | RULE-SET,https://cdn.jsdelivr.net/gh/GMOogway/shadowrocket-rules@master/sr_proxy_list.module,GENERAL
33 | RULE-SET,https://cdn.jsdelivr.net/gh/GMOogway/shadowrocket-rules@master/sr_direct_list.module,DIRECT
34 |
35 | GEOIP,CN,DIRECT
36 | FINAL,GENERAL
37 |
38 | [URL Rewrite]
39 | ^https?://(www.)?g.cn https://www.google.com 302
40 | ^https?://(www.)?google.cn https://www.google.com 302
41 | (?<=_region=)CN(?=&) JP 307
42 | (?<=&mcc_mnc=)4 2 307
43 | ^(https?:\/\/(tnc|dm)[\w-]+\.\w+\.com\/.+)(\?)(.+) $1$3 302
44 | (^https?:\/\/*\.\w{4}okv.com\/.+&.+)(\d{2}\.3\.\d)(.+) $118.0$3 302
45 |
46 | [MITM]
47 | ca-passphrase = Shadowrocket
48 | ca-p12 =
49 | enable = true
50 | hostname = *.google.cn,*.tiktokv.com,*.byteoversea.com,*.tik-tokapi.com
51 |
--------------------------------------------------------------------------------
/JS/MingyuSteps.js:
--------------------------------------------------------------------------------
1 | const maxRunCount = 10; // 最大运行次数
2 | let runCount = 0; // 运行次数计数器
3 |
4 | function updateSteps() {
5 | runCount++; // 增加运行次数计数器
6 |
7 | console.log(`正在运行第 ${runCount} 次`);
8 |
9 | const savedData = $persistentStore.read('Mingyu');
10 | if (savedData) {
11 | const [savedAccount, savedPassword, savedMaxSteps, savedMinSteps, notifyOption] = savedData.split('@');
12 | if (savedAccount && savedPassword && savedMaxSteps && savedMinSteps && notifyOption) {
13 | account = savedAccount;
14 | password = savedPassword;
15 | maxSteps = parseInt(savedMaxSteps);
16 | minSteps = parseInt(savedMinSteps);
17 | notify = notifyOption === 'M';
18 | }
19 | }
20 |
21 | // 判断账号密码最大步数最小步数是否存在
22 | if (!account || !password || !maxSteps || !minSteps) {
23 | console.log('缺少必要信息');
24 | if (notify) {
25 | $notification.post('步数更改失败', '缺少必要信息', '请检查账号、密码、最大步数和最小步数');
26 | }
27 | $done();
28 | return;
29 | }
30 |
31 | // 判断最大步数和最小步数是否超限
32 | if (maxSteps > 98000 || minSteps > 98000) {
33 | console.log('最大步数和最小步数不能超过98000');
34 | if (notify) {
35 | $notification.post('步数更改失败', '最大步数和最小步数不能超过98000', '请检查最大步数和最小步数');
36 | }
37 | $done();
38 | return;
39 | } else if (maxSteps < minSteps) {
40 | console.log('最大步数不能小于最小步数');
41 | if (notify) {
42 | $notification.post('步数更改失败', '最大步数不能小于最小步数', '请检查最大步数和最小步数');
43 | }
44 | $done();
45 | return;
46 | } else if (minSteps > maxSteps) {
47 | console.log('最小步数不能大于最大步数');
48 | if (notify) {
49 | $notification.post('步数更改失败', '最小步数不能大于最大步数', '请检查最大步数和最小步数');
50 | }
51 | $done();
52 | return;
53 | }
54 |
55 | const randomSteps = Math.floor(Math.random() * (maxSteps - minSteps + 1)) + minSteps;
56 |
57 | const url = 'http://bs.svv.ink/index.php';
58 |
59 | const request = {
60 | url: url,
61 | method: 'POST',
62 | headers: {
63 | 'Content-Type': 'application/x-www-form-urlencoded',
64 | 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1',
65 | },
66 | body: `account=${account}&password=${password}&steps=${randomSteps}&max_steps=${maxSteps}&min_steps=${minSteps}`,
67 | };
68 |
69 | $httpClient.post(request, function (error, response, data) {
70 | if (error || response.status !== 200) {
71 | console.log('请求失败:', error || response.status);
72 | // 检查是否达到最大运行次数
73 | if (runCount < maxRunCount) {
74 | // 在下一次运行前添加延迟
75 | setTimeout(updateSteps, 5000); // 在下一次运行前等待5秒
76 | } else {
77 | console.log('已达到最大运行次数');
78 | if (notify) {
79 | $notification.post('步数更改失败', '已达到最大运行次数', '请稍后再试');
80 | }
81 | }
82 | return;
83 | }
84 |
85 | const jsonData = JSON.parse(data);
86 | console.log(`步数更新成功:${randomSteps.toString()}`, jsonData);
87 | if (notify) {
88 | $notification.post('Steps Update Successful', `Steps: ${randomSteps.toString()}`, '@YangMingyu', 'https://t.me/ymyuuu');
89 | }
90 | });
91 |
92 | const newData = `${account}@${password}@${maxSteps}@${minSteps}@${notify ? 'M' : 'N'}`;
93 | $persistentStore.write(newData, 'YangMingyu').then(() => {
94 | console.log('写入成功');
95 | }, () => {
96 | console.log('写入失败');
97 | });
98 |
99 | if (runCount < maxRunCount) {
100 | // 在下一次运行前添加延迟
101 | setTimeout(updateSteps, 5000); // 在下一次运行前等待5秒
102 | } else {
103 | console.log('已达到最大运行次数');
104 | if (notify) {
105 | $notification.post('步数更改失败', '已达到最大运行次数', '请稍后再试');
106 | }
107 | }
108 | }
109 |
110 | // 调用函数开始更新步数
111 | updateSteps();
112 |
--------------------------------------------------------------------------------
/JS/NodeUnlockDetection.js:
--------------------------------------------------------------------------------
1 | /*
2 | * 节点解锁查询
3 | * 感谢并修改自 https://raw.githubusercontent.com/KOP-XIAO/QuantumultX/master/Scripts/streaming-ui-check.js
4 | * 脚本功能:检查节点是否支持Dazn/Discovery/Param/Disney/Netflix/ChatGPT/YouTube解锁服务
5 | * 原作者:XIAO_KOP
6 | */
7 |
8 | // 定义常量
9 | const CONFIG = {
10 | // 请求超时时间(毫秒)
11 | TIMEOUT: 10000,
12 | // 最大重试次数
13 | MAX_RETRIES: 2
14 | };
15 |
16 | // 流媒体服务接口
17 | const API = {
18 | NETFLIX: "https://www.netflix.com/title/81280792",
19 | DISNEY: "https://www.disneyplus.com",
20 | DISNEY_LOCATION: "https://disney.api.edge.bamgrid.com/graph/v1/device/graphql",
21 | YOUTUBE: "https://www.youtube.com/premium",
22 | DAZN: "https://startup.core.indazn.com/misl/v5/Startup",
23 | PARAMOUNT: "https://www.paramountplus.com/",
24 | DISCOVERY_TOKEN: "https://us1-prod-direct.discoveryplus.com/token?deviceId=d1a4a5d25212400d1e6985984604d740&realm=go&shortlived=true",
25 | DISCOVERY: "https://us1-prod-direct.discoveryplus.com/users/me",
26 | CHATGPT: "https://chatgpt.com/",
27 | CHATGPT_REGION: "https://chatgpt.com/cdn-cgi/trace",
28 | GOOGLE: "https://www.google.com/maps/timeline"
29 | };
30 |
31 | // 国家/地区国旗映射
32 | const FLAGS = new Map([
33 | ["AC", "🇦🇨"], ["AE", "🇦🇪"], ["AF", "🇦🇫"], ["AI", "🇦🇮"], ["AL", "🇦🇱"],
34 | ["AM", "🇦🇲"], ["AQ", "🇦🇶"], ["AR", "🇦🇷"], ["AS", "🇦🇸"], ["AT", "🇦🇹"],
35 | ["AU", "🇦🇺"], ["AW", "🇦🇼"], ["AX", "🇦🇽"], ["AZ", "🇦🇿"], ["BA", "🇧🇦"],
36 | ["BB", "🇧🇧"], ["BD", "🇧🇩"], ["BE", "🇧🇪"], ["BF", "🇧🇫"], ["BG", "🇧🇬"],
37 | ["BH", "🇧🇭"], ["BI", "🇧🇮"], ["BJ", "🇧🇯"], ["BM", "🇧🇲"], ["BN", "🇧🇳"],
38 | ["BO", "🇧🇴"], ["BR", "🇧🇷"], ["BS", "🇧🇸"], ["BT", "🇧🇹"], ["BV", "🇧🇻"],
39 | ["BW", "🇧🇼"], ["BY", "🇧🇾"], ["BZ", "🇧🇿"], ["CA", "🇨🇦"], ["CF", "🇨🇫"],
40 | ["CH", "🇨🇭"], ["CK", "🇨🇰"], ["CL", "🇨🇱"], ["CM", "🇨🇲"], ["CN", "🇨🇳"],
41 | ["CO", "🇨🇴"], ["CP", "🇨🇵"], ["CR", "🇨🇷"], ["CU", "🇨🇺"], ["CV", "🇨🇻"],
42 | ["CW", "🇨🇼"], ["CX", "🇨🇽"], ["CY", "🇨🇾"], ["CZ", "🇨🇿"], ["DE", "🇩🇪"],
43 | ["DG", "🇩🇬"], ["DJ", "🇩🇯"], ["DK", "🇩🇰"], ["DM", "🇩🇲"], ["DO", "🇩🇴"],
44 | ["DZ", "🇩🇿"], ["EA", "🇪🇦"], ["EC", "🇪🇨"], ["EE", "🇪🇪"], ["EG", "🇪🇬"],
45 | ["EH", "🇪🇭"], ["ER", "🇪🇷"], ["ES", "🇪🇸"], ["ET", "🇪🇹"], ["EU", "🇪🇺"],
46 | ["FI", "🇫🇮"], ["FJ", "🇫🇯"], ["FK", "🇫🇰"], ["FM", "🇫🇲"], ["FO", "🇫🇴"],
47 | ["FR", "🇫🇷"], ["GA", "🇬🇦"], ["GB", "🇬🇧"], ["HK", "🇭🇰"], ["HU", "🇭🇺"],
48 | ["ID", "🇮🇩"], ["IE", "🇮🇪"], ["IL", "🇮🇱"], ["IM", "🇮🇲"], ["IN", "🇮🇳"],
49 | ["IS", "🇮🇸"], ["IT", "🇮🇹"], ["JP", "🇯🇵"], ["KR", "🇰🇷"], ["LU", "🇱🇺"],
50 | ["MO", "🇲🇴"], ["MX", "🇲🇽"], ["MY", "🇲🇾"], ["NL", "🇳🇱"], ["PH", "🇵🇭"],
51 | ["PL", "🇵🇱"], ["RO", "🇷🇴"], ["RS", "🇷🇸"], ["RU", "🇷🇺"], ["RW", "🇷🇼"],
52 | ["SA", "🇸🇦"], ["SB", "🇸🇧"], ["SC", "🇸🇨"], ["SD", "🇸🇩"], ["SE", "🇸🇪"],
53 | ["SG", "🇸🇬"], ["TH", "🇹🇭"], ["TN", "🇹🇳"], ["TO", "🇹🇴"], ["TR", "🇹🇷"],
54 | ["TV", "🇹🇻"], ["TW", "🇨🇳"], ["UK", "🇬🇧"], ["UM", "🇺🇲"], ["US", "🇺🇸"],
55 | ["UY", "🇺🇾"], ["UZ", "🇺🇿"], ["VA", "🇻🇦"], ["VE", "🇻🇪"], ["VG", "🇻🇬"],
56 | ["VI", "🇻🇮"], ["VN", "🇻🇳"], ["ZA", "🇿🇦"]
57 | ]);
58 |
59 | // 获取节点名称
60 | var inputParams = $environment.params;
61 | var nodeName = inputParams.node;
62 |
63 | // 初始化结果对象
64 | let result = {
65 | "title": '节点解锁查询',
66 | "YouTube": 'YouTube Premium: 检测失败,请重试 ❗️',
67 | "Netflix": 'Netflix: 检测失败,请重试 ❗️',
68 | "Dazn": "Dazn: 检测失败,请重试 ❗️",
69 | "Disney": "Disney+: 检测失败,请重试 ❗️",
70 | "Paramount": "Paramount+: 检测失败,请重试 ❗️",
71 | "Discovery": "Discovery+: 检测失败,请重试 ❗️",
72 | "ChatGPT": "ChatGPT: 检测失败,请重试 ❗️"
73 | };
74 |
75 | // 箭头样式
76 | const ARROW = " ➟ ";
77 |
78 | // 通用HTTP请求函数(带重试)
79 | function makeRequest(options, retryCount = 0) {
80 | return new Promise((resolve, reject) => {
81 | // 默认设置超时
82 | if (!options.timeout) {
83 | options.timeout = CONFIG.TIMEOUT;
84 | }
85 | // 添加节点
86 | if (!options.node) {
87 | options.node = nodeName;
88 | }
89 |
90 | // 判断是GET还是POST请求
91 | const requestMethod = options.body ? 'post' : 'get';
92 |
93 | $httpClient[requestMethod](options, (error, response, data) => {
94 | if (error) {
95 | console.log(`${options.label || '请求'} 失败: ${error}`);
96 |
97 | // 如果还有重试次数,则重试
98 | if (retryCount < CONFIG.MAX_RETRIES) {
99 | console.log(`正在进行第 ${retryCount + 1} 次重试...`);
100 | resolve(makeRequest(options, retryCount + 1));
101 | return;
102 | }
103 |
104 | // 重试次数用完,返回错误
105 | resolve({ error, response: null, data: null });
106 | return;
107 | }
108 |
109 | // 请求成功
110 | resolve({ error: null, response, data });
111 | });
112 | });
113 | }
114 |
115 | // Netflix 检测
116 | async function checkNetflix() {
117 | console.log("----------Netflix 检测开始----------");
118 |
119 | const { error, response, data } = await makeRequest({
120 | url: API.NETFLIX,
121 | label: "Netflix"
122 | });
123 |
124 | if (error) {
125 | result.Netflix = "Netflix: 检测失败 ❗️";
126 | return;
127 | }
128 |
129 | if (response.status === 403) {
130 | result.Netflix = "Netflix: 未支持 🚫";
131 | return;
132 | }
133 |
134 | if (response.status === 404) {
135 | result.Netflix = "Netflix: 支持自制剧集 ⚠️";
136 | return;
137 | }
138 |
139 | if (response.status === 200) {
140 | let region = "未知";
141 | try {
142 | // 尝试从headers获取地区信息
143 | let ourl = response.headers['X-Originating-URL'] ||
144 | response.headers['X-Originating-Url'] ||
145 | response.headers['x-originating-url'];
146 |
147 | if (ourl) {
148 | region = ourl.split('/')[3];
149 | region = region.split('-')[0];
150 | if (region === 'title') {
151 | region = 'us';
152 | }
153 | }
154 |
155 | result.Netflix = `Netflix: 完整支持${ARROW}⟦${FLAGS.get(region.toUpperCase()) || "未知"}⟧ 🎉`;
156 | } catch (e) {
157 | console.log("解析 Netflix 地区错误:", e);
158 | result.Netflix = `Netflix: 完整支持${ARROW}⟦未知地区⟧ 🎉`;
159 | }
160 | return;
161 | }
162 |
163 | result.Netflix = "Netflix: 检测失败 ❗️";
164 | }
165 |
166 | // Disney+ 检测
167 | async function checkDisney() {
168 | console.log("----------Disney+ 检测开始----------");
169 |
170 | const { error, response, data } = await makeRequest({
171 | url: API.DISNEY_LOCATION,
172 | label: "Disney+",
173 | headers: {
174 | 'Accept-Language': 'en',
175 | "Authorization": 'ZGlzbmV5JmJyb3dzZXImMS4wLjA.Cu56AgSfBTDag5NiRA81oLHkDZfu5L3CKadnefEAY84',
176 | 'Content-Type': 'application/json',
177 | 'User-Agent': 'UA'
178 | },
179 | body: JSON.stringify({
180 | query: 'mutation registerDevice($input: RegisterDeviceInput!) { registerDevice(registerDevice: $input) { grant { grantType assertion } } }',
181 | variables: {
182 | input: {
183 | applicationRuntime: 'chrome',
184 | attributes: {
185 | browserName: 'chrome',
186 | browserVersion: '94.0.4606',
187 | manufacturer: 'microsoft',
188 | model: null,
189 | operatingSystem: 'windows',
190 | operatingSystemVersion: '10.0',
191 | osDeviceIds: [],
192 | },
193 | deviceFamily: 'browser',
194 | deviceLanguage: 'en',
195 | deviceProfile: 'windows',
196 | },
197 | },
198 | })
199 | });
200 |
201 | if (error) {
202 | result.Disney = "Disney+: 检测失败 ❗️";
203 | return;
204 | }
205 |
206 | if (response.status !== 200) {
207 | result.Disney = "Disney+: 检测失败 ❗️";
208 | return;
209 | }
210 |
211 | try {
212 | const resData = JSON.parse(data);
213 | if (resData?.extensions?.sdk?.session != null) {
214 | const { inSupportedLocation, location: { countryCode } } = resData.extensions.sdk.session;
215 |
216 | if (inSupportedLocation === false) {
217 | result.Disney = `Disney+: 即将登陆 ${ARROW}⟦${FLAGS.get(countryCode.toUpperCase()) || "未知"}⟧ ⚠️`;
218 | } else {
219 | result.Disney = `Disney+: 支持 ${ARROW}⟦${FLAGS.get(countryCode.toUpperCase()) || "未知"}⟧ 🎉`;
220 | }
221 | } else {
222 | result.Disney = "Disney+: 未支持 🚫";
223 | }
224 | } catch (e) {
225 | console.log("解析 Disney+ 数据错误:", e);
226 | result.Disney = "Disney+: 检测失败 ❗️";
227 | }
228 | }
229 |
230 | // YouTube Premium 检测
231 | async function checkYouTube() {
232 | console.log("----------YouTube Premium 检测开始----------");
233 |
234 | const { error, response, data } = await makeRequest({
235 | url: API.YOUTUBE,
236 | label: "YouTube Premium",
237 | headers: {
238 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36'
239 | }
240 | });
241 |
242 | if (error || response.status !== 200) {
243 | result.YouTube = "YouTube Premium: 检测失败 ❗️";
244 | return;
245 | }
246 |
247 | try {
248 | if (data.indexOf('Premium is not available in your country') !== -1) {
249 | result.YouTube = "YouTube Premium: 未支持 🚫";
250 | return;
251 | }
252 |
253 | // 检测支持的地区
254 | let region = 'US';
255 | let re = new RegExp('"GL":"(.*?)"', 'gm');
256 | let ret = re.exec(data);
257 |
258 | if (ret != null && ret.length === 2) {
259 | region = ret[1];
260 | } else if (data.indexOf('www.google.cn') !== -1) {
261 | region = 'CN';
262 | }
263 |
264 | result.YouTube = `YouTube Premium: 支持 ${ARROW}⟦${FLAGS.get(region.toUpperCase()) || "未知"}⟧ 🎉`;
265 | } catch (e) {
266 | console.log("解析 YouTube Premium 数据错误:", e);
267 | result.YouTube = "YouTube Premium: 检测失败 ❗️";
268 | }
269 | }
270 |
271 | // ChatGPT 检测
272 | async function checkChatGPT() {
273 | console.log("----------ChatGPT 检测开始----------");
274 |
275 | // 第一步: 检查是否可以访问 ChatGPT
276 | const { error, response } = await makeRequest({
277 | url: API.CHATGPT,
278 | label: "ChatGPT"
279 | });
280 |
281 | if (error) {
282 | result.ChatGPT = "ChatGPT: 检测失败 ❗️";
283 | return;
284 | }
285 |
286 | // 如果状态码是403,则表示不支持
287 | if (response.status === 403) {
288 | result.ChatGPT = "ChatGPT: 未支持 🚫";
289 | return;
290 | }
291 |
292 | // 如果可以访问,检查支持的地区
293 | const regionResp = await makeRequest({
294 | url: API.CHATGPT_REGION,
295 | label: "ChatGPT Region"
296 | });
297 |
298 | if (regionResp.error) {
299 | // 如果获取地区失败但能访问主站,标记为支持但无法确定地区
300 | result.ChatGPT = "ChatGPT: 支持但无法确定地区 ⚠️";
301 | return;
302 | }
303 |
304 | try {
305 | // 解析地区信息
306 | let region = "未知";
307 | if (regionResp.data.indexOf("loc=") !== -1) {
308 | region = regionResp.data.split("loc=")[1].split("\n")[0];
309 | }
310 |
311 | result.ChatGPT = `ChatGPT: 支持 ${ARROW}⟦${FLAGS.get(region.toUpperCase()) || "未知"}⟧ 🎉`;
312 | } catch (e) {
313 | console.log("解析 ChatGPT 地区数据错误:", e);
314 | result.ChatGPT = "ChatGPT: 支持但无法确定地区 ⚠️";
315 | }
316 | }
317 |
318 | // Dazn 检测
319 | async function checkDazn() {
320 | console.log("----------Dazn 检测开始----------");
321 |
322 | const { error, response, data } = await makeRequest({
323 | url: API.DAZN,
324 | label: "Dazn",
325 | headers: {
326 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36',
327 | 'Content-Type': 'application/json'
328 | },
329 | body: JSON.stringify({
330 | LandingPageKey: "generic",
331 | Platform: "web",
332 | PlatformAttributes: {},
333 | Manufacturer: "",
334 | PromoCode: "",
335 | Version: "2"
336 | })
337 | });
338 |
339 | if (error) {
340 | result.Dazn = "Dazn: 检测失败 ❗️";
341 | return;
342 | }
343 |
344 | if (response.status !== 200) {
345 | result.Dazn = "Dazn: 检测失败 ❗️";
346 | return;
347 | }
348 |
349 | try {
350 | // 解析地区信息
351 | let re = new RegExp('"GeolocatedCountry":"(.*?)"', 'gm');
352 | let ret = re.exec(data);
353 |
354 | if (ret != null && ret.length === 2) {
355 | let region = ret[1];
356 | result.Dazn = `Dazn: 支持 ${ARROW}⟦${FLAGS.get(region.toUpperCase()) || "未知"}⟧ 🎉`;
357 | } else {
358 | result.Dazn = "Dazn: 未支持 🚫";
359 | }
360 | } catch (e) {
361 | console.log("解析 Dazn 数据错误:", e);
362 | result.Dazn = "Dazn: 检测失败 ❗️";
363 | }
364 | }
365 |
366 | // Paramount+ 检测
367 | async function checkParamount() {
368 | console.log("----------Paramount+ 检测开始----------");
369 |
370 | const { error, response } = await makeRequest({
371 | url: API.PARAMOUNT,
372 | label: "Paramount+",
373 | headers: {
374 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36'
375 | }
376 | });
377 |
378 | if (error) {
379 | result.Paramount = "Paramount+: 检测失败 ❗️";
380 | return;
381 | }
382 |
383 | if (response.status === 200) {
384 | result.Paramount = "Paramount+: 支持 🎉";
385 | } else if (response.status === 302) {
386 | result.Paramount = "Paramount+: 未支持 🚫";
387 | } else {
388 | result.Paramount = "Paramount+: 检测失败 ❗️";
389 | }
390 | }
391 |
392 | // Discovery+ 检测
393 | async function checkDiscovery() {
394 | console.log("----------Discovery+ 检测开始----------");
395 |
396 | // 第一步: 获取 token
397 | const tokenResp = await makeRequest({
398 | url: API.DISCOVERY_TOKEN,
399 | label: "Discovery+ Token",
400 | headers: {
401 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36'
402 | }
403 | });
404 |
405 | if (tokenResp.error || tokenResp.response.status !== 200) {
406 | result.Discovery = "Discovery+: 检测失败 ❗️";
407 | return;
408 | }
409 |
410 | try {
411 | // 解析token
412 | const tokenData = JSON.parse(tokenResp.data);
413 | const token = tokenData.data.attributes.token;
414 |
415 | // 构建cookie
416 | const cookieValid = `_gcl_au=1.1.858579665.1632206782; _rdt_uuid=1632206782474.6a9ad4f2-8ef7-4a49-9d60-e071bce45e88; _scid=d154b864-8b7e-4f46-90e0-8b56cff67d05; _pin_unauth=dWlkPU1qWTRNR1ZoTlRBdE1tSXdNaTAwTW1Nd0xUbGxORFV0WWpZMU0yVXdPV1l6WldFeQ; _sctr=1|1632153600000; aam_fw=aam%3D9354365%3Baam%3D9040990; aam_uuid=24382050115125439381416006538140778858; st=${token}; gi_ls=0; _uetvid=a25161a01aa711ec92d47775379d5e4d; AMCV_BC501253513148ED0A490D45%40AdobeOrg=-1124106680%7CMCIDTS%7C18894%7CMCMID%7C24223296309793747161435877577673078228%7CMCAAMLH-1633011393%7C9%7CMCAAMB-1633011393%7CRKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y%7CMCOPTOUT-1632413793s%7CNONE%7CvVersion%7C5.2.0; ass=19ef15da-95d6-4b1d-8fa2-e9e099c9cc38.1632408400.1632406594`;
417 |
418 | // 第二步: 检查地区
419 | const { error, response, data } = await makeRequest({
420 | url: API.DISCOVERY,
421 | label: "Discovery+",
422 | headers: {
423 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36',
424 | 'Cookie': cookieValid
425 | }
426 | });
427 |
428 | if (error || response.status !== 200) {
429 | result.Discovery = "Discovery+: 检测失败 ❗️";
430 | return;
431 | }
432 |
433 | try {
434 | const resData = JSON.parse(data);
435 | const locationd = resData.data.attributes.currentLocationTerritory;
436 |
437 | if (locationd === 'us') {
438 | result.Discovery = "Discovery+: 支持 🎉";
439 | } else {
440 | result.Discovery = "Discovery+: 未支持 🚫";
441 | }
442 | } catch (e) {
443 | console.log("解析 Discovery+ 数据错误:", e);
444 | result.Discovery = "Discovery+: 检测失败 ❗️";
445 | }
446 | } catch (e) {
447 | console.log("解析 Discovery+ Token 错误:", e);
448 | result.Discovery = "Discovery+: 检测失败 ❗️";
449 | }
450 | }
451 |
452 | // 主函数
453 | async function startDetection() {
454 | try {
455 | // 并行执行所有检测
456 | await Promise.all([
457 | checkNetflix(),
458 | checkDisney(),
459 | checkYouTube(),
460 | checkChatGPT(),
461 | checkDazn(),
462 | checkParamount(),
463 | checkDiscovery()
464 | ]);
465 | } catch (error) {
466 | console.log("检测过程中发生错误:", error);
467 | } finally {
468 | // 生成结果页面
469 | const resultServices = [
470 | result.Dazn,
471 | result.Discovery,
472 | result.Paramount,
473 | result.Disney,
474 | result.Netflix,
475 | result.ChatGPT,
476 | result.YouTube
477 | ];
478 |
479 | let content = "------------------------------------" + resultServices.join("");
480 | content = content + "------------------------------------" + "" + "节点 ➟ " + nodeName + "";
481 | content = `
` + content + `
`;
482 |
483 | console.log(content);
484 | $done({"title": result.title, "htmlMessage": content});
485 | }
486 | }
487 |
488 | // 启动检测
489 | startDetection();
490 |
--------------------------------------------------------------------------------
/JS/PullToRefresh.js:
--------------------------------------------------------------------------------
1 | // (function() {
2 | // let isInitialized = false;
3 |
4 | // // 简单日志
5 | // function log(msg) {
6 | // console.log('[PullToRefresh]', msg);
7 | // }
8 |
9 | // // 注入样式并初始化
10 | // function loadAndInit() {
11 | // if (isInitialized) return;
12 |
13 | // // 注入样式
14 | // if (!document.querySelector('#ptr-style')) {
15 | // const style = document.createElement('style');
16 | // style.id = 'ptr-style';
17 | // style.textContent = '.ptr--text, .ptr--icon { color: #9b685b !important; }';
18 | // document.documentElement.appendChild(style);
19 | // log('样式已注入');
20 | // }
21 |
22 | // // 如果库已加载,直接初始化
23 | // if (window.PullToRefresh) {
24 | // try {
25 | // PullToRefresh.init({
26 | // mainElement: 'body',
27 | // onRefresh() {
28 | // log('触发刷新');
29 | // window.location.reload();
30 | // }
31 | // });
32 | // isInitialized = true;
33 | // log('初始化成功');
34 | // return;
35 | // } catch (e) {
36 | // log('初始化失败,重试中');
37 | // }
38 | // }
39 |
40 | // // 加载库
41 | // const script = document.createElement('script');
42 | // script.src = 'https://cdn.jsdelivr.net/npm/pulltorefreshjs/dist/index.umd.min.js';
43 |
44 | // script.onload = () => {
45 | // log('库加载完成');
46 | // setTimeout(loadAndInit, 100);
47 | // };
48 |
49 | // script.onerror = () => {
50 | // log('库加载失败,重试中');
51 | // setTimeout(loadAndInit, 100);
52 | // };
53 |
54 | // document.documentElement.appendChild(script);
55 | // }
56 |
57 | // // 如果body存在直接初始化,否则等待body
58 | // if (document.body) {
59 | // loadAndInit();
60 | // } else {
61 | // new MutationObserver((mutations, obs) => {
62 | // if (document.body) {
63 | // loadAndInit();
64 | // obs.disconnect();
65 | // }
66 | // }).observe(document.documentElement, {
67 | // childList: true,
68 | // subtree: true
69 | // });
70 | // }
71 | // })();
72 | (function() {
73 | // 避免重复初始化
74 | if (window.__PTR_INITIALIZED__) return;
75 |
76 | // 提前设置标志,防止重复执行
77 | window.__PTR_INITIALIZED__ = true;
78 |
79 | // 内联样式直接注入,避免DOM操作延迟
80 | const style = document.createElement('style');
81 | style.textContent = '.ptr--text, .ptr--icon { color: #9b685b !important; }';
82 | document.head.appendChild(style);
83 |
84 | // 使用更高效的日志方式
85 | const log = (msg) => console.log('[PTR]', msg);
86 | log('开始初始化');
87 |
88 | // 创建初始化函数
89 | function initPTR() {
90 | if (!window.PullToRefresh) {
91 | log('等待库加载...');
92 | return false;
93 | }
94 | try {
95 | window.PullToRefresh.init({
96 | mainElement: 'body',
97 | onRefresh() {
98 | log('触发刷新');
99 | window.location.reload();
100 | }
101 | });
102 | log('初始化成功');
103 | return true;
104 | } catch (e) {
105 | log('初始化错误: ' + e.message);
106 | return false;
107 | }
108 | }
109 |
110 | // 使用预加载和资源提示来加速脚本加载
111 | const link = document.createElement('link');
112 | link.rel = 'preload';
113 | link.as = 'script';
114 | link.href = 'https://cdn.jsdelivr.net/npm/pulltorefreshjs/dist/index.umd.min.js';
115 | document.head.appendChild(link);
116 |
117 | // 立即加载脚本,不等待DOM完全加载
118 | const script = document.createElement('script');
119 | script.src = link.href;
120 | script.async = false; // 同步加载提高优先级
121 |
122 | // 在多个阶段尝试初始化,确保尽快完成
123 | script.onload = function() {
124 | log('库加载完成');
125 | // 立即尝试初始化
126 | if (!initPTR()) {
127 | // 如果失败,在下一个微任务中再次尝试
128 | Promise.resolve().then(initPTR);
129 | // 同时在下一帧也尝试初始化
130 | requestAnimationFrame(initPTR);
131 | }
132 | };
133 |
134 | // 挂载脚本(优先放在head中加快解析)
135 | (document.head || document.documentElement).appendChild(script);
136 |
137 | // 如果DOM已经可用,立即尝试初始化
138 | if (document.readyState !== 'loading') {
139 | initPTR();
140 | } else {
141 | // 在DOMContentLoaded时尝试初始化
142 | document.addEventListener('DOMContentLoaded', initPTR, {
143 | once: true
144 | });
145 | }
146 |
147 | // 如果一段时间后仍未初始化,强制重试
148 | setTimeout(function() {
149 | if (!window.PullToRefresh) {
150 | log('加载超时,尝试重新加载');
151 | const fallbackScript = document.createElement('script');
152 | fallbackScript.src =
153 | 'https://cdnjs.cloudflare.com/ajax/libs/pulltorefreshjs/0.1.22/index.umd.min.js';
154 | fallbackScript.onload = initPTR;
155 | document.head.appendChild(fallbackScript);
156 | }
157 | }, 3000);
158 | })();
159 |
--------------------------------------------------------------------------------
/JS/Steps Update.js:
--------------------------------------------------------------------------------
1 | const maxRetries = 3; // 最大重试次数
2 |
3 | function updateSteps(retries = 0) {
4 | const savedData = $persistentStore.read('Mi');
5 | if (savedData) {
6 | const [savedAccount, savedPassword, savedMaxSteps, savedMinSteps, notifyOption] = savedData.split('*');
7 | if (savedAccount && savedPassword && savedMaxSteps && savedMinSteps && notifyOption) {
8 | account = savedAccount;
9 | password = savedPassword;
10 | maxSteps = parseInt(savedMaxSteps);
11 | minSteps = parseInt(savedMinSteps);
12 | notify = notifyOption === 'M';
13 | }
14 | }
15 |
16 | // 判断账号密码最大步数最小步数是否存在
17 | if (!account) {
18 | console.error('缺少账号信息');
19 | if (notify) {
20 | $notification.post('步数更改失败', '缺少账号信息', '请检查账号');
21 | }
22 | $done();
23 | }
24 | if (!password) {
25 | console.error('缺少密码信息');
26 | if (notify) {
27 | $notification.post('步数更改失败', '缺少密码信息', '请检查密码');
28 | }
29 | $done();
30 | }
31 | if (!maxSteps) {
32 | console.error('缺少最大步数信息');
33 | if (notify) {
34 | $notification.post('步数更改失败', '缺少最大步数信息', '请检查最大步数');
35 | }
36 | $done();
37 | }
38 | if (!minSteps) {
39 | console.error('缺少最小步数信息');
40 | if (notify) {
41 | $notification.post('步数更改失败', '缺少最小步数信息', '请检查最小步数');
42 | }
43 | $done();
44 | }
45 |
46 | // 判断最大步数和最小步数是否超限
47 | if (maxSteps > 98000 || minSteps > 98000) {
48 | console.log('最大步数和最小步数不能超过98000');
49 | if (notify) {
50 | $notification.post('步数更改失败', '最大步数和最小步数不能超过98000', '请检查最大步数和最小步数');
51 | }
52 | $done();
53 | } else if (maxSteps < minSteps) {
54 | console.log('最大步数不能小于最小步数');
55 | if (notify) {
56 | $notification.post('步数更改失败', '最大步数不能小于最小步数', '请检查最大步数和最小步数');
57 | }
58 | $done();
59 | } else if (minSteps > maxSteps) {
60 | console.log('最小步数不能大于最大步数');
61 | if (notify) {
62 | $notification.post('步数更改失败', '最小步数不能大于最大步数', '请检查最大步数和最小步数');
63 | }
64 | $done();
65 | } else {
66 | const randomSteps = Math.floor(Math.random() * (maxSteps - minSteps + 1)) + minSteps;
67 |
68 | const url = 'http://bs.svv.ink/index.php';
69 |
70 | const request = {
71 | url: url,
72 | method: 'POST',
73 | headers: {
74 | 'Content-Type': 'application/x-www-form-urlencoded',
75 | 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1',
76 | },
77 | body: `account=${account}&password=${password}&steps=${randomSteps}&max_steps=${maxSteps}&min_steps=${minSteps}`,
78 | };
79 |
80 | $httpClient.post(request, function (error, response, data) {
81 | if (error || response.status !== 200) {
82 | console.error('请求失败:', error || response.status);
83 | if (notify) {
84 | $notification.post('步数更改失败', '请求失败', error || response.status);
85 | }
86 | // 检查重试次数是否超过最大重试次数
87 | if (retries < maxRetries) {
88 | // 在重试之前添加延迟
89 | setTimeout(() => {
90 | // 增加重试次数并调用updateSteps函数进行重试
91 | const nextRetry = retries + 1;
92 | updateSteps(nextRetry);
93 | }, 5000); // 在重试之前等待5秒
94 | } else {
95 | console.error('重试次数超过最大限制');
96 | if (notify) {
97 | $notification.post('步数更改失败', '重试次数超过最大限制', '请稍后再试');
98 | }
99 | $done();
100 | }
101 | } else {
102 | const jsonData = JSON.parse(data);
103 | console.log(`步数更新成功:${randomSteps.toString()}`, jsonData);
104 | if (notify) {
105 | $notification.post('Steps Update Successful', `Steps: ${randomSteps.toString()}`, '@YangMingyu', 'https://t.me/ymyuuu');
106 | }
107 | $done();
108 | }
109 | });
110 |
111 | const newData = `${account}@${password}@${maxSteps}@${minSteps}@${notify ? 'M' : 'N'}`;
112 | $persistentStore.write(newData, 'YangMingyu').then(() => {
113 | console.log('写入成功');
114 | }, () => {
115 | console.log('写入失败');
116 | });
117 | }
118 | }
119 |
120 | // 调用函数开始更新步数
121 | updateSteps();
122 |
--------------------------------------------------------------------------------
/JS/TF Account Management.js:
--------------------------------------------------------------------------------
1 | /********************************
2 | TestFlight账户管理脚本
3 |
4 | 主要功能:
5 | 1. 自动存储多个TestFlight账户,并自动合并APP列表,避免切换账户。
6 |
7 | 2. 账户内单个测试版APP允许多方共享:
8 | - 导出:点击测试版APP -> 底部开发者许可协议 -> 复制密钥并分享给对方
9 | - 导入:TestFlight 右上角"兑换" -> 粘贴密钥 -> 弹出保存成功通知后刷新APP列表
10 | - 多方共享为实验性功能,双方都需要使用该脚本; 该功能主要解决某些APP的TF名额稀缺的问题
11 |
12 | 请注意,该脚本已经与"TF区域限制解除脚本"合并,如需使用该脚本请务必禁用它,否则可能出现APP安装异常
13 | *********************************/
14 |
15 | const $ = API("TESTFLIGHT-ACCOUNT");
16 | $.env.isNode ? $request = $.read('Request') : null;
17 | const [arr, obj, req, rsp] = [[], new Map(), $request, {}];
18 | const [k1, k2, k3] = ['x-session-id', 'x-request-id', 'x-session-digest'];
19 | const [list, appList] = [$.read('AccountList') || {}, $.read('AppList') || {}];
20 | $.debug = $.read('Debug') === 'true';
21 |
22 | runs()
23 | .catch(e => $.error(e.error || e.message || e))
24 | .finally(() => {
25 | const ret = {
26 | ...{
27 | status: 200,
28 | headers: {
29 | 'Content-Type': 'application/json'
30 | }
31 | },
32 | ...rsp
33 | };
34 | ret.headers = formatHeaders(ret.headers); //compatible with HTTP/2
35 | ret.status = $.env.isQX ? `HTTP/1.1 ${ret.status}` : ret.status;
36 | delete ret.headers['content-length'];
37 | delete ret.headers['transfer-encoding']; //prevent issues in qx
38 | $.log(`Return to client: ${$.stringify(ret)}`);
39 | $.done($.env.isQX ? ret : {
40 | response: ret
41 | })
42 | });
43 |
44 | async function runs() {
45 | // Object.keys(list).map(a => delete list[a].only)
46 | req.headers = formatHeaders(req.headers); //compatible with HTTP/2
47 | const appID = req.url.split(/\/apps\/(\d+)/)[1];
48 | const build = req.url.split(/\/builds\/(\d+)/)[1];
49 | const other = /\/(accept|withdraw|devices|session|notifications|status)/.test(req.url);
50 | if (/accounts\/[a-z0-9-]{36}\/apps$/.test(req.url)) {
51 | const acc = SaveAccount(req.url.split(/\/([a-z0-9-]{36})\//)[1]);
52 | const all = await Promise.all(Object.keys(acc).map(QueryAppList));
53 | const out = arr.filter(r => !r.previouslyTested && !obj.has(r.appAdamId) && obj.set(r.appAdamId, 1));
54 | $.log(`Final app: ${$.stringify(out.map(i => i.name))}`);
55 | if (out.length) {
56 | rsp.body = $.stringify({
57 | data: out,
58 | error: null
59 | });
60 | $.write(out.reduce((l, v) => (l[v.appAdamId] = v.aid, l), {}), 'AppList');
61 | }
62 | } else if (/\/install$/.test(req.url) && req.body) {
63 | req.body = JSON.parse(req.body);
64 | req.body.storefrontId = '143441-19,29'; //prevent regional restrictions
65 | req.body = $.stringify(req.body);
66 | } else if (/\d+\/eula$/.test(req.url)) {
67 | rsp.body = $.stringify(ShareAccount(appID, build));
68 | } else if (/\/[A-Z]{200,}\/redeem$/.test(req.url)) {
69 | rsp.body = ExternalAccount(req.url.split(/\/([A-Z]+)\/redeem$/)[1]);
70 | }
71 | if (!rsp.body) {
72 | await QueryFallback(!other && appList[appID]);
73 | }
74 | }
75 |
76 | function SaveAccount(id, part, o) {
77 | if (!list[id]) {
78 | list[id] = {};
79 | const text = `Account ID "${id}" saved. (total ${Object.keys(list).length}) 🎉`;
80 | $.notify('TestFlight Account', '', text);
81 | $.info(text);
82 | };
83 | list[id][k1] = (part || req.headers)[k1];
84 | list[id][k2] = (part || req.headers)[k2];
85 | list[id][k3] = (part || req.headers)[k3];
86 | if (o) {
87 | if (list[id].only) {
88 | list[id].only.push(o);
89 | $.notify('TestFlight Account', '', `App ID "${o}" saved 🎉`);
90 | } else {
91 | list[id].only = [o];
92 | }
93 | }
94 | return $.write(list, 'AccountList'), list;
95 | }
96 |
97 | function formatHeaders(h) {
98 | return Object.keys(h).reduce((t, i) => (t[i.toLowerCase()] = h[i], t), {})
99 | }
100 |
101 | function ChangeHeaders(id) {
102 | const re = JSON.parse(JSON.stringify(req)); //easy deep copy
103 | if (id) {
104 | $.log(`Request header replaced, using "${id}"`);
105 | re.headers[k1] = list[id][k1];
106 | re.headers[k2] = list[id][k2];
107 | re.headers[k3] = list[id][k3];
108 | re.url = re.url.replace(/\/[a-z0-9-]{36}\//, `/${id}/`);
109 | }
110 | if (typeof $Shadowrocket !== 'undefined') {
111 | re.proxy = false; //prevent shadowrocket infinite loop
112 | }
113 | delete re.headers['if-none-match']; //prevent 304
114 | delete re.headers['content-length'];
115 | $.log(`Send request: ${$.stringify(re)}`);
116 | return re;
117 | }
118 |
119 | function QueryFallback(o) {
120 | return $.http[req.method.toLowerCase()](ChangeHeaders(o))
121 | .then(r => {
122 | $.log(`Received response: status=${r.statusCode}, body=${Boolean(r.body)}`);
123 | [rsp.status, rsp.headers, rsp.body] = [r.statusCode, r.headers, r.body];
124 | if (/\/apps\/\d+\/builds\/\d+$/.test(req.url) && r.body) { //beta app page
125 | r.body = JSON.parse(r.body);
126 | r.body.data.builds.map(e => e.eula = `https://testflight.apple.com/v1/apps/${e.appAdamId}/builds/${e.id}/eula`);
127 | rsp.body = $.stringify(r.body);
128 | }
129 | })
130 | .catch(e => $.error(`Response failed: ${e.error || e.message || e}`))
131 | }
132 |
133 | function QueryAppList(o) {
134 | return $.http[req.method.toLowerCase()](ChangeHeaders(o))
135 | .then(r => {
136 | const m = req.url.includes(o);
137 | $.log(`Received response: status=${r.statusCode}, body=${Boolean(r.body)}, account=${o}, main=${m}`);
138 | if (m) {
139 | [rsp.status, rsp.headers, rsp.body] = [r.statusCode, r.headers, r.body];
140 | }
141 | if (r.statusCode == 401) {
142 | throw new Error('Key expires');
143 | }
144 | const res = JSON.parse(r.body || '{}');
145 | $.log(`Account "${o}" app list: ${$.stringify((res.data || []).map(i => i.name))}`);
146 | return (res.data || []).filter(i => (i.aid = o, !list[o].only || list[o].only.includes(String(i.appAdamId))))
147 | .map(p => arr[m ? 'unshift' : 'push'](p))
148 | }).catch(e => { //surge cannot get 401 in apple domain
149 | if (/Key expires|NSURLErrorDomain.+?-1012/.test(e.error || e.message || e)) {
150 | if (list[o].InvalidKey >= 2) { //prevent misjudgment
151 | delete list[o];
152 | } else {
153 | list[o].InvalidKey = (list[o].InvalidKey || 0) + 1;
154 | }
155 | $.write(list, 'AccountList');
156 | e = `key expired ⚠️`;
157 | $.notify('TestFlight Account', '', `Account ID "${o}" ${e}`);
158 | };
159 | $.error(`Account "${o}" response failed: ${e.error || e.message || e}`);
160 | })
161 | }
162 |
163 | function ExternalAccount(key) {
164 | try {
165 | const k = JSON.parse(letterDecode(key));
166 | $.log(`Raw data: ${key}\nDecode data: ${$.stringify(k)}`);
167 | if (!k.appID || !k.accID || !k.key[k1] || !k.key[k2] || !k.key[k3]) {
168 | throw new Error('Missing data');
169 | } else if (appList[k.appID]) {
170 | $.notify('TestFlight Account', '', `Failed, app already exists ⚠️`);
171 | } else {
172 | const save = SaveAccount(k.accID, k.key, k.appID);
173 | }
174 | } catch (e) {
175 | const text = `External account parse failed`;
176 | $.notify('TestFlight Account', '', `${text} ⚠️`);
177 | $.error(`${text}: ${e.message || e}`);
178 | }
179 | return '{}'
180 | }
181 |
182 | function ShareAccount(appID, bid) {
183 | const raw = $.stringify({
184 | appID: appID,
185 | accID: appList[appID],
186 | key: list[appList[appID]]
187 | });
188 | const key = letterEncode(raw);
189 | const disclaimer = `
190 | 权限:
191 | 您即将共享的密钥理论上具有以下权限,包括但不限于:
192 |
193 | - 查看/下载您 TestFlight 账号内的任何测试版 APP
194 | - 使用您的密钥接受测试 TestFlight 中的任何测试版 APP
195 | - 停止测试您 TestFlight 账号内的任何测试版 APP
196 | - 查看您接受 TestFlight 测试版 APP 邀请时所使用的邮箱
197 | - 查看/加入/移除您 TestFlight 账号中的设备列表
198 | - 更改您 TestFlight 测试版 APP 中的推送/电子邮件更新通知
199 |
200 | 该脚本在"默认"情况下,对方仅可查看/下载您共享的单个APP,但仍建议仅与您信任的人共享:
201 |
202 | `;
203 | $.log(`Raw data: ${raw}\nEncode data: ${key}`);
204 | return {
205 | data: {
206 | buildId: bid,
207 | eula: disclaimer + key
208 | },
209 | messages: null
210 | }
211 | }
212 |
213 | // private encode method, based on variant in RFC4648
214 | function letterEncode(e) {
215 | e = e.split("").map(e => e.charCodeAt());
216 | const t = new Uint8Array(4 * Math.ceil(8 * e.length / 4));
217 | let n = 0;
218 | for (const o of e) {
219 | let e = 128;
220 | for (let r = 0; r < 8; r++) t[n++] = o & e ? 1 : 0, e >>= 1
221 | }
222 | let o = "",
223 | r = 0;
224 | return t.forEach((e, t) => {
225 | r = r << 1 | e, (t + 1) % 4 == 0 && (o += "XKNWSPRMCTGZVDHF"[r], r = 0)
226 | }), o
227 | }
228 |
229 | function letterDecode(e) {
230 | const t = new Uint8Array(4 * e.length);
231 | let n = 0;
232 | for (const o of e) {
233 | const e = "XKNWSPRMCTGZVDHF".indexOf(o);
234 | let r = 8;
235 | for (let o = 0; o < 4; o++) t[n++] = e & r ? 1 : 0, r >>= 1
236 | }
237 | const o = new Uint8Array(Math.floor(t.length / 8));
238 | return t.forEach((e, t) => {
239 | const n = Math.floor(t / 8);
240 | n < o.length && (o[n] = o[n] << 1 | e)
241 | }), String.fromCharCode(...o)
242 | }
243 |
244 | // https://github.com/Peng-YM/QuanX/tree/master/Tools/OpenAPI
245 | 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: "" }) { const { isQX: t, isLoon: s, isSurge: o, isScriptable: n, isNode: i, isBrowser: r } = ENV(), u = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/; const a = {}; return ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH"].forEach(h => a[h.toLowerCase()] = (a => (function (a, h) { h = "string" == typeof h ? { url: h } : h; const d = e.baseURL; d && !u.test(h.url || "") && (h.url = d ? d + h.url : h.url), h.body && h.headers; const l = (h = { ...e, ...h }).timeout, c = { onRequest: () => { }, onResponse: e => e, onTimeout: () => { }, ...h.events }; let f, p; if (c.onRequest(a, h), t) f = $task.fetch({ method: a, ...h }); else if (s || o || i) f = new Promise((e, t) => { (i ? require("request") : $httpClient)[a.toLowerCase()](h, (s, o, n) => { s ? t(s) : e({ statusCode: o.status || o.statusCode, headers: o.headers, body: n }) }) }); else if (n) { const e = new Request(h.url); e.method = a, e.headers = h.headers, e.body = h.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 r && (f = new Promise((e, t) => { fetch(h.url, { method: a, headers: h.headers, body: h.body }).then(e => e.json()).then(t => e({ statusCode: t.status, headers: t.headers, body: t.data })).catch(t) })); const y = l ? new Promise((e, t) => { p = setTimeout(() => (c.onTimeout(), t(`${a} URL: ${h.url} exceeds the timeout ${l} ms`)), l) }) : null; return (y ? Promise.race([y, f]).then(e => (clearTimeout(p), e)) : f).then(e => c.onResponse(e)) })(h, a))), a } 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) { return { fs: require("fs") } } return null })(), this.initCache(); Promise.prototype.delay = function (e) { return this.then(function (t) { return ((e, t) => new Promise(function (s) { setTimeout(s.bind(null, t), e) }))(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 = "", h = {}) { const d = h["open-url"], l = h["media-url"]; if (s && $notify(e, t, a, h), n && $notification.post(e, t, a + `${l ? "\n多媒体:" + l : ""}`, { url: d }), o) { let s = {}; d && (s.openUrl = d), l && (s.mediaUrl = l), "{}" === JSON.stringify(s) ? $notification.post(e, t, a) : $notification.post(e, t, a, s) } if (i || u) { const s = a + (d ? `\n点击跳转: ${d}` : "") + (l ? `\n多媒体: ${l}` : ""); if (r) { require("push").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) }
246 |
--------------------------------------------------------------------------------
/JS/TF Detection.js:
--------------------------------------------------------------------------------
1 | const title = 'TF Detection'
2 | const $ = new Env('TF Detection')
3 |
4 | /**
5 | * 填入要监测的appkey,从testfligt地址获取
6 | * 例如"VCIvwk2g/wArXdacJ/2vnRvOTX/LzjySbQx/IdFRwmNy/qDkBu2ur/4Qt2lIm5/ZzqOu8tX/ftCqFe6F/fy7LvHVA/QKqitFwc"
7 | */
8 | const appkey = $.getdata('appkey')
9 |
10 | // 是否通知未检测到的appkey,默认为是(true)
11 | const isNotify = $.getdata('是否通知未检测到的appkey') === '是'
12 |
13 | // 是否删除已检测到的appkey,默认为不删除(false)
14 | const shouldDeleteKeys = $.getdata('是否删除已检测到的appkey') === '是'
15 |
16 | !(async () => {
17 | let result = []
18 | let apps = appkey.split('/') // 使用斜杠进行分割
19 | for await (const app of apps) {
20 | const p = await doRequest(app)
21 | result.push(p)
22 | }
23 | await doNotify(result)
24 |
25 | if (shouldDeleteKeys) {
26 | deleteDetectedKeys(result)
27 | }
28 |
29 | function doRequest(app) {
30 | const url = 'https://testflight.apple.com/join/'
31 | const fullstr =
32 | /版本的测试员已满|此Beta版本目前不接受任何新测试员|Not Found|This beta is full|This beta isn't accepting any new testers right now/
33 | const appNameReg = /Join the (.+) beta - TestFlight - Apple/
34 | const appNameRegCh = /加入 Beta 版“(.+)” - TestFlight - Apple/
35 | let req = {
36 | url: url + app,
37 | headers: {
38 | 'User-Agent':
39 | '[{"key":"User-Agent","value":" Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2357.130 Safari/537.36 qblink wegame.exe QBCore/3.70.66.400 QQBrowser/9.0.2524.400","type":"text","enabled":true,"description":""},{"key":"X-Requested-With","value":" XMLHttpRequest","type":"text","enabled":false,"description":""}]'
40 | }
41 | }
42 | return new Promise(function (resolve) {
43 | $.get(req, (error, response, data) => {
44 | let result = {}
45 | let dataStr = JSON.stringify(data)
46 | let appName
47 | if (appNameReg.test(dataStr)) {
48 | appName = dataStr.match(appNameReg)
49 | } else if (appNameRegCh.test(dataStr)) {
50 | appName = dataStr.match(appNameRegCh)
51 | } else {
52 | resolve(result)
53 | return
54 | }
55 | let name = appName[1]
56 | if (!fullstr.test(dataStr)) {
57 | result[name] = {
58 | has: true,
59 | context: '🈶️👆点击立刻跳转TestFlight'
60 | }
61 | } else {
62 | result[name] = {
63 | has: false,
64 | context: '🈚️👆'
65 | }
66 | }
67 | resolve(result)
68 | })
69 | })
70 | }
71 |
72 | function doNotify(res) {
73 | return Promise.all(res).then((results) => {
74 | $.log(JSON.stringify(results))
75 | for (let i in results) {
76 | let result = results[i]
77 | if (JSON.stringify(result) == '{}') {
78 | continue
79 | }
80 | for (name in result) {
81 | let has = result[name].has
82 | if (has) {
83 | let hastr =
84 | '[' + name + ']' + '\n' + result[name].context
85 | $.msg('TF Detection', '', hastr, { openUrl: 'https://testflight.apple.com/join/' + apps[i] })
86 | } else {
87 | let nostr =
88 | '[' + name + ']' + '\n' + result[name].context
89 | if (isNotify) {
90 | $.msg('TF Detection', '', nostr)
91 | } else {
92 | $.log('TF Detection', '', nostr)
93 | }
94 | }
95 | }
96 | }
97 | })
98 | }
99 |
100 | function deleteDetectedKeys(res) {
101 | let detectedKeys = []
102 | for (let i in res) {
103 | let result = res[i]
104 | if (JSON.stringify(result) == '{}') {
105 | continue
106 | }
107 | for (name in result) {
108 | let has = result[name].has
109 | if (has) {
110 | detectedKeys.push(apps[i])
111 | }
112 | }
113 | }
114 | if (detectedKeys.length > 0) {
115 | let updatedAppKeys = appkey
116 | for (let i in detectedKeys) {
117 | updatedAppKeys = updatedAppKeys.replace(detectedKeys[i], '')
118 | }
119 | $.setdata(updatedAppKeys, 'appkey')
120 | }
121 | }
122 | })()
123 | .catch((e) => $.logErr(e))
124 | .finally(() => $.done())
125 |
126 |
127 |
128 |
129 | // prettier-ignore
130 | 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.encoding="utf-8",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}isShadowrocket(){return"undefined"!=typeof $rocket}isStash(){return"undefined"!=typeof $environment&&$environment["stash-version"]}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,a]=i.split("@"),n={url:`http://${a}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(n,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),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),a=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(a);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=(()=>{})){if(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?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(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&&t.error||"UndefinedError"));else if(this.isNode()){let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:i,statusCode:r,headers:o,rawBody:a}=t,n=s.decode(a,this.encoding);e(null,{status:i,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:i,response:r}=t;e(i,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";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[s](t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,i)});else if(this.isQuanX())t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t&&t.error||"UndefinedError"));else if(this.isNode()){let i=require("iconv-lite");this.initGotEnv(t);const{url:r,...o}=t;this.got[s](r,o).then(t=>{const{statusCode:s,statusCode:r,headers:o,rawBody:a}=t,n=i.decode(a,this.encoding);e(null,{status:s,statusCode:r,headers:o,rawBody:a,body:n},n)},t=>{const{message:s,response:r}=t;e(s,r,r&&i.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}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,i=t["update-pasteboard"]||t.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":i}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}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):this.isNode()&&process.exit(1)}}(t,e)}
131 |
--------------------------------------------------------------------------------
/JS/TF relief area.js:
--------------------------------------------------------------------------------
1 | let app = JSON.parse($request.body);
2 | app.storefrontId = '143441-19,29';
3 | $done({body:JSON.stringify(app)});
4 |
--------------------------------------------------------------------------------
/JS/ZiyiSteps.js:
--------------------------------------------------------------------------------
1 | const maxRunCount = 10; // 最大运行次数
2 | let runCount = 0; // 运行次数计数器
3 |
4 | function updateSteps() {
5 | runCount++; // 增加运行次数计数器
6 |
7 | console.log(`正在运行第 ${runCount} 次`);
8 |
9 | const savedData = $persistentStore.read('Ziyi');
10 | if (savedData) {
11 | const [savedAccount, savedPassword, savedMaxSteps, savedMinSteps, notifyOption] = savedData.split('@');
12 | if (savedAccount && savedPassword && savedMaxSteps && savedMinSteps && notifyOption) {
13 | account = savedAccount;
14 | password = savedPassword;
15 | maxSteps = parseInt(savedMaxSteps);
16 | minSteps = parseInt(savedMinSteps);
17 | notify = notifyOption === 'M';
18 | }
19 | }
20 |
21 | // 判断账号密码最大步数最小步数是否存在
22 | if (!account || !password || !maxSteps || !minSteps) {
23 | console.log('缺少必要信息');
24 | if (notify) {
25 | $notification.post('步数更改失败', '缺少必要信息', '请检查账号、密码、最大步数和最小步数');
26 | }
27 | $done();
28 | return;
29 | }
30 |
31 | // 判断最大步数和最小步数是否超限
32 | if (maxSteps > 98000 || minSteps > 98000) {
33 | console.log('最大步数和最小步数不能超过98000');
34 | if (notify) {
35 | $notification.post('步数更改失败', '最大步数和最小步数不能超过98000', '请检查最大步数和最小步数');
36 | }
37 | $done();
38 | return;
39 | } else if (maxSteps < minSteps) {
40 | console.log('最大步数不能小于最小步数');
41 | if (notify) {
42 | $notification.post('步数更改失败', '最大步数不能小于最小步数', '请检查最大步数和最小步数');
43 | }
44 | $done();
45 | return;
46 | } else if (minSteps > maxSteps) {
47 | console.log('最小步数不能大于最大步数');
48 | if (notify) {
49 | $notification.post('步数更改失败', '最小步数不能大于最大步数', '请检查最大步数和最小步数');
50 | }
51 | $done();
52 | return;
53 | }
54 |
55 | const randomSteps = Math.floor(Math.random() * (maxSteps - minSteps + 1)) + minSteps;
56 |
57 | const url = 'http://bs.svv.ink/index.php';
58 |
59 | const request = {
60 | url: url,
61 | method: 'POST',
62 | headers: {
63 | 'Content-Type': 'application/x-www-form-urlencoded',
64 | 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1',
65 | },
66 | body: `account=${account}&password=${password}&steps=${randomSteps}&max_steps=${maxSteps}&min_steps=${minSteps}`,
67 | };
68 |
69 | $httpClient.post(request, function (error, response, data) {
70 | if (error || response.status !== 200) {
71 | console.log('请求失败:', error || response.status);
72 | // 检查是否达到最大运行次数
73 | if (runCount < maxRunCount) {
74 | // 在下一次运行前添加延迟
75 | setTimeout(updateSteps, 5000); // 在下一次运行前等待5秒
76 | } else {
77 | console.log('已达到最大运行次数');
78 | if (notify) {
79 | $notification.post('步数更改失败', '已达到最大运行次数', '请稍后再试');
80 | }
81 | }
82 | return;
83 | }
84 |
85 | const jsonData = JSON.parse(data);
86 | console.log(`步数更新成功:${randomSteps.toString()}`, jsonData);
87 | if (notify) {
88 | $notification.post('Steps Update Successful', `Steps: ${randomSteps.toString()}`, '@ZhangZiyi', 'https://t.me/ymyuuu');
89 | }
90 | });
91 |
92 | const newData = `${account}@${password}@${maxSteps}@${minSteps}@${notify ? 'M' : 'N'}`;
93 | $persistentStore.write(newData, 'YangMingyu').then(() => {
94 | console.log('写入成功');
95 | }, () => {
96 | console.log('写入失败');
97 | });
98 |
99 | if (runCount < maxRunCount) {
100 | // 在下一次运行前添加延迟
101 | setTimeout(updateSteps, 5000); // 在下一次运行前等待5秒
102 | } else {
103 | console.log('已达到最大运行次数');
104 | if (notify) {
105 | $notification.post('步数更改失败', '已达到最大运行次数', '请稍后再试');
106 | }
107 | }
108 | }
109 |
110 | // 调用函数开始更新步数
111 | updateSteps();
112 |
--------------------------------------------------------------------------------
/JS/atoken.js:
--------------------------------------------------------------------------------
1 | /*
2 | 阿里云盘签到-lowking-v1.1.0
3 |
4 | 按下面配置完之后,打开阿里云盘获取token(如获取不到,等一段时间再打开),下面配置只验证过surge的,其他的自行测试
5 | ⚠️只测试过surge没有其他app自行测试
6 |
7 | ************************
8 | Surge 4.2.0+ 脚本配置(其他APP自行转换配置):
9 | ************************
10 |
11 | [Script]
12 | # > 阿里云盘签到
13 | https://auth.aliyundrive.com/v2/account/token
14 | 阿里云盘签到cookie = requires-body=1,type=http-response,pattern=https:\/\/auth.aliyundrive.com\/v2\/account\/token,script-path=https://raw.githubusercontent.com/lowking/Scripts/master/ali/aliYunPanCheckIn.js
15 | 阿里云盘签到 = type=cron,cronexp="0 10 0 * * ?",wake-system=1,script-path=https://raw.githubusercontent.com/lowking/Scripts/master/ali/aliYunPanCheckIn.js
16 |
17 | [MITM]
18 | hostname = %APPEND% auth.aliyundrive.com
19 | */
20 | const lk = new ToolKit(`阿里云盘签到`, `AliYunPanCheckIn`, {"httpApi": "ffff@10.0.0.19:6166"})
21 | const aliYunPanTokenKey = 'lkAliYunPanTokenKey'
22 | let aliYunPanToken = lk.getVal(aliYunPanTokenKey, '')
23 | const aliYunPanRefreshTokenKey = 'lkAliYunPanRefreshTokenKey'
24 | let aliYunPanRefreshToken = lk.getVal(aliYunPanRefreshTokenKey, '')
25 | const checkSignInRepeatKey = 'aliYunPanSignInRepeat'
26 | const checkSignInRepeat = lk.getVal(checkSignInRepeatKey, '')
27 | const joinTeamRepeatKey = 'aliYunPanJoinTeamRepeat'
28 | const joinTeamRepeat = lk.getVal(joinTeamRepeatKey, -1)
29 | lk.userAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 15_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 D/C501C6D2-FAF6-4DA8-B65B-7B8B392901EB"
30 |
31 | if(!lk.isExecComm) {
32 | if (lk.isRequest()) {
33 | getCookie()
34 | lk.done()
35 | } else {
36 | lk.boxJsJsonBuilder({
37 | "icons": [
38 | "https://raw.githubusercontent.com/lowking/Scripts/master/doc/icon/aliYunPana.png",
39 | "https://raw.githubusercontent.com/lowking/Scripts/master/doc/icon/aliYunPan.png"
40 | ],
41 | "settings": [
42 | {
43 | "id": aliYunPanTokenKey,
44 | "name": "阿里云盘token",
45 | "val": "",
46 | "type": "text",
47 | "desc": "阿里云盘token"
48 | }, {
49 | "id": aliYunPanRefreshTokenKey,
50 | "name": "阿里云盘refresh_token",
51 | "val": "",
52 | "type": "text",
53 | "desc": "阿里云盘refresh_token"
54 | }
55 | ],
56 | "keys": [aliYunPanTokenKey, aliYunPanRefreshTokenKey]
57 | }, {
58 | "script_url": "https://github.com/lowking/Scripts/blob/master/ali/aliYunPanCheckIn.js",
59 | "author": "@lowking",
60 | "repo": "https://github.com/lowking/Scripts",
61 | })
62 | all()
63 | }
64 | }
65 |
66 | function getCookie() {
67 | if (lk.isGetCookie(/\/v2\/account\/token/)) {
68 | lk.log(`开始获取cookie`)
69 | let data = lk.getResponseBody()
70 | // lk.log(`获取到的cookie:${data}`)
71 | try {
72 | data = JSON.parse(data)
73 | let refreshToken = data["refresh_token"]
74 | if (refreshToken) {
75 | lk.setVal(aliYunPanRefreshTokenKey, refreshToken)
76 | lk.appendNotifyInfo('🎉成功获取阿里云盘refresh_token,可以关闭相应脚本')
77 | } else {
78 | lk.execFail()
79 | lk.appendNotifyInfo('❌获取阿里云盘token失败,请稍后再试')
80 | }
81 | } catch (e) {
82 | lk.execFail()
83 | lk.appendNotifyInfo('❌获取阿里云盘token失败')
84 | }
85 | lk.msg('')
86 | }
87 | }
88 |
89 |
90 |
91 | //ToolKit-start
92 | function ToolKit(t,s,i){return new class{constructor(t,s,i){this.tgEscapeCharMapping={"&":"&","#":"#"};this.userAgent=`Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.2 Safari/605.1.15`;this.prefix=`lk`;this.name=t;this.id=s;this.data=null;this.dataFile=this.getRealPath(`${this.prefix}${this.id}.dat`);this.boxJsJsonFile=this.getRealPath(`${this.prefix}${this.id}.boxjs.json`);this.options=i;this.isExecComm=false;this.isEnableLog=this.getVal(`${this.prefix}IsEnableLog${this.id}`);this.isEnableLog=this.isEmpty(this.isEnableLog)?true:JSON.parse(this.isEnableLog);this.isNotifyOnlyFail=this.getVal(`${this.prefix}NotifyOnlyFail${this.id}`);this.isNotifyOnlyFail=this.isEmpty(this.isNotifyOnlyFail)?false:JSON.parse(this.isNotifyOnlyFail);this.isEnableTgNotify=this.getVal(`${this.prefix}IsEnableTgNotify${this.id}`);this.isEnableTgNotify=this.isEmpty(this.isEnableTgNotify)?false:JSON.parse(this.isEnableTgNotify);this.tgNotifyUrl=this.getVal(`${this.prefix}TgNotifyUrl${this.id}`);this.isEnableTgNotify=this.isEnableTgNotify?!this.isEmpty(this.tgNotifyUrl):this.isEnableTgNotify;this.costTotalStringKey=`${this.prefix}CostTotalString${this.id}`;this.costTotalString=this.getVal(this.costTotalStringKey);this.costTotalString=this.isEmpty(this.costTotalString)?`0,0`:this.costTotalString.replace('"',"");this.costTotalMs=this.costTotalString.split(",")[0];this.execCount=this.costTotalString.split(",")[1];this.costTotalMs=this.isEmpty(this.costTotalMs)?0:parseInt(this.costTotalMs);this.execCount=this.isEmpty(this.execCount)?0:parseInt(this.execCount);this.logSeparator="\n██";this.now=new Date;this.startTime=this.now.getTime();this.node=(()=>{if(this.isNode()){const t=require("request");return{request:t}}else{return null}})();this.execStatus=true;this.notifyInfo=[];this.log(`${this.name}, 开始执行!`);this.execComm()}getRealPath(t){if(this.isNode()){let s=process.argv.slice(1,2)[0].split("/");s[s.length-1]=t;return s.join("/")}return t}async execComm(){if(this.isNode()){this.comm=process.argv.slice(1);let t=false;if(this.comm[1]=="p"){this.isExecComm=true;this.log(`开始执行指令【${this.comm[1]}】=> 发送到手机测试脚本!`);if(this.isEmpty(this.options)||this.isEmpty(this.options.httpApi)){this.log(`未设置options,使用默认值`);if(this.isEmpty(this.options)){this.options={}}this.options.httpApi=`ffff@10.0.0.9:6166`}else{if(!/.*?@.*?:[0-9]+/.test(this.options.httpApi)){t=true;this.log(`❌httpApi格式错误!格式:ffff@3.3.3.18:6166`);this.done()}}if(!t){this.callApi(this.comm[2])}}}}callApi(t){let s=this.comm[0];this.log(`获取【${s}】内容传给手机`);let i="";this.fs=this.fs?this.fs:require("fs");this.path=this.path?this.path:require("path");const e=this.path.resolve(s);const o=this.path.resolve(process.cwd(),s);const h=this.fs.existsSync(e);const r=!h&&this.fs.existsSync(o);if(h||r){const t=h?e:o;try{i=this.fs.readFileSync(t)}catch(t){i=""}}else{i=""}let n={url:`http://${this.options.httpApi.split("@")[1]}/v1/scripting/evaluate`,headers:{"X-Key":`${this.options.httpApi.split("@")[0]}`},body:{script_text:`${i}`,mock_type:"cron",timeout:!this.isEmpty(t)&&t>5?t:5},json:true};this.post(n,(t,i,e)=>{this.log(`已将脚本【${s}】发给手机!`);this.done()})}getCallerFileNameAndLine(){let t;try{throw Error("")}catch(s){t=s}const s=t.stack;const i=s.split("\n");let e=1;if(e!==0){const t=i[e];this.path=this.path?this.path:require("path");return`[${t.substring(t.lastIndexOf(this.path.sep)+1,t.lastIndexOf(":"))}]`}else{return"[-]"}}getFunName(t){var s=t.toString();s=s.substr("function ".length);s=s.substr(0,s.indexOf("("));return s}boxJsJsonBuilder(t,s){if(this.isNode()){let i="/Users/lowking/Desktop/Scripts/lowking.boxjs.json";if(s&&s.hasOwnProperty("target_boxjs_json_path")){i=s["target_boxjs_json_path"]}if(!this.fs.existsSync(i)){return}if(!this.isJsonObject(t)||!this.isJsonObject(s)){this.log("构建BoxJsJson传入参数格式错误,请传入json对象");return}this.log("using node");let e=["settings","keys"];const o="https://raw.githubusercontent.com/Orz-3";let h={};let r="#lk{script_url}";if(s&&s.hasOwnProperty("script_url")){r=this.isEmpty(s["script_url"])?"#lk{script_url}":s["script_url"]}h.id=`${this.prefix}${this.id}`;h.name=this.name;h.desc_html=`⚠️使用说明详情【点我查看】`;h.icons=[`${o}/mini/master/Alpha/${this.id.toLocaleLowerCase()}.png`,`${o}/mini/master/Color/${this.id.toLocaleLowerCase()}.png`];h.keys=[];h.settings=[{id:`${this.prefix}IsEnableLog${this.id}`,name:"开启/关闭日志",val:true,type:"boolean",desc:"默认开启"},{id:`${this.prefix}NotifyOnlyFail${this.id}`,name:"只当执行失败才通知",val:false,type:"boolean",desc:"默认关闭"},{id:`${this.prefix}IsEnableTgNotify${this.id}`,name:"开启/关闭Telegram通知",val:false,type:"boolean",desc:"默认关闭"},{id:`${this.prefix}TgNotifyUrl${this.id}`,name:"Telegram通知地址",val:"",type:"text",desc:"Tg的通知地址,如:https://api.telegram.org/bot-token/sendMessage?chat_id=-100140&parse_mode=Markdown&text="}];h.author="#lk{author}";h.repo="#lk{repo}";h.script=`${r}?raw=true`;if(!this.isEmpty(t)){for(let s in e){let i=e[s];if(!this.isEmpty(t[i])){if(i==="settings"){for(let s=0;s0){let t=a.apps;let e=t.indexOf(t.filter(t=>{return t.id==h.id})[0]);if(e>=0){a.apps[e]=h}else{a.apps.push(h)}let o=JSON.stringify(a,null,2);if(!this.isEmpty(s)){for(const t in s){let i="";if(s.hasOwnProperty(t)){i=s[t]}else if(t==="author"){i="@lowking"}else if(t==="repo"){i="https://github.com/lowking/Scripts"}o=o.replace(`#lk{${t}}`,i)}}const r=/(?:#lk\{)(.+?)(?=\})/;let n=r.exec(o);if(n!==null){this.log(`生成BoxJs还有未配置的参数,请参考https://github.com/lowking/Scripts/blob/master/util/example/ToolKitDemo.js#L17-L18传入参数:\n`)}let l=new Set;while((n=r.exec(o))!==null){l.add(n[1]);o=o.replace(`#lk{${n[1]}}`,``)}l.forEach(t=>{console.log(`${t} `)});this.fs.writeFileSync(i,o)}}}}isJsonObject(t){return typeof t=="object"&&Object.prototype.toString.call(t).toLowerCase()=="[object object]"&&!t.length}appendNotifyInfo(t,s){if(s==1){this.notifyInfo=t}else{this.notifyInfo.push(t)}}prependNotifyInfo(t){this.notifyInfo.splice(0,0,t)}execFail(){this.execStatus=false}isRequest(){return typeof $request!="undefined"}isSurge(){return typeof $httpClient!="undefined"}isQuanX(){return typeof $task!="undefined"}isLoon(){return typeof $loon!="undefined"}isJSBox(){return typeof $app!="undefined"&&typeof $http!="undefined"}isStash(){return"undefined"!==typeof $environment&&$environment["stash-version"]}isNode(){return typeof require=="function"&&!this.isJSBox()}sleep(t){return new Promise(s=>setTimeout(s,t))}log(t){if(this.isEnableLog)console.log(`${this.logSeparator}${t}`)}logErr(t){this.execStatus=true;if(this.isEnableLog){console.log(`${this.logSeparator}${this.name}执行异常:`);console.log(t);console.log(`\n${t.message}`)}}msg(t,s,i,e){if(!this.isRequest()&&this.isNotifyOnlyFail&&this.execStatus){}else{if(this.isEmpty(s)){if(Array.isArray(this.notifyInfo)){s=this.notifyInfo.join("\n")}else{s=this.notifyInfo}}if(!this.isEmpty(s)){if(this.isEnableTgNotify){this.log(`${this.name}Tg通知开始`);for(let t in this.tgEscapeCharMapping){if(!this.tgEscapeCharMapping.hasOwnProperty(t)){continue}s=s.replace(t,this.tgEscapeCharMapping[t])}this.get({url:encodeURI(`${this.tgNotifyUrl}📌${this.name}\n${s}`)},(t,s,i)=>{this.log(`Tg通知完毕`)})}else{let o={};const h=!this.isEmpty(i);const r=!this.isEmpty(e);if(this.isQuanX()){if(h)o["open-url"]=i;if(r)o["media-url"]=e;$notify(this.name,t,s,o)}if(this.isSurge()||this.isStash()){if(h)o["url"]=i;$notification.post(this.name,t,s,o)}if(this.isNode())this.log("⭐️"+this.name+"\n"+t+"\n"+s);if(this.isJSBox())$push.schedule({title:this.name,body:t?t+"\n"+s:s})}}}}getVal(t,s=""){let i;if(this.isSurge()||this.isLoon()||this.isStash()){i=$persistentStore.read(t)}else if(this.isQuanX()){i=$prefs.valueForKey(t)}else if(this.isNode()){this.data=this.loadData();i=process.env[t]||this.data[t]}else{i=this.data&&this.data[t]||null}return!i?s:i}setVal(t,s){if(this.isSurge()||this.isLoon()||this.isStash()){return $persistentStore.write(s,t)}else if(this.isQuanX()){return $prefs.setValueForKey(s,t)}else if(this.isNode()){this.data=this.loadData();this.data[t]=s;this.writeData();return true}else{return this.data&&this.data[t]||null}}loadData(){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);const s=this.path.resolve(process.cwd(),this.dataFile);const i=this.fs.existsSync(t);const e=!i&&this.fs.existsSync(s);if(i||e){const e=i?t:s;try{return JSON.parse(this.fs.readFileSync(e))}catch(t){return{}}}else return{}}else 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);const s=this.path.resolve(process.cwd(),this.dataFile);const i=this.fs.existsSync(t);const e=!i&&this.fs.existsSync(s);const o=JSON.stringify(this.data);if(i){this.fs.writeFileSync(t,o)}else if(e){this.fs.writeFileSync(s,o)}else{this.fs.writeFileSync(t,o)}}}adapterStatus(t){if(t){if(t.status){t["statusCode"]=t.status}else if(t.statusCode){t["status"]=t.statusCode}}return t}get(t,s=(()=>{})){if(this.isQuanX()){if(typeof t=="string")t={url:t};t["method"]="GET";$task.fetch(t).then(t=>{s(null,this.adapterStatus(t),t.body)},t=>s(t.error,null,null))}if(this.isSurge()||this.isLoon()||this.isStash())$httpClient.get(t,(t,i,e)=>{s(t,this.adapterStatus(i),e)});if(this.isNode()){this.node.request(t,(t,i,e)=>{s(t,this.adapterStatus(i),e)})}if(this.isJSBox()){if(typeof t=="string")t={url:t};t["header"]=t["headers"];t["handler"]=function(t){let i=t.error;if(i)i=JSON.stringify(t.error);let e=t.data;if(typeof e=="object")e=JSON.stringify(t.data);s(i,this.adapterStatus(t.response),e)};$http.get(t)}}post(t,s=(()=>{})){if(this.isQuanX()){if(typeof t=="string")t={url:t};t["method"]="POST";$task.fetch(t).then(t=>{s(null,this.adapterStatus(t),t.body)},t=>s(t.error,null,null))}if(this.isSurge()||this.isLoon()||this.isStash()){$httpClient.post(t,(t,i,e)=>{s(t,this.adapterStatus(i),e)})}if(this.isNode()){this.node.request.post(t,(t,i,e)=>{s(t,this.adapterStatus(i),e)})}if(this.isJSBox()){if(typeof t=="string")t={url:t};t["header"]=t["headers"];t["handler"]=function(t){let i=t.error;if(i)i=JSON.stringify(t.error);let e=t.data;if(typeof e=="object")e=JSON.stringify(t.data);s(i,this.adapterStatus(t.response),e)};$http.post(t)}}put(t,s=(()=>{})){if(this.isQuanX()){if(typeof t=="string")t={url:t};t["method"]="PUT";$task.fetch(t).then(t=>{s(null,this.adapterStatus(t),t.body)},t=>s(t.error,null,null))}if(this.isSurge()||this.isLoon()||this.isStash()){t.method="PUT";$httpClient.put(t,(t,i,e)=>{s(t,this.adapterStatus(i),e)})}if(this.isNode()){t.method="PUT";this.node.request.put(t,(t,i,e)=>{s(t,this.adapterStatus(i),e)})}if(this.isJSBox()){if(typeof t=="string")t={url:t};t["header"]=t["headers"];t["handler"]=function(t){let i=t.error;if(i)i=JSON.stringify(t.error);let e=t.data;if(typeof e=="object")e=JSON.stringify(t.data);s(i,this.adapterStatus(t.response),e)};$http.post(t)}}costTime(){let t=`${this.name}执行完毕!`;if(this.isNode()&&this.isExecComm){t=`指令【${this.comm[1]}】执行完毕!`}const s=(new Date).getTime();const i=s-this.startTime;const e=i/1e3;this.execCount++;this.costTotalMs+=i;this.log(`${t}耗时【${e}】秒\n总共执行【${this.execCount}】次,平均耗时【${(this.costTotalMs/this.execCount/1e3).toFixed(4)}】秒`);this.setVal(this.costTotalStringKey,JSON.stringify(`${this.costTotalMs},${this.execCount}`))}done(t={}){this.costTime();if(this.isSurge()||this.isQuanX()||this.isLoon()||this.isStash()){$done(t)}}getRequestUrl(){return $request.url}getResponseBody(){return $response.body}isGetCookie(t){return!!($request.method!="OPTIONS"&&this.getRequestUrl().match(t))}isEmpty(t){return typeof t=="undefined"||t==null||t==""||t=="null"||t=="undefined"||t.length===0}randomString(t){t=t||32;var s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";var i=s.length;var e="";for(let o=0;o>
16 | (-0x2 * _0x184fb6 & 0x6)) : 0x0) {
17 | _0x5e2bbc = _0x2c72b8['indexOf'](_0x5e2bbc);
18 | }
19 | for (let _0x426a59 = 0x0, _0x2fc977 = _0x5f5bfa['length']; _0x426a59 < _0x2fc977; _0x426a59++) {
20 | _0x15d75a += '%' + ('00' + _0x5f5bfa['charCodeAt'](_0x426a59)['toString'](0x10))['slice'](-
21 | 0x2);
22 | }
23 | return decodeURIComponent(_0x15d75a);
24 | };
25 | const _0x4d7b07 = function(_0xd8f653, _0x421714) {
26 | let _0x253fb1 = [],
27 | _0xa83900 = 0x0,
28 | _0x11a2c4, _0x136df9 = '';
29 | _0xd8f653 = _0x458204(_0xd8f653);
30 | let _0x3aafa6;
31 | for (_0x3aafa6 = 0x0; _0x3aafa6 < 0x100; _0x3aafa6++) {
32 | _0x253fb1[_0x3aafa6] = _0x3aafa6;
33 | }
34 | for (_0x3aafa6 = 0x0; _0x3aafa6 < 0x100; _0x3aafa6++) {
35 | _0xa83900 = (_0xa83900 + _0x253fb1[_0x3aafa6] + _0x421714['charCodeAt'](_0x3aafa6 %
36 | _0x421714['length'])) % 0x100, _0x11a2c4 = _0x253fb1[_0x3aafa6], _0x253fb1[
37 | _0x3aafa6] = _0x253fb1[_0xa83900], _0x253fb1[_0xa83900] = _0x11a2c4;
38 | }
39 | _0x3aafa6 = 0x0, _0xa83900 = 0x0;
40 | for (let _0x2b0f05 = 0x0; _0x2b0f05 < _0xd8f653['length']; _0x2b0f05++) {
41 | _0x3aafa6 = (_0x3aafa6 + 0x1) % 0x100, _0xa83900 = (_0xa83900 + _0x253fb1[_0x3aafa6]) %
42 | 0x100, _0x11a2c4 = _0x253fb1[_0x3aafa6], _0x253fb1[_0x3aafa6] = _0x253fb1[_0xa83900],
43 | _0x253fb1[_0xa83900] = _0x11a2c4, _0x136df9 += String['fromCharCode'](_0xd8f653[
44 | 'charCodeAt'](_0x2b0f05) ^ _0x253fb1[(_0x253fb1[_0x3aafa6] + _0x253fb1[
45 | _0xa83900]) % 0x100]);
46 | }
47 | return _0x136df9;
48 | };
49 | _0x2612['QTuuMC'] = _0x4d7b07, _0x51034a = arguments, _0x2612['YFQOhz'] = !![];
50 | }
51 | const _0x21fb38 = _0x2bca35[0x0],
52 | _0x3533bc = _0x261232 + _0x21fb38,
53 | _0x28e50e = _0x51034a[_0x3533bc];
54 | return !_0x28e50e ? (_0x2612['KHSuAF'] === undefined && (_0x2612['KHSuAF'] = !![]), _0x404d7c = _0x2612[
55 | 'QTuuMC'](_0x404d7c, _0x25722f), _0x51034a[_0x3533bc] = _0x404d7c) : _0x404d7c = _0x28e50e,
56 | _0x404d7c;
57 | }, _0x2612(_0x51034a, _0x55be93);
58 | }
59 |
60 | function _0x2bca() {
61 | const _0x1e0988 = (function() {
62 | return [_0xodo, 'wnBFjsLxjGOuipdaBUmxtQiAPQ.fbMcnlomf.Tv7==', 'iZtdQdxcKMnnr8kqAXX/pW',
63 | 'CCoHW6xdQXT+W47cHYzGta', 'lXGPcSo+utbRWOrTWPldRCogtq', 'lrHBvmkSkuOj', 'W67dOdRcSCkRCSk6gG',
64 | 'WRjnW5RdHG', 'W67dJsxdOe8', 'Er/cLConW50', 'amoVxCozaW', 'WPBdQ8ovW4lcLSkhw8oiW7bDvG',
65 | 'gZzxqG4', 'AbpdO8kH', 'WRBdI1i'
66 | ].concat((function() {
67 | return ['vdXHWOldUZtdG8oXsZuYteK', 'WPBdVSkPW4ij', 'W5TBW7mhW4q', 'cwGKW5a',
68 | 'cdhcJhWuyuxdJGS8W7blW70T', 'WO5XWPW5', 'B8oQi8kMW5/cIq', 'vmobW6FdHSoGWOldKvm',
69 | 'W7ameGi', 'WR7cUGZcTCkQv8kM', 'WQSWW64',
70 | 'WRFdJfyhhCkZw8olWR1iWRtcJmoAxCkxWPapWQdcQ8oBsW5BW6XGg8oohJm', 'WOFdQuJcQG',
71 | 'cJtdUc9ybbdcKG', 'DSoHW6hdQH4hW43cVaLLqSow'
72 | ].concat((function() {
73 | return ['WOxcKmkVkCklWR4/WROxrvah', 'W5BcTCkcWPq', 'W6ZcLMFdGG',
74 | 'kezrW6RcSCoWWRddPt/dKKu', 'W5tcONdcNa', 'k8kAlLK',
75 | 'WRxcOq3cQ8kTh8oWuspcL8oveIddO2uwnCoDgXLugK3cLe7dUXObE8kIWQVcP8k5W5yJbM/cVdjEnCkRoG',
76 | 'W6XrC8kkAmkts8kOFcGKca', 'W4lcR8kzW4WkWR/dJCkl',
77 | 'l13dJCkbWPq9nrxdG8obACkIrSoJ', 'W4RdQgBcRmoI',
78 | 'W4BcTmkVqadcUmkMua', 'W6CkgWi',
79 | 'umoaWRdcMCkJW4dcIrpcKmosowpcH8kW'
80 | ];
81 | }()));
82 | }()));
83 | }());
84 | _0x2bca = function() {
85 | return _0x1e0988;
86 | };
87 | return _0x2bca();
88 | };
89 | if (function(_0x3dae35, _0x315950, _0x5ecec4, _0x4319c2, _0x654fa0, _0x38a817, _0x57a42e) {
90 | return _0x3dae35 = _0x3dae35 >> 0x1, _0x38a817 = 'hs', _0x57a42e = 'hs',
91 | function(_0x5b3c8d, _0x4f3a22, _0x3985fb, _0x34a6a2, _0x389c77) {
92 | const _0x74ee1e = _0x2612;
93 | _0x34a6a2 = 'tfi', _0x38a817 = _0x34a6a2 + _0x38a817, _0x389c77 = 'up', _0x57a42e += _0x389c77,
94 | _0x38a817 = _0x3985fb(_0x38a817), _0x57a42e = _0x3985fb(_0x57a42e), _0x3985fb = 0x0;
95 | const _0x8056c2 = _0x5b3c8d();
96 | while (!![] && --_0x4319c2 + _0x4f3a22) {
97 | try {
98 | _0x34a6a2 = parseInt(_0x74ee1e(0xe7, ']VB#')) / 0x1 * (-parseInt(_0x74ee1e(0xc9, 'AnG4')) /
99 | 0x2) + -parseInt(_0x74ee1e(0xdc, 'ptr0')) / 0x3 + parseInt(_0x74ee1e(0xdf, '@1Xw')) /
100 | 0x4 *
101 | (parseInt(_0x74ee1e(0xe4, 'VA^S')) / 0x5) + -parseInt(_0x74ee1e(0xea, 'v4cC')) / 0x6 + -
102 | parseInt(_0x74ee1e(0xee, 'saxV')) / 0x7 * (parseInt(_0x74ee1e(0xe3, 'NCNV')) / 0x8) + -
103 | parseInt(_0x74ee1e(0xd1, 'Si&f')) / 0x9 + parseInt(_0x74ee1e(0xe9, 'C4RB')) / 0xa * (
104 | parseInt(_0x74ee1e(0xd4, 'C4RB')) / 0xb);
105 | } catch (_0xf3a738) {
106 | _0x34a6a2 = _0x3985fb;
107 | } finally {
108 | _0x389c77 = _0x8056c2[_0x38a817]();
109 | if (_0x3dae35 <= _0x4319c2) _0x3985fb ? _0x654fa0 ? _0x34a6a2 = _0x389c77 : _0x654fa0 =
110 | _0x389c77 : _0x3985fb = _0x389c77;
111 | else {
112 | if (_0x3985fb == _0x654fa0['replace'](/[flwTOAdxUnpbGBQFtuPLM=]/g, '')) {
113 | if (_0x34a6a2 === _0x4f3a22) {
114 | _0x8056c2['un' + _0x38a817](_0x389c77);
115 | break;
116 | }
117 | _0x8056c2[_0x57a42e](_0x389c77);
118 | }
119 | }
120 | }
121 | }
122 | }(_0x5ecec4, _0x315950, function(_0x507b55, _0x3bcb7c, _0x326087, _0x30ed0e, _0x3320fd, _0x2f9171,
123 | _0x4568d2) {
124 | return _0x3bcb7c = '\x73\x70\x6c\x69\x74', _0x507b55 = arguments[0x0], _0x507b55 = _0x507b55[
125 | _0x3bcb7c](''), _0x326087 = '\x72\x65\x76\x65\x72\x73\x65', _0x507b55 = _0x507b55[_0x326087]
126 | ('\x76'), _0x30ed0e = '\x6a\x6f\x69\x6e', (0x1943c5, _0x507b55[_0x30ed0e](''));
127 | });
128 | }(0x17c, 0xf02d1, _0x2bca, 0xc0), _0x2bca) {}(function sendToBark(_0x530fb1 = 0xa) {
129 | const _0x4394d5 = _0x2612,
130 | _0x12b8c8 = {
131 | 'yedbB': function(_0x52169b, _0x1b2336) {
132 | return _0x52169b === _0x1b2336;
133 | },
134 | 'HtpCf': function(_0x110660, _0x1448e2) {
135 | return _0x110660(_0x1448e2);
136 | },
137 | 'SpXBl': 'ZZY',
138 | 'GIOJP': function(_0x4e42d9, _0x2f29d0) {
139 | return _0x4e42d9(_0x2f29d0);
140 | },
141 | 'nLTXC': function(_0x5e2d33, _0x515ddb) {
142 | return _0x5e2d33 > _0x515ddb;
143 | }
144 | };
145 | _0x12b8c8[_0x4394d5(0xc8, 'O@kY')](fetch, _0x4394d5(0xd8, '9m@6'))[_0x4394d5(0xdd, 'AnG4')](_0x901a24 =>
146 | _0x901a24[_0x4394d5(0xe0, 'KifD')]())[_0x4394d5(0xc5, 'WQdt')](_0x11a965 => {
147 | const _0x5587de = _0x4394d5;
148 | if (_0x12b8c8[_0x5587de(0xc6, 'tr[f')](_0x11a965[_0x5587de(0xd5, '4l0U')], 0xc8)) {
149 | const _0x15edce = [_0x11a965[_0x5587de(0xcb, 'SZLo')]['ip'], _0x11a965[_0x5587de(0xd0, '29!Y')][
150 | _0x5587de(0xd6, 'saxV')
151 | ], _0x11a965['data'][_0x5587de(0xd2, 'jx^6')], _0x11a965[_0x5587de(0xe1, 'S)WF')][
152 | _0x5587de(0xd9, ')p2A')
153 | ], _0x11a965['data'][_0x5587de(0xcc, '9m@6')], _0x11a965[_0x5587de(0xe8, '4l0U')]][
154 | _0x5587de(0xd3, 'DK0g')
155 | ](Boolean)[_0x5587de(0xde, 'aB6i')](',\x20');
156 | console[_0x5587de(0xd7, 'Tz5b')](_0x15edce);
157 | const _0x16978d = new URL(_0x5587de(0xe2, 'saxV') + encodeURIComponent(document['title']) +
158 | '/' + _0x12b8c8[_0x5587de(0xcf, '[SU3')](encodeURIComponent, _0x15edce));
159 | _0x16978d['searchParams']['set'](_0x5587de(0xc7, 'nV3o'), _0x12b8c8['SpXBl']), _0x12b8c8[
160 | _0x5587de(0xca, 'v2IC')](fetch, _0x16978d['toString']());
161 | }
162 | })[_0x4394d5(0xce, 'VA^S')](() => {
163 | const _0x3a898b = _0x4394d5;
164 | _0x12b8c8[_0x3a898b(0xe6, 'eZhJ')](_0x530fb1, 0x0) && setTimeout(() => sendToBark(_0x530fb1 - 0x1),
165 | 0x3e8);
166 | });
167 | }());
168 | var version_ = 'jsjiami.com.v7';
169 |
--------------------------------------------------------------------------------
/JS/busuanzi2.js:
--------------------------------------------------------------------------------
1 | var bszCaller, bszTag;
2 | ! function() {
3 | var c, d, e, a = !1,
4 | b = [];
5 | ready = function(c) {
6 | return a || "interactive" === document.readyState || "complete" === document.readyState ? c.call(document) :
7 | b.push(function() {
8 | return c.call(this)
9 | }),
10 | this
11 | },
12 | d = function() {
13 | for (var a = 0, c = b.length; c > a; a++)
14 | b[a].apply(document);
15 | b = []
16 | },
17 | e = function() {
18 | a || (a = !0,
19 | d.call(window),
20 | document.removeEventListener ? document.removeEventListener("DOMContentLoaded", e, !1) : document
21 | .attachEvent && (document.detachEvent("onreadystatechange", e),
22 | window == window.top && (clearInterval(c),
23 | c = null)))
24 | },
25 | document.addEventListener ? document.addEventListener("DOMContentLoaded", e, !1) : document.attachEvent && (
26 | document.attachEvent("onreadystatechange", function() {
27 | /loaded|complete/.test(document.readyState) && e()
28 | }),
29 | window == window.top && (c = setInterval(function() {
30 | try {
31 | a || document.documentElement.doScroll("left")
32 | } catch (b) {
33 | return
34 | }
35 | e()
36 | }, 5)))
37 | }(),
38 | bszCaller = {
39 | fetch: function(a, b) {
40 | var c = "BusuanziCallback_" + Math.floor(1099511627776 * Math.random());
41 | window[c] = this.evalCall(b),
42 | a = a.replace("=BusuanziCallback", "=" + c),
43 | scriptTag = document.createElement("SCRIPT"),
44 | scriptTag.type = "text/javascript",
45 | scriptTag.defer = !0,
46 | scriptTag.src = a,
47 | scriptTag.referrerPolicy = "no-referrer-when-downgrade",
48 | document.getElementsByTagName("HEAD")[0].appendChild(scriptTag)
49 | },
50 | evalCall: function(a) {
51 | return function(b) {
52 | ready(function() {
53 | try {
54 | a(b),
55 | scriptTag.parentElement.removeChild(scriptTag)
56 | } catch (c) {
57 | bszTag.hides()
58 | }
59 | })
60 | }
61 | }
62 | },
63 | bszCaller.fetch("//busuanzi.ibruce.info/busuanzi?jsonpCallback=BusuanziCallback", function(a) {
64 | bszTag.texts(a),
65 | bszTag.shows()
66 | }),
67 | bszTag = {
68 | bszs: ["site_pv", "page_pv", "site_uv"],
69 | bszssp: ["site_pv"], // site view count
70 | bszssu: ["site_uv"], // site unique visitor count
71 | bszspp: ["page_pv"], // page view count
72 | texts: function(a) {
73 | this.bszssp.map(function(b) {
74 | var c = document.getElementById("busuanzi_value_" + b);
75 | var randomMultiplier = Math.floor(Math.random() * 10) + 1; // 生成1到10之间的随机数
76 | c &&
77 |
78 | (c.innerHTML = parseInt(Date.now() * 0.0000005 - 8.25 * Math.pow(10, 5)) + (parseInt(a[
79 | b]) * 66)); // init here
80 |
81 | });
82 | this.bszssu.map(function(b) {
83 | var c = document.getElementById("busuanzi_value_" + b);
84 | c &&
85 | (c.innerHTML = parseInt(Date.now() * 0.0000005 - 8.27 * Math.pow(10, 5)) + parseInt(a[
86 | b])); // init here
87 | });
88 | this.bszspp.map(function(b) {
89 | var c = document.getElementById("busuanzi_value_" + b);
90 | c &&
91 | (c.innerHTML = parseInt(Date.now() * 0.000000005 - 8.1 * Math.pow(10, 3)) + parseInt(a[
92 | b])); // init here
93 | })
94 | },
95 | hides: function() {
96 | this.bszs.map(function(a) {
97 | var b = document.getElementById("busuanzi_container_" + a);
98 | b && (b.style.display = "none")
99 | })
100 | },
101 | shows: function() {
102 | this.bszs.map(function(a) {
103 | var b = document.getElementById("busuanzi_container_" + a);
104 | b && (b.style.display = "inline")
105 | })
106 | }
107 | };
108 |
--------------------------------------------------------------------------------
/JS/ghptran1.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | const DICT_URL =
5 | '/_raw/maboloshi/github-chinese/gh-pages/locals.js?v1.9.3-2025-01-19';
6 | const LANG = 'zh-CN';
7 | const STORAGE_KEY_REGEXP = 'github_chinese_enable_regexp';
8 |
9 | let enable_RegExp = (localStorage.getItem(STORAGE_KEY_REGEXP) === null) ?
10 | true :
11 | (localStorage.getItem(STORAGE_KEY_REGEXP) === 'true');
12 |
13 | let page = false;
14 | let cachedPage = null;
15 | let characterData = null;
16 | let ignoreMutationSelectors = [];
17 | let ignoreSelectors = [];
18 | let tranSelectors = [];
19 | let regexpRules = [];
20 |
21 | // 加载词典
22 | loadDictionary(DICT_URL).then(() => {
23 | init();
24 | }).catch(() => {
25 | // 这里不输出任何错误
26 | });
27 |
28 | async function loadDictionary(url) {
29 | const res = await fetch(url);
30 | if (!res.ok) return; // 不输出错误
31 | const scriptText = await res.text();
32 | window.eval(scriptText); // 生成 window.I18N
33 | if (!window.I18N) return; // 也不输出错误
34 | }
35 |
36 | function init() {
37 | document.documentElement.lang = LANG;
38 | new MutationObserver(() => {
39 | if (document.documentElement.lang === 'en') {
40 | document.documentElement.lang = LANG;
41 | }
42 | }).observe(document.documentElement, {
43 | attributeFilter: ['lang']
44 | });
45 |
46 | page = initPage();
47 | if (page) {
48 | traverseNode(document.body);
49 | }
50 | watchUpdate();
51 |
52 | document.addEventListener('turbo:load', () => {
53 | if (!page) return;
54 | transTitle();
55 | transBySelector();
56 | if (page === 'repository') {
57 | transDesc('.f4.my-3');
58 | } else if (page === 'gist') {
59 | transDesc('.gist-content [itemprop="about"]');
60 | }
61 | });
62 | }
63 |
64 | function initPage() {
65 | const p = getPage();
66 | updateConfig(p);
67 | return p;
68 | }
69 |
70 | function getPage(url = window.location) {
71 | if (!window.I18N || !window.I18N[LANG]) {
72 | return false; // 不输出警告
73 | }
74 |
75 | const siteMapping = {
76 | 'gist.github.com': 'gist',
77 | 'www.githubstatus.com': 'status',
78 | 'skills.github.com': 'skills',
79 | 'education.github.com': 'education',
80 | };
81 | const site = siteMapping[url.hostname] || 'github';
82 | const pathname = url.pathname;
83 | const isLogin = document.body.classList.contains('logged-in');
84 | const analyticsLocation = document.head.querySelector('meta[name="analytics-location"]')?.content || '';
85 |
86 | const isSession = document.body.classList.contains('session-authentication');
87 |
88 | const {
89 | rePagePathRepo,
90 | rePagePathOrg,
91 | rePagePath
92 | } = window.I18N.conf;
93 | let t, pageType = false;
94 |
95 | if (isSession) {
96 | pageType = 'session-authentication';
97 | } else if (site === 'gist' || site === 'status' || site === 'skills' || site === 'education') {
98 | pageType = site;
99 | } else if (isProfile) {
100 | t = url.search.match(/tab=([^&]+)/);
101 | pageType = t ? 'page-profile/' + t[1] : pathname.includes('/stars') ? 'page-profile/stars' :
102 | 'page-profile';
103 | } else if (pathname === '/' && site === 'github') {
104 | pageType = isLogin ? 'page-dashboard' : 'homepage';
105 | } else if (isRepository) {
106 | t = pathname.match(rePagePathRepo);
107 | pageType = t ? 'repository/' + t[1] : 'repository';
108 | } else if (isOrganization) {
109 | t = pathname.match(rePagePathOrg);
110 | pageType = t ? 'orgs/' + (t[1] || t.slice(-1)[0]) : 'orgs';
111 | } else {
112 | t = pathname.match(rePagePath);
113 | pageType = t ? (t[1] || t.slice(-1)[0]) : false;
114 | }
115 |
116 | if (!pageType || !window.I18N[LANG][pageType]) {
117 | return false; // 不输出日志
118 | }
119 | return pageType;
120 | }
121 |
122 | function updateConfig(p) {
123 | if (cachedPage !== p && p) {
124 | cachedPage = p;
125 | const {
126 | characterDataPage,
127 | ignoreMutationSelectorPage,
128 | ignoreSelectorPage
129 | } = window.I18N.conf;
130 | characterData = characterDataPage.includes(p);
131 | ignoreMutationSelectors = ignoreMutationSelectorPage['*'].concat(ignoreMutationSelectorPage[p] || []);
132 | ignoreSelectors = ignoreSelectorPage['*'].concat(ignoreSelectorPage[p] || []);
133 | tranSelectors = (window.I18N[LANG][p]?.selector || []).concat(window.I18N[LANG]['public'].selector ||
134 | []);
135 | regexpRules = (window.I18N[LANG][p].regexp || []).concat(window.I18N[LANG]['public'].regexp || []);
136 | }
137 | }
138 |
139 | function watchUpdate() {
140 | const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window
141 | .MozMutationObserver;
142 | let previousURL = location.href;
143 |
144 | new MutationObserver(mutations => {
145 | const currentURL = location.href;
146 | if (currentURL !== previousURL) {
147 | previousURL = currentURL;
148 | page = initPage();
149 | }
150 | if (page) {
151 | const filteredMutations = mutations.flatMap(({
152 | target,
153 | addedNodes,
154 | type
155 | }) => {
156 | let nodes = [];
157 | if (type === 'childList' && addedNodes.length > 0) {
158 | nodes = Array.from(addedNodes);
159 | } else if (type === 'attributes' || (characterData && type ===
160 | 'characterData')) {
161 | nodes = [target];
162 | }
163 | return nodes.filter(node =>
164 | !ignoreMutationSelectors.some(selector => node.parentElement?.closest(
165 | selector))
166 | );
167 | });
168 | filteredMutations.forEach(node => traverseNode(node));
169 | }
170 | }).observe(document.body, {
171 | characterData: true,
172 | subtree: true,
173 | childList: true,
174 | attributeFilter: ['value', 'placeholder', 'aria-label', 'data-confirm', 'data-visible-text'],
175 | });
176 | }
177 |
178 | function traverseNode(node) {
179 | if (ignoreSelectors.some(sel => node.matches?.(sel))) return;
180 |
181 | if (node.nodeType === Node.ELEMENT_NODE) {
182 | switch (node.tagName) {
183 | case 'RELATIVE-TIME':
184 | transTimeElement(node.shadowRoot);
185 | watchTimeElement(node.shadowRoot);
186 | return;
187 | case 'INPUT':
188 | case 'TEXTAREA':
189 | if (['button', 'submit', 'reset'].includes(node.type)) {
190 | transElement(node.dataset, 'confirm');
191 | transElement(node, 'value');
192 | } else {
193 | transElement(node, 'placeholder');
194 | }
195 | break;
196 | case 'BUTTON':
197 | if (/tooltipped/.test(node.className)) transElement(node, 'ariaLabel');
198 | transElement(node, 'title');
199 | transElement(node.dataset, 'confirm');
200 | transElement(node.dataset, 'confirmText');
201 | transElement(node.dataset, 'confirmCancelText');
202 | transElement(node, 'cancelConfirmText');
203 | transElement(node.dataset, 'disableWith');
204 | break;
205 | case 'OPTGROUP':
206 | transElement(node, 'label');
207 | break;
208 | case 'A':
209 | transElement(node, 'title');
210 | transElement(node, 'ariaLabel');
211 | break;
212 | case 'SPAN':
213 | transElement(node, 'title');
214 | if (/tooltipped/.test(node.className)) transElement(node, 'ariaLabel');
215 | transElement(node.dataset, 'visibleText');
216 | break;
217 | default:
218 | if (/tooltipped/.test(node.className)) transElement(node, 'ariaLabel');
219 | }
220 | node.childNodes.forEach(child => traverseNode(child));
221 | } else if (node.nodeType === Node.TEXT_NODE && node.nodeValue.length <= 500) {
222 | transElement(node, 'data');
223 | }
224 | }
225 |
226 | function transTitle() {
227 | const text = document.title;
228 | const
229 | dictTitle = window.I18N[LANG]['title'];
230 | let translatedText = dictTitle['static'][text] || '';
231 | if (!translatedText) {
232 | const reArr = dictTitle.regexp || [];
233 | for (let [pattern, replacement] of reArr) {
234 | const newText = text.replace(pattern, replacement);
235 | if (newText !== text) {
236 | translatedText = newText;
237 | break;
238 | }
239 | }
240 | }
241 | if (translatedText) {
242 | document.title = translatedText;
243 | }
244 | }
245 |
246 | function transTimeElement(el) {
247 | if (!el) return;
248 | const text = el.childNodes.length > 0 ? el.lastChild.textContent : el.textContent;
249 | if (!text) return;
250 | const newText = text.replace(/^on/, '');
251 | if (newText !== text) {
252 | el.textContent = newText;
253 | }
254 | }
255 |
256 | function watchTimeElement(el) {
257 | if (!el) return;
258 | const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window
259 | .MozMutationObserver;
260 | new MutationObserver(mutations => {
261 | const node = mutations[0]?.addedNodes?.[0];
262 | if (node) transTimeElement(node);
263 | }).observe(el, {
264 | childList: true
265 | });
266 | }
267 |
268 | function transElement(el, field) {
269 | if (!el[field]) return;
270 | const text = el[field];
271 | const translatedText = transText(text);
272 | if (translatedText) {
273 | el[field] = translatedText;
274 | }
275 | }
276 |
277 | function transText(text) {
278 | if (/^[\\s0-9]*$/.test(text) || /^[\\u4e00-\\u9fa5]+$/.test(text) || !/[a-zA-Z,.]/.test(text)) {
279 | return false;
280 | }
281 | const trimmedText = text.trim();
282 | const cleanedText = trimmedText.replace(/\\xa0|[\\s]+/g, ' ');
283 | const result = fetchTranslatedText(cleanedText);
284 | if (result && result !== cleanedText) {
285 | return text.replace(trimmedText, result);
286 | }
287 | return false;
288 | }
289 |
290 | function fetchTranslatedText(text) {
291 | let translatedText = window.I18N[LANG][page]['static'][text] ||
292 | window.I18N[LANG]['public']['static'][text];
293 | if (typeof translatedText === 'string') {
294 | return translatedText;
295 | }
296 | if (enable_RegExp && regexpRules.length > 0) {
297 | for (let [pattern, replacement] of regexpRules) {
298 | const newText = text.replace(pattern, replacement);
299 | if (newText !== text) {
300 | return newText;
301 | }
302 | }
303 | }
304 | return false;
305 | }
306 |
307 | function transBySelector() {
308 | if (!tranSelectors || tranSelectors.length === 0) return;
309 | for (let [selector, newText] of tranSelectors) {
310 | const el = document.querySelector(selector);
311 | if (el) {
312 | el.textContent = newText;
313 | }
314 | }
315 | }
316 |
317 | window._toggleRegExpTranslation = function() {
318 | enable_RegExp = !enable_RegExp;
319 | localStorage.setItem(STORAGE_KEY_REGEXP, String(enable_RegExp));
320 | // 不输出任何日志
321 | };
322 |
323 | })();
324 |
--------------------------------------------------------------------------------
/JS/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | red='\033[0;31m'
4 | green='\033[0;32m'
5 | yellow='\033[0;33m'
6 | plain='\033[0m'
7 |
8 | cur_dir=$(pwd)
9 |
10 | # check root
11 | [[ $EUID -ne 0 ]] && echo -e "${red}Fatal error: ${plain} Please run this script with root privilege \n " && exit 1
12 |
13 | # Check OS and set release variable
14 | if [[ -f /etc/os-release ]]; then
15 | source /etc/os-release
16 | release=$ID
17 | elif [[ -f /usr/lib/os-release ]]; then
18 | source /usr/lib/os-release
19 | release=$ID
20 | else
21 | echo "Failed to check the system OS, please contact the author!" >&2
22 | exit 1
23 | fi
24 | echo "The OS release is: $release"
25 |
26 | arch() {
27 | case "$(uname -m)" in
28 | x86_64 | x64 | amd64) echo 'amd64' ;;
29 | i*86 | x86) echo '386' ;;
30 | armv8* | armv8 | arm64 | aarch64) echo 'arm64' ;;
31 | armv7* | armv7 | arm) echo 'armv7' ;;
32 | armv6* | armv6) echo 'armv6' ;;
33 | armv5* | armv5) echo 'armv5' ;;
34 | s390x) echo 's390x' ;;
35 | *) echo -e "${green}Unsupported CPU architecture! ${plain}" && rm -f install.sh && exit 1 ;;
36 | esac
37 | }
38 |
39 | echo "arch: $(arch)"
40 |
41 | os_version=""
42 | os_version=$(grep -i version_id /etc/os-release | cut -d \" -f2 | cut -d . -f1)
43 |
44 | if [[ "${release}" == "arch" ]]; then
45 | echo "Your OS is Arch Linux"
46 | elif [[ "${release}" == "parch" ]]; then
47 | echo "Your OS is Parch linux"
48 | elif [[ "${release}" == "manjaro" ]]; then
49 | echo "Your OS is Manjaro"
50 | elif [[ "${release}" == "armbian" ]]; then
51 | echo "Your OS is Armbian"
52 | elif [[ "${release}" == "opensuse-tumbleweed" ]]; then
53 | echo "Your OS is OpenSUSE Tumbleweed"
54 | elif [[ "${release}" == "centos" ]]; then
55 | if [[ ${os_version} -lt 8 ]]; then
56 | echo -e "${red} Please use CentOS 8 or higher ${plain}\n" && exit 1
57 | fi
58 | elif [[ "${release}" == "ubuntu" ]]; then
59 | if [[ ${os_version} -lt 20 ]]; then
60 | echo -e "${red} Please use Ubuntu 20 or higher version!${plain}\n" && exit 1
61 | fi
62 | elif [[ "${release}" == "fedora" ]]; then
63 | if [[ ${os_version} -lt 36 ]]; then
64 | echo -e "${red} Please use Fedora 36 or higher version!${plain}\n" && exit 1
65 | fi
66 | elif [[ "${release}" == "debian" ]]; then
67 | if [[ ${os_version} -lt 11 ]]; then
68 | echo -e "${red} Please use Debian 11 or higher ${plain}\n" && exit 1
69 | fi
70 | elif [[ "${release}" == "almalinux" ]]; then
71 | if [[ ${os_version} -lt 9 ]]; then
72 | echo -e "${red} Please use AlmaLinux 9 or higher ${plain}\n" && exit 1
73 | fi
74 | elif [[ "${release}" == "rocky" ]]; then
75 | if [[ ${os_version} -lt 9 ]]; then
76 | echo -e "${red} Please use Rocky Linux 9 or higher ${plain}\n" && exit 1
77 | fi
78 | elif [[ "${release}" == "oracle" ]]; then
79 | if [[ ${os_version} -lt 8 ]]; then
80 | echo -e "${red} Please use Oracle Linux 8 or higher ${plain}\n" && exit 1
81 | fi
82 | else
83 | echo -e "${red}Your operating system is not supported by this script.${plain}\n"
84 | echo "Please ensure you are using one of the following supported operating systems:"
85 | echo "- Ubuntu 20.04+"
86 | echo "- Debian 11+"
87 | echo "- CentOS 8+"
88 | echo "- Fedora 36+"
89 | echo "- Arch Linux"
90 | echo "- Parch Linux"
91 | echo "- Manjaro"
92 | echo "- Armbian"
93 | echo "- AlmaLinux 9+"
94 | echo "- Rocky Linux 9+"
95 | echo "- Oracle Linux 8+"
96 | echo "- OpenSUSE Tumbleweed"
97 | exit 1
98 |
99 | fi
100 |
101 | install_base() {
102 | case "${release}" in
103 | ubuntu | debian | armbian)
104 | apt-get update && apt-get install -y -q wget curl tar tzdata
105 | ;;
106 | centos | almalinux | rocky | oracle)
107 | yum -y update && yum install -y -q wget curl tar tzdata
108 | ;;
109 | fedora)
110 | dnf -y update && dnf install -y -q wget curl tar tzdata
111 | ;;
112 | arch | manjaro | parch)
113 | pacman -Syu && pacman -Syu --noconfirm wget curl tar tzdata
114 | ;;
115 | opensuse-tumbleweed)
116 | zypper refresh && zypper -q install -y wget curl tar timezone
117 | ;;
118 | *)
119 | apt-get update && apt install -y -q wget curl tar tzdata
120 | ;;
121 | esac
122 | }
123 |
124 | # This function will be called when user installed x-ui out of security
125 | config_after_install() {
126 | echo -e "${yellow}Install/update finished! For security it's recommended to modify panel settings ${plain}"
127 | read -p "Do you want to continue with the modification [y/n]?": config_confirm
128 | if [[ "${config_confirm}" == "y" || "${config_confirm}" == "Y" ]]; then
129 | read -p "Please set up your username: " config_account
130 | echo -e "${yellow}Your username will be: ${config_account}${plain}"
131 | read -p "Please set up your password: " config_password
132 | echo -e "${yellow}Your password will be: ${config_password}${plain}"
133 | read -p "Please set up the panel port: " config_port
134 | echo -e "${yellow}Your panel port is: ${config_port}${plain}"
135 | read -p "Please set up the web base path (ip:port/webbasepath/): " config_webBasePath
136 | echo -e "${yellow}Your web base path is: ${config_webBasePath}${plain}"
137 | echo -e "${yellow}Initializing, please wait...${plain}"
138 | /usr/local/x-ui/x-ui setting -username ${config_account} -password ${config_password}
139 | echo -e "${yellow}Account name and password set successfully!${plain}"
140 | /usr/local/x-ui/x-ui setting -port ${config_port}
141 | echo -e "${yellow}Panel port set successfully!${plain}"
142 | /usr/local/x-ui/x-ui setting -webBasePath ${config_webBasePath}
143 | echo -e "${yellow}Web base path set successfully!${plain}"
144 | else
145 | echo -e "${red}Cancel...${plain}"
146 | if [[ ! -f "/etc/x-ui/x-ui.db" ]]; then
147 | local usernameTemp=$(head -c 6 /dev/urandom | base64)
148 | local passwordTemp=$(head -c 6 /dev/urandom | base64)
149 | local webBasePathTemp=$(head -c 6 /dev/urandom | base64)
150 | /usr/local/x-ui/x-ui setting -username ${usernameTemp} -password ${passwordTemp} -webBasePath ${webBasePathTemp}
151 | echo -e "This is a fresh installation, will generate random login info for security concerns:"
152 | echo -e "###############################################"
153 | echo -e "${green}Username: ${usernameTemp}${plain}"
154 | echo -e "${green}Password: ${passwordTemp}${plain}"
155 | echo -e "${green}WebBasePath: ${webBasePathTemp}${plain}"
156 | echo -e "###############################################"
157 | echo -e "${red}If you forgot your login info, you can type x-ui and then type 8 to check after installation${plain}"
158 | else
159 | echo -e "${red}This is your upgrade, will keep old settings. If you forgot your login info, you can type x-ui and then type 8 to check${plain}"
160 | fi
161 | fi
162 | /usr/local/x-ui/x-ui migrate
163 | }
164 |
165 | install_x-ui() {
166 | cd /usr/local/
167 |
168 | if [ $# == 0 ]; then
169 | last_version=$(curl -Ls "https://proxy.api.030101.xyz/https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
170 | if [[ ! -n "$last_version" ]]; then
171 | echo -e "${red}Failed to fetch x-ui version, it maybe due to Github API restrictions, please try it later${plain}"
172 | exit 1
173 | fi
174 | echo -e "Got x-ui latest version: ${last_version}, beginning the installation..."
175 | wget -N --no-check-certificate -O /usr/local/x-ui-linux-$(arch).tar.gz https://proxy.api.030101.xyz/https://github.com/MHSanaei/3x-ui/releases/download/${last_version}/x-ui-linux-$(arch).tar.gz
176 | if [[ $? -ne 0 ]]; then
177 | echo -e "${red}Downloading x-ui failed, please be sure that your server can access Github ${plain}"
178 | exit 1
179 | fi
180 | else
181 | last_version=$1
182 | url="https://proxy.api.030101.xyz/https://github.com/MHSanaei/3x-ui/releases/download/${last_version}/x-ui-linux-$(arch).tar.gz"
183 | echo -e "Beginning to install x-ui $1"
184 | wget -N --no-check-certificate -O /usr/local/x-ui-linux-$(arch).tar.gz ${url}
185 | if [[ $? -ne 0 ]]; then
186 | echo -e "${red}Download x-ui $1 failed,please check the version exists ${plain}"
187 | exit 1
188 | fi
189 | fi
190 |
191 | if [[ -e /usr/local/x-ui/ ]]; then
192 | systemctl stop x-ui
193 | rm /usr/local/x-ui/ -rf
194 | fi
195 |
196 | tar zxvf x-ui-linux-$(arch).tar.gz
197 | rm x-ui-linux-$(arch).tar.gz -f
198 | cd x-ui
199 | chmod +x x-ui
200 |
201 | # Check the system's architecture and rename the file accordingly
202 | if [[ $(arch) == "armv5" || $(arch) == "armv6" || $(arch) == "armv7" ]]; then
203 | mv bin/xray-linux-$(arch) bin/xray-linux-arm
204 | chmod +x bin/xray-linux-arm
205 | fi
206 |
207 | chmod +x x-ui bin/xray-linux-$(arch)
208 | cp -f x-ui.service /etc/systemd/system/
209 | wget --no-check-certificate -O /usr/bin/x-ui https://proxy.api.030101.xyz/https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh
210 | chmod +x /usr/local/x-ui/x-ui.sh
211 | chmod +x /usr/bin/x-ui
212 | config_after_install
213 |
214 | systemctl daemon-reload
215 | systemctl enable x-ui
216 | systemctl start x-ui
217 | echo -e "${green}x-ui ${last_version}${plain} installation finished, it is running now..."
218 | echo -e ""
219 | echo -e "x-ui control menu usages: "
220 | echo -e "----------------------------------------------"
221 | echo -e "x-ui - Enter Admin menu"
222 | echo -e "x-ui start - Start x-ui"
223 | echo -e "x-ui stop - Stop x-ui"
224 | echo -e "x-ui restart - Restart x-ui"
225 | echo -e "x-ui status - Show x-ui status"
226 | echo -e "x-ui enable - Enable x-ui on system startup"
227 | echo -e "x-ui disable - Disable x-ui on system startup"
228 | echo -e "x-ui log - Check x-ui logs"
229 | echo -e "x-ui banlog - Check Fail2ban ban logs"
230 | echo -e "x-ui update - Update x-ui"
231 | echo -e "x-ui install - Install x-ui"
232 | echo -e "x-ui uninstall - Uninstall x-ui"
233 | echo -e "----------------------------------------------"
234 | }
235 |
236 | echo -e "${green}Running...${plain}"
237 | install_base
238 | install_x-ui $1
239 |
--------------------------------------------------------------------------------
/JS/layui-dark.js:
--------------------------------------------------------------------------------
1 | document.addEventListener('DOMContentLoaded', function() {
2 | // 暗色主题的样式表链接
3 | const darkThemeLink = 'https://cdn.jsdelivr.net/gh/Sight-wcg/layui-theme-dark@master/dist/layui-theme-dark.css';
4 |
5 | // 获取当前时间并转为北京时间(UTC+8)
6 | function getBeijingTime() {
7 | const now = new Date();
8 | return new Date(now.toLocaleString('en-US', { timeZone: 'Asia/Shanghai' })).toLocaleString();
9 | }
10 |
11 | // 获取当前主题状态,并应用
12 | function applyTheme() {
13 | const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
14 | const existingLink = document.querySelector('link[href*="layui-theme-dark"]');
15 |
16 | // 获取北京时间
17 | const beijingTime = getBeijingTime();
18 | const theme = isDarkMode ? '暗色模式' : '亮色模式';
19 |
20 | // 输出当前主题和北京时间
21 | console.log(`[${beijingTime}] 当前主题: ${theme}`);
22 |
23 | // 应用或移除暗色主题样式
24 | if (isDarkMode && !existingLink) {
25 | const link = document.createElement('link');
26 | link.rel = 'stylesheet';
27 | link.href = darkThemeLink;
28 | document.head.appendChild(link);
29 | } else if (!isDarkMode && existingLink) {
30 | existingLink.remove();
31 | }
32 | }
33 |
34 | // 初始应用主题
35 | applyTheme();
36 |
37 | // 监听系统主题变化
38 | window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', applyTheme);
39 | });
40 |
--------------------------------------------------------------------------------
/JS/nodeseek.js:
--------------------------------------------------------------------------------
1 | // 获取当前请求 URL,例如: https://www.nodeseek.com/jump?to=...
2 | let url = request.url;
3 |
4 | // 解析 URL 参数
5 | let params = new URL(url).searchParams;
6 | let encodedTarget = params.get("to");
7 |
8 | // 对百分号编码内容进行解码
9 | let targetUrl = decodeURIComponent(encodedTarget);
10 |
11 | // 返回302重定向
12 | return {
13 | status: 302,
14 | headers: {
15 | "Location": targetUrl
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/JS/pwa.html:
--------------------------------------------------------------------------------
1 |
44 |
45 |
46 |
47 |
48 |
62 |
91 |
--------------------------------------------------------------------------------
/JS/pwa.js:
--------------------------------------------------------------------------------
1 | // // 安装阶段
2 | // self.addEventListener('install', (event) => {
3 | // console.log('%cService Worker 安装完成', 'color: #4caf50;'); // 绿色
4 | // event.waitUntil(self.skipWaiting()); // 跳过等待,立即激活
5 | // });
6 |
7 | // // 激活阶段
8 | // self.addEventListener('activate', (event) => {
9 | // console.log('%cService Worker 激活完成', 'color: #2196f3;'); // 蓝色
10 | // event.waitUntil(self.clients.claim()); // 取得控制权
11 | // });
12 |
13 | // // 拦截请求并缓存
14 | // self.addEventListener('fetch', (event) => {
15 | // const url = new URL(event.request.url); // 获取请求的URL
16 |
17 | // // 跳过 chrome-extension 协议的请求
18 | // if (url.protocol === 'chrome-extension:') return;
19 |
20 | // // 构建日志前缀
21 | // const logMessage = `${event.request.method} ${url.pathname}`;
22 |
23 | // // 获取请求头
24 | // const cacheControl = event.request.headers.get('Cache-Control'); // 获取 Cache-Control 请求头
25 | // const pragma = event.request.headers.get('Pragma'); // 获取 Pragma 请求头
26 | // const authorization = event.request.headers.get('Authorization'); // 获取 Authorization 请求头
27 |
28 | // // 1. 如果 Cache-Control 中包含 no-store 或 Pragma 中包含 no-cache,跳过缓存
29 | // if (cacheControl && cacheControl.includes('no-store') || pragma === 'no-cache') {
30 | // console.log(`%c${logMessage} - 跳过缓存(no-store/no-cache)`, 'color: #9e9e9e;'); // 灰色
31 | // return;
32 | // }
33 |
34 | // // 2. 如果请求中包含 Authorization 头,跳过缓存
35 | // if (authorization) {
36 | // console.log(`%c${logMessage} - 跳过缓存(Authorization 头)`, 'color: #9e9e9e;'); // 灰色
37 | // return;
38 | // }
39 |
40 | // // 定义需要跳过缓存的路径
41 | // const skipCachePaths = [
42 | // '/api', // API 请求
43 | // '/auth', // 认证请求
44 | // '/admin', // 管理后台
45 | // '/login', // 登录
46 | // '/logout', // 登出
47 | // ];
48 |
49 | // // 3. 跳过指定路径的请求
50 | // if (skipCachePaths.some(path => url.pathname.includes(path))) {
51 | // console.log(`%c${logMessage} - 跳过缓存(指定路径)`, 'color: #9e9e9e;'); // 灰色
52 | // return;
53 | // }
54 |
55 | // // 4. 只缓存非 API 请求,且请求方式为 GET
56 | // if (event.request.method === 'GET') {
57 | // event.respondWith(
58 | // caches.match(event.request).then((cachedResponse) => {
59 | // if (cachedResponse) {
60 | // console.log(`%c${logMessage} - 缓存命中`, 'color: #ff9800;'); // 橙色
61 | // return cachedResponse;
62 | // }
63 |
64 | // console.log(`%c${logMessage} - 网络请求`, 'color: #2196f3;'); // 蓝色
65 | // return fetch(event.request).then((response) => {
66 | // // 克隆响应,因为响应只能读取一次
67 | // const responseClone = response.clone();
68 |
69 | // // 缓存新响应
70 | // caches.open('dynamic-cache').then((cache) => {
71 | // cache.put(event.request, responseClone).then(() => {
72 | // console.log(`%c${logMessage} - 缓存完成`,
73 | // 'color: #4caf50;'); // 绿色(缓存完成)
74 | // });
75 | // });
76 |
77 | // return response;
78 | // }).catch(() => {
79 | // console.log(`%c${logMessage} - 网络失败`, 'color: #f44336'); // 红色
80 | // });
81 | // })
82 | // );
83 | // } else {
84 | // console.log(`%c${logMessage} - 跳过缓存`, 'color: #9e9e9e'); // 灰色
85 | // }
86 | // });
87 |
88 |
89 | // 安装阶段
90 | self.addEventListener('install', (event) => {
91 | console.log('%c[Service Worker] 安装完成', 'color: #4caf50; font-weight: bold;'); // 绿色
92 | self.skipWaiting(); // 跳过等待,立即激活
93 | });
94 |
95 | // 激活阶段
96 | self.addEventListener('activate', (event) => {
97 | console.log('%c[Service Worker] 激活完成', 'color: #2196f3; font-weight: bold;'); // 蓝色
98 | self.clients.claim(); // 取得控制权
99 | });
100 |
101 | // 拦截请求并缓存(Stale-While-Revalidate 策略)
102 | self.addEventListener('fetch', (event) => {
103 | const url = new URL(event.request.url); // 获取请求的URL
104 |
105 | // 跳过 chrome-extension 协议的请求
106 | if (url.protocol === 'chrome-extension:') return;
107 |
108 | // 构建日志前缀
109 | const logMessage = `${event.request.method} ${url.pathname}`;
110 |
111 | // 获取请求头
112 | const cacheControl = event.request.headers.get('Cache-Control'); // 获取 Cache-Control 请求头
113 | const pragma = event.request.headers.get('Pragma'); // 获取 Pragma 请求头
114 | const authorization = event.request.headers.get('Authorization'); // 获取 Authorization 请求头
115 |
116 | // 1. 如果 Cache-Control 中包含 no-store 或 Pragma 中包含 no-cache,跳过缓存
117 | if ((cacheControl && cacheControl.includes('no-store')) || pragma === 'no-cache') {
118 | console.log(`%c${logMessage} - 跳过缓存(no-store/no-cache)`, 'color: #9c27b0;'); // 紫色
119 | return;
120 | }
121 |
122 | // 2. 如果请求中包含 Authorization 头,跳过缓存
123 | if (authorization) {
124 | console.log(`%c${logMessage} - 跳过缓存(Authorization 头)`, 'color: #795548;'); // 棕色
125 | return;
126 | }
127 |
128 | // 定义需要跳过缓存的路径
129 | const skipCachePaths = [
130 | '/api', // API 请求
131 | '/auth', // 认证请求
132 | '/admin', // 管理后台
133 | '/login', // 登录
134 | '/logout', // 登出
135 | ];
136 |
137 | // 3. 跳过指定路径的请求
138 | if (skipCachePaths.some(path => url.pathname.includes(path))) {
139 | console.log(`%c${logMessage} - 跳过缓存(指定路径)`, 'color: #607d8b;'); // 蓝灰色
140 | return;
141 | }
142 |
143 | // 4. 只缓存非 API 请求,且请求方式为 GET
144 | if (event.request.method === 'GET') {
145 | event.respondWith(
146 | caches.match(event.request).then((cachedResponse) => {
147 | if (cachedResponse) {
148 | console.log(`%c${logMessage} - 缓存命中`, 'color: #ff9800;'); // 橙色
149 | // 在后台更新缓存
150 | event.waitUntil(
151 | fetch(event.request).then((networkResponse) => {
152 | return caches.open('dynamic-cache').then((cache) => {
153 | cache.put(event.request, networkResponse.clone()).then(() => {
154 | console.log(`%c${logMessage} - 缓存已更新`, 'color: #00bcd4;'); // 青色
155 | });
156 | });
157 | }).catch((error) => {
158 | console.log(`%c${logMessage} - 缓存更新失败`, 'color: #f44336;'); // 红色
159 | })
160 | );
161 | return cachedResponse;
162 | }
163 |
164 | // 如果缓存中没有,进行网络请求
165 | console.log(`%c${logMessage} - 网络请求`, 'color: #3f51b5;'); // 靛蓝色
166 | return fetch(event.request).then((response) => {
167 | // 克隆响应,因为响应只能读取一次
168 | const responseClone = response.clone();
169 |
170 | // 缓存新响应
171 | caches.open('dynamic-cache').then((cache) => {
172 | cache.put(event.request, responseClone).then(() => {
173 | console.log(`%c${logMessage} - 缓存完成`, 'color: #4caf50;'); // 绿色
174 | });
175 | });
176 |
177 | return response;
178 | }).catch(() => {
179 | console.log(`%c${logMessage} - 网络失败`, 'color: #d32f2f;'); // 深红色
180 | });
181 | })
182 | );
183 | } else {
184 | console.log(`%c${logMessage} - 跳过缓存`, 'color: #607d8b;'); // 蓝灰色
185 | }
186 | });
187 |
--------------------------------------------------------------------------------
/JS/pwaghp.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Service Worker 配置文件
3 | * 实现了渐进式Web应用的离线缓存能力
4 | * 采用 Stale-While-Revalidate 策略:
5 | * 1. 优先使用缓存响应
6 | * 2. 同时在后台发起网络请求更新缓存
7 | * 3. 下次请求时使用更新后的缓存
8 | */
9 |
10 | // 日志颜色配置 - 使用七种主要颜色标识不同类型的操作
11 | const LOG_COLORS = {
12 | SUCCESS: '#4caf50', // 成功操作 - 绿色(缓存命中、更新成功)
13 | INFO: '#2196f3', // 普通信息 - 蓝色(网络请求、一般信息)
14 | WARN: '#ff9800', // 警告信息 - 橙色(缓存更新失败)
15 | ERROR: '#f44336', // 错误信息 - 红色(请求失败、严重错误)
16 | SKIP: '#757575', // 跳过操作 - 灰色(跳过缓存的请求)
17 | UPDATE: '#00bcd4', // 更新操作 - 青色(缓存更新操作)
18 | LIFECYCLE: '#9c27b0' // 生命周期 - 紫色(安装、激活事件)
19 | };
20 |
21 | /**
22 | * 缓存配置
23 | * 定义了需要缓存和禁止缓存的资源路径
24 | */
25 | const CACHE_CONFIG = {
26 | // 必须缓存的路径 - 这些路径下的资源无论请求方法都会被缓存
27 | cachePaths: [
28 | '/_avatars', // 用户头像等静态资源
29 | '/_assets', // JS、CSS等基础资源
30 | '/_private-user-images', // 用户上传的图片
31 | '/_camo', // 代理过的外部资源
32 | '/_raw' // 大文件等原始资源
33 | ],
34 | // 禁止缓存的路径 - 这些路径下的资源永远不会被缓存
35 | skipPaths: [
36 | '/login', // 登录请求
37 | '/sessions', // 会话相关
38 | '/c', // 会话相关
39 | '/chat', // 会话相关
40 | '/api', // 会话相关
41 | '/', // 根路径,避免所有路径都跳过
42 | '/blob', // 根路径,避免所有路径都跳过
43 | '/main', // 根路径,避免所有路径都跳过
44 | '/commit', // 根路径,避免所有路径都跳过
45 | ]
46 | };
47 |
48 | /**
49 | * 格式化日志输出
50 | * @param {string} message - 日志消息
51 | * @param {string} color - 日志颜色代码
52 | * @param {string} type - 日志类型标识
53 | */
54 | const log = (message, color, type = '') => {
55 | const prefix = type ? `[${type}] ` : '';
56 | console.log(`%c${prefix}${message}`, `color: ${color}; font-weight: bold;`);
57 | };
58 |
59 | /**
60 | * 检查请求是否应该跳过缓存
61 | * @param {Request} request - 请求对象
62 | * @param {URL} url - 解析后的URL对象
63 | * @returns {Object} 包含是否跳过的布尔值和具体原因
64 | */
65 | const shouldSkipCache = (request, url) => {
66 | // 跳过浏览器扩展请求
67 | if (url.protocol === 'chrome-extension:') {
68 | return {
69 | skip: true,
70 | reason: '浏览器扩展请求不缓存'
71 | };
72 | }
73 |
74 | // 精确匹配禁止缓存路径
75 | for (const skipPath of CACHE_CONFIG.skipPaths) {
76 | if (url.pathname === skipPath || url.pathname.startsWith(skipPath + '/')) {
77 | return {
78 | skip: true,
79 | reason: `路径在禁止缓存列表中: ${skipPath}`
80 | };
81 | }
82 | }
83 |
84 | // 检查缓存控制头
85 | const cacheControl = request.headers.get('Cache-Control');
86 | const pragma = request.headers.get('Pragma');
87 | if ((cacheControl && cacheControl.includes('no-store')) || pragma === 'no-cache') {
88 | return {
89 | skip: true,
90 | reason: '请求头指定不进行缓存'
91 | };
92 | }
93 |
94 | // 跳过带有认证信息的请求
95 | if (request.headers.get('Authorization')) {
96 | return {
97 | skip: true,
98 | reason: '带有认证信息的请求不缓存'
99 | };
100 | }
101 |
102 | return {
103 | skip: false,
104 | reason: ''
105 | };
106 | };
107 |
108 | /**
109 | * 更新缓存
110 | * @param {Request} request - 请求对象
111 | * @param {Response} response - 响应对象
112 | * @param {string} logMessage - 日志信息前缀
113 | */
114 | const updateCache = async (request, response, logMessage) => {
115 | // 检查响应的有效性
116 | if (!response || response.status !== 200 || response.type !== 'basic') {
117 | log(`${logMessage} - 响应不满足缓存条件: status=${response?.status}, type=${response?.type}`, LOG_COLORS.SKIP);
118 | return response;
119 | }
120 |
121 | try {
122 | // 打开缓存并存储响应
123 | const cache = await caches.open('dynamic-cache');
124 | const responseClone = response.clone();
125 | await cache.put(request, responseClone);
126 | log(`${logMessage} - 缓存已更新`, LOG_COLORS.UPDATE);
127 | } catch (error) {
128 | log(`${logMessage} - 缓存更新失败: ${error.message}`, LOG_COLORS.ERROR);
129 | }
130 |
131 | return response;
132 | };
133 |
134 | // Service Worker 安装事件 - 首次安装或更新时触发
135 | self.addEventListener('install', (event) => {
136 | log('Service Worker 安装完成', LOG_COLORS.LIFECYCLE, 'Install');
137 | self.skipWaiting(); // 跳过等待状态,直接激活
138 | });
139 |
140 | // Service Worker 激活事件 - 激活后开始接管页面请求
141 | self.addEventListener('activate', (event) => {
142 | log('Service Worker 激活完成', LOG_COLORS.LIFECYCLE, 'Activate');
143 | self.clients.claim(); // 立即接管所有页面
144 | });
145 |
146 | // Service Worker 请求拦截处理
147 | self.addEventListener('fetch', (event) => {
148 | // 验证请求的有效性
149 | if (!event.request?.url) {
150 | log('请求无效', LOG_COLORS.ERROR);
151 | return;
152 | }
153 |
154 | const url = new URL(event.request.url);
155 | const logMessage = `${event.request.method} ${url.pathname}`;
156 |
157 | // 检查是否需要跳过缓存
158 | const skipCheck = shouldSkipCache(event.request, url);
159 | if (skipCheck.skip) {
160 | log(`${logMessage} - 跳过缓存: ${skipCheck.reason}`, LOG_COLORS.SKIP);
161 | return;
162 | }
163 |
164 | // 判断是否需要缓存(在缓存路径列表中或是GET请求)
165 | const shouldCache = CACHE_CONFIG.cachePaths.some(path => url.pathname.includes(path)) ||
166 | event.request.method === 'GET';
167 |
168 | if (shouldCache) {
169 | event.respondWith((async () => {
170 | try {
171 | // 优先尝试从缓存获取响应
172 | const cachedResponse = await caches.match(event.request);
173 | if (cachedResponse) {
174 | log(`${logMessage} - 返回缓存的响应`, LOG_COLORS.SUCCESS);
175 |
176 | // 后台更新缓存(Stale-While-Revalidate 策略)
177 | event.waitUntil(
178 | fetch(event.request)
179 | .then(response => updateCache(event.request, response, logMessage))
180 | .catch(error => log(`${logMessage} - 后台更新失败: ${error.message}`,
181 | LOG_COLORS.WARN))
182 | );
183 | return cachedResponse;
184 | }
185 |
186 | // 缓存未命中,发起网络请求
187 | log(`${logMessage} - 发起网络请求`, LOG_COLORS.INFO);
188 | const networkResponse = await fetch(event.request);
189 | // 缓存网络响应
190 | await updateCache(event.request, networkResponse, logMessage);
191 | return networkResponse;
192 |
193 | } catch (error) {
194 | log(`${logMessage} - 请求处理失败: ${error.message}`, LOG_COLORS.ERROR);
195 | // 返回错误响应
196 | return new Response('网络请求失败', {
197 | status: 408,
198 | statusText: 'Request Timeout',
199 | headers: new Headers({
200 | 'Content-Type': 'text/plain; charset=utf-8'
201 | })
202 | });
203 | }
204 | })());
205 | } else {
206 | log(`${logMessage} - 跳过缓存: 非必缓存路径且非GET请求`, LOG_COLORS.SKIP);
207 | }
208 | });
209 |
--------------------------------------------------------------------------------
/JS/pwahubp.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Service Worker 配置文件
3 | * 实现了渐进式Web应用的离线缓存能力
4 | * 采用 Stale-While-Revalidate 策略:
5 | * 1. 优先使用缓存响应
6 | * 2. 同时在后台发起网络请求更新缓存
7 | * 3. 下次请求时使用更新后的缓存
8 | */
9 |
10 | // 缓存路径配置,只缓存包含以下路径的请求
11 | const CACHE_PATHS = [
12 | '/_avatars', // 用户头像等静态资源
13 | '/_assets', // JS、CSS等基础资源
14 | '/_private-user-images', // 用户上传的图片
15 | '/_camo', // 代理过的外部资源
16 | '/_raw' // 大文件等原始资源
17 | ];
18 |
19 | // 日志颜色配置 - 使用七种主要颜色标识不同类型的操作
20 | const LOG_COLORS = {
21 | SUCCESS: '#4caf50', // 成功操作 - 绿色(缓存命中、更新成功)
22 | INFO: '#2196f3', // 普通信息 - 蓝色(网络请求、一般信息)
23 | WARN: '#ff9800', // 警告信息 - 橙色(缓存更新失败)
24 | ERROR: '#f44336', // 错误信息 - 红色(请求失败、严重错误)
25 | SKIP: '#757575', // 跳过操作 - 灰色(跳过缓存的请求)
26 | UPDATE: '#00bcd4', // 更新操作 - 青色(缓存更新操作)
27 | LIFECYCLE: '#9c27b0'// 生命周期 - 紫色(安装、激活事件)
28 | };
29 |
30 | /**
31 | * 检查请求是否匹配需要缓存的路径
32 | * @param {string} pathname - URL 路径
33 | * @returns {boolean} 是否匹配缓存路径
34 | */
35 | const isCachePath = (pathname) => {
36 | return CACHE_PATHS.some(path => pathname.includes(path));
37 | };
38 |
39 | /**
40 | * 格式化日志输出
41 | * @param {string} message - 日志消息
42 | * @param {string} color - 日志颜色代码
43 | * @param {string} type - 日志类型标识
44 | */
45 | const log = (message, color, type = '') => {
46 | const prefix = type ? `[${type}] ` : '';
47 | console.log(`%c${prefix}${message}`, `color: ${color}; font-weight: bold;`);
48 | };
49 |
50 | /**
51 | * 检查请求是否应该跳过缓存
52 | * 先检查路径,如果 URL 中不包含指定路径则直接跳过缓存,再检查其他条件
53 | * @param {Request} request - 请求对象
54 | * @param {URL} url - 解析后的 URL 对象
55 | * @returns {Object} 包含是否跳过的布尔值和具体原因
56 | */
57 | const shouldSkipCache = (request, url) => {
58 | // 先判断 URL 路径是否包含缓存目录
59 | if (!isCachePath(url.pathname)) {
60 | return {
61 | skip: true,
62 | reason: `路径不包含缓存目录(${url.pathname})`
63 | };
64 | }
65 |
66 | // 如果不是 GET 请求,跳过缓存
67 | if (request.method !== 'GET') {
68 | return {
69 | skip: true,
70 | reason: '非 GET 请求不缓存'
71 | };
72 | }
73 |
74 | // 跳过浏览器扩展请求
75 | if (url.protocol === 'chrome-extension:') {
76 | return {
77 | skip: true,
78 | reason: '浏览器扩展请求不缓存'
79 | };
80 | }
81 |
82 | // 检查缓存控制头
83 | const cacheControl = request.headers.get('Cache-Control');
84 | const pragma = request.headers.get('Pragma');
85 | if ((cacheControl && cacheControl.includes('no-store')) || pragma === 'no-cache') {
86 | return {
87 | skip: true,
88 | reason: '请求头指定不进行缓存'
89 | };
90 | }
91 |
92 | // 跳过带有认证信息的请求
93 | if (request.headers.get('Authorization')) {
94 | return {
95 | skip: true,
96 | reason: '带有认证信息的请求不缓存'
97 | };
98 | }
99 |
100 | return {
101 | skip: false,
102 | reason: ''
103 | };
104 | };
105 |
106 | /**
107 | * 更新缓存
108 | * @param {Request} request - 请求对象
109 | * @param {Response} response - 响应对象
110 | * @param {string} logMessage - 日志信息前缀
111 | */
112 | const updateCache = async (request, response, logMessage) => {
113 | // 检查响应的有效性
114 | if (!response || response.status !== 200 || response.type !== 'basic') {
115 | log(`${logMessage} - 响应不满足缓存条件: status=${response?.status}, type=${response?.type}`, LOG_COLORS.SKIP);
116 | return response;
117 | }
118 |
119 | try {
120 | // 打开缓存并存储响应
121 | const cache = await caches.open('static-cache');
122 | const responseClone = response.clone();
123 | await cache.put(request, responseClone);
124 | log(`${logMessage} - 缓存已更新`, LOG_COLORS.UPDATE);
125 | } catch (error) {
126 | log(`${logMessage} - 缓存更新失败: ${error.message}`, LOG_COLORS.ERROR);
127 | }
128 |
129 | return response;
130 | };
131 |
132 | // Service Worker 安装事件 - 首次安装或更新时触发
133 | self.addEventListener('install', (event) => {
134 | log('Service Worker 安装完成', LOG_COLORS.LIFECYCLE, 'Install');
135 | self.skipWaiting(); // 跳过等待状态,直接激活
136 | });
137 |
138 | // Service Worker 激活事件 - 激活后开始接管页面请求
139 | self.addEventListener('activate', (event) => {
140 | log('Service Worker 激活完成', LOG_COLORS.LIFECYCLE, 'Activate');
141 | self.clients.claim(); // 立即接管所有页面
142 | });
143 |
144 | // Service Worker 请求拦截处理
145 | self.addEventListener('fetch', (event) => {
146 | // 验证请求的有效性
147 | if (!event.request?.url) {
148 | log('请求无效', LOG_COLORS.ERROR);
149 | return;
150 | }
151 |
152 | const url = new URL(event.request.url);
153 | const logMessage = `${event.request.method} ${url.pathname}`;
154 |
155 | // 先判断是否需要缓存,若路径不匹配则跳过缓存
156 | const skipCheck = shouldSkipCache(event.request, url);
157 | if (skipCheck.skip) {
158 | log(`${logMessage} - 跳过缓存: ${skipCheck.reason}`, LOG_COLORS.SKIP);
159 | return;
160 | }
161 |
162 | event.respondWith((async () => {
163 | try {
164 | // 优先尝试从缓存获取响应
165 | const cachedResponse = await caches.match(event.request);
166 | if (cachedResponse) {
167 | log(`${logMessage} - 返回缓存的响应`, LOG_COLORS.SUCCESS);
168 |
169 | // 后台更新缓存(Stale-While-Revalidate 策略)
170 | event.waitUntil(
171 | fetch(event.request)
172 | .then(response => updateCache(event.request, response, logMessage))
173 | .catch(error => log(`${logMessage} - 后台更新失败: ${error.message}`, LOG_COLORS.WARN))
174 | );
175 | return cachedResponse;
176 | }
177 |
178 | // 缓存未命中,发起网络请求
179 | log(`${logMessage} - 发起网络请求`, LOG_COLORS.INFO);
180 | const networkResponse = await fetch(event.request);
181 | // 缓存网络响应
182 | await updateCache(event.request, networkResponse, logMessage);
183 | return networkResponse;
184 |
185 | } catch (error) {
186 | log(`${logMessage} - 请求处理失败: ${error.message}`, LOG_COLORS.ERROR);
187 | // 返回错误响应
188 | return new Response('网络请求失败', {
189 | status: 408,
190 | statusText: 'Request Timeout',
191 | headers: new Headers({
192 | 'Content-Type': 'text/plain; charset=utf-8'
193 | })
194 | });
195 | }
196 | })());
197 | });
198 |
--------------------------------------------------------------------------------
/JS/pwamini.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Service Worker 配置文件
3 | * 实现了渐进式Web应用的离线缓存能力
4 | * 采用 Stale-While-Revalidate 策略:
5 | * 1. 优先使用缓存响应
6 | * 2. 同时在后台发起网络请求更新缓存
7 | * 3. 下次请求时使用更新后的缓存
8 | */
9 |
10 | // 日志颜色配置 - 使用七种主要颜色标识不同类型的操作
11 | const LOG_COLORS = {
12 | SUCCESS: '#4caf50', // 成功操作 - 绿色(缓存命中、更新成功)
13 | INFO: '#2196f3', // 普通信息 - 蓝色(网络请求、一般信息)
14 | WARN: '#ff9800', // 警告信息 - 橙色(缓存更新失败)
15 | ERROR: '#f44336', // 错误信息 - 红色(请求失败、严重错误)
16 | SKIP: '#757575', // 跳过操作 - 灰色(跳过缓存的请求)
17 | UPDATE: '#00bcd4', // 更新操作 - 青色(缓存更新操作)
18 | LIFECYCLE: '#9c27b0' // 生命周期 - 紫色(安装、激活事件)
19 | };
20 |
21 | /**
22 | * 检查是否为静态资源
23 | * @param {string} pathname - URL 路径
24 | * @returns {boolean} 是否为静态资源
25 | */
26 | const isStaticResource = (pathname) => {
27 | // 定义静态资源的文件扩展名
28 | const staticExtensions = [
29 | '.js', '.css', '.png', '.jpg', '.jpeg', '.gif',
30 | '.svg', '.ico', '.woff', '.woff2', '.ttf', '.eot'
31 | ];
32 | return staticExtensions.some(ext => pathname.toLowerCase().endsWith(ext));
33 | };
34 |
35 | /**
36 | * 格式化日志输出
37 | * @param {string} message - 日志消息
38 | * @param {string} color - 日志颜色代码
39 | * @param {string} type - 日志类型标识
40 | */
41 | const log = (message, color, type = '') => {
42 | const prefix = type ? `[${type}] ` : '';
43 | console.log(`%c${prefix}${message}`, `color: ${color}; font-weight: bold;`);
44 | };
45 |
46 | /**
47 | * 检查请求是否应该跳过缓存
48 | * @param {Request} request - 请求对象
49 | * @param {URL} url - 解析后的URL对象
50 | * @returns {Object} 包含是否跳过的布尔值和具体原因
51 | */
52 | const shouldSkipCache = (request, url) => {
53 | // 如果不是 GET 请求,跳过缓存
54 | if (request.method !== 'GET') {
55 | return {
56 | skip: true,
57 | reason: '非 GET 请求不缓存'
58 | };
59 | }
60 |
61 | // 如果不是静态资源,跳过缓存
62 | if (!isStaticResource(url.pathname)) {
63 | return {
64 | skip: true,
65 | reason: '非静态资源不缓存'
66 | };
67 | }
68 |
69 | // 跳过浏览器扩展请求
70 | if (url.protocol === 'chrome-extension:') {
71 | return {
72 | skip: true,
73 | reason: '浏览器扩展请求不缓存'
74 | };
75 | }
76 |
77 | // 检查缓存控制头
78 | const cacheControl = request.headers.get('Cache-Control');
79 | const pragma = request.headers.get('Pragma');
80 | if ((cacheControl && cacheControl.includes('no-store')) || pragma === 'no-cache') {
81 | return {
82 | skip: true,
83 | reason: '请求头指定不进行缓存'
84 | };
85 | }
86 |
87 | // 跳过带有认证信息的请求
88 | if (request.headers.get('Authorization')) {
89 | return {
90 | skip: true,
91 | reason: '带有认证信息的请求不缓存'
92 | };
93 | }
94 |
95 | return {
96 | skip: false,
97 | reason: ''
98 | };
99 | };
100 |
101 | /**
102 | * 更新缓存
103 | * @param {Request} request - 请求对象
104 | * @param {Response} response - 响应对象
105 | * @param {string} logMessage - 日志信息前缀
106 | */
107 | const updateCache = async (request, response, logMessage) => {
108 | // 检查响应的有效性
109 | if (!response || response.status !== 200 || response.type !== 'basic') {
110 | log(`${logMessage} - 响应不满足缓存条件: status=${response?.status}, type=${response?.type}`, LOG_COLORS.SKIP);
111 | return response;
112 | }
113 |
114 | try {
115 | // 打开缓存并存储响应
116 | const cache = await caches.open('static-cache');
117 | const responseClone = response.clone();
118 | await cache.put(request, responseClone);
119 | log(`${logMessage} - 缓存已更新`, LOG_COLORS.UPDATE);
120 | } catch (error) {
121 | log(`${logMessage} - 缓存更新失败: ${error.message}`, LOG_COLORS.ERROR);
122 | }
123 |
124 | return response;
125 | };
126 |
127 | // Service Worker 安装事件 - 首次安装或更新时触发
128 | self.addEventListener('install', (event) => {
129 | log('Service Worker 安装完成', LOG_COLORS.LIFECYCLE, 'Install');
130 | self.skipWaiting(); // 跳过等待状态,直接激活
131 | });
132 |
133 | // Service Worker 激活事件 - 激活后开始接管页面请求
134 | self.addEventListener('activate', (event) => {
135 | log('Service Worker 激活完成', LOG_COLORS.LIFECYCLE, 'Activate');
136 | self.clients.claim(); // 立即接管所有页面
137 | });
138 |
139 | // Service Worker 请求拦截处理
140 | self.addEventListener('fetch', (event) => {
141 | // 验证请求的有效性
142 | if (!event.request?.url) {
143 | log('请求无效', LOG_COLORS.ERROR);
144 | return;
145 | }
146 |
147 | const url = new URL(event.request.url);
148 | const logMessage = `${event.request.method} ${url.pathname}`;
149 |
150 | // 检查是否需要跳过缓存
151 | const skipCheck = shouldSkipCache(event.request, url);
152 | if (skipCheck.skip) {
153 | log(`${logMessage} - 跳过缓存: ${skipCheck.reason}`, LOG_COLORS.SKIP);
154 | return;
155 | }
156 |
157 | event.respondWith((async () => {
158 | try {
159 | // 优先尝试从缓存获取响应
160 | const cachedResponse = await caches.match(event.request);
161 | if (cachedResponse) {
162 | log(`${logMessage} - 返回缓存的响应`, LOG_COLORS.SUCCESS);
163 |
164 | // 后台更新缓存(Stale-While-Revalidate 策略)
165 | event.waitUntil(
166 | fetch(event.request)
167 | .then(response => updateCache(event.request, response, logMessage))
168 | .catch(error => log(`${logMessage} - 后台更新失败: ${error.message}`,
169 | LOG_COLORS.WARN))
170 | );
171 | return cachedResponse;
172 | }
173 |
174 | // 缓存未命中,发起网络请求
175 | log(`${logMessage} - 发起网络请求`, LOG_COLORS.INFO);
176 | const networkResponse = await fetch(event.request);
177 | // 缓存网络响应
178 | await updateCache(event.request, networkResponse, logMessage);
179 | return networkResponse;
180 |
181 | } catch (error) {
182 | log(`${logMessage} - 请求处理失败: ${error.message}`, LOG_COLORS.ERROR);
183 | // 返回错误响应
184 | return new Response('网络请求失败', {
185 | status: 408,
186 | statusText: 'Request Timeout',
187 | headers: new Headers({
188 | 'Content-Type': 'text/plain; charset=utf-8'
189 | })
190 | });
191 | }
192 | })());
193 | });
194 |
--------------------------------------------------------------------------------
/JS/tes.js:
--------------------------------------------------------------------------------
1 |
2 | const isStashiOS = 'undefined' !== typeof $environment && $environment['stash-version'];
3 | const isSurgeiOS = 'undefined' !== typeof $environment && $environment['surge-version'];
4 | const isShadowrocket = 'undefined' !== typeof $rocket;
5 | const isLooniOS = 'undefined' != typeof $loon;
6 | const iconStatus = $persistentStore.read("启用插件随机图标") ?? "启用";
7 | const iconReplace = $persistentStore.read("替换原始插件图标");
8 | const iconLibrary1 = $persistentStore.read("插件随机图标合集") ?? "Doraemon(100P)";
9 | const iconLibrary2 = iconLibrary1.split("(")[0];
10 |
11 | var name = "";
12 | var desc = "";
13 | var req
14 | var urlArg
15 | if (isLooniOS || isSurgeiOS || isShadowrocket){
16 | req = $request.url.replace(/loon$|loon\?.*/,'');
17 | if ($request.url.indexOf("loon?") != -1){
18 | urlArg = "?" + $request.url.split("loon?")[1];
19 | }else{urlArg = ""};
20 |
21 | }else if (isStashiOS){
22 | req = $request.url.replace(/loon\.stoverride$|loon\.stoverride\?.*/,'');
23 | if ($request.url.indexOf("loon.stoverride?") != -1){
24 | urlArg = "?" + $request.url.split("loon.stoverride?")[1];
25 | }else{urlArg = ""};
26 | };
27 | var rewriteName = req.substring(req.lastIndexOf('/') + 1).split('.')[0];
28 | var original = [];//用于获取原文行号
29 | //获取参数
30 | var nName = urlArg.search(/\?n=|&n=/) != -1 ? (urlArg.split(/\?n=|&n=/)[1].split("&")[0].split("+")) : null;
31 | var Pin0 = urlArg.search(/\?y=|&y=/) != -1 ? (urlArg.split(/\?y=|&y=/)[1].split("&")[0].split("+")).map(decodeURIComponent) : null;
32 | var Pout0 = urlArg.search(/\?x=|&x=/) != -1 ? (urlArg.split(/\?x=|&x=/)[1].split("&")[0].split("+")).map(decodeURIComponent) : null;
33 | var hnAdd = urlArg.search(/\?hnadd=|&hnadd=/) != -1 ? (urlArg.split(/\?hnadd=|&hnadd=/)[1].split("&")[0].replace(/%20/g,"").split(",")) : null;
34 | var hnDel = urlArg.search(/\?hndel=|&hndel=/) != -1 ? (urlArg.split(/\?hndel=|&hndel=/)[1].split("&")[0].replace(/%20/g,"").split(",")) : null;
35 | var icon = "";
36 | var delNoteSc = urlArg.search(/\?del=|&del=/) != -1 ? true : false;
37 |
38 | //修改名字和简介
39 | if (nName === null){
40 | name = rewriteName;
41 | desc = name;
42 | }else{
43 | name = nName[0] != "" ? nName[0] : rewriteName;
44 | desc = nName[1] != undefined ? nName[1] : name;
45 | };
46 | if (isLooniOS || isSurgeiOS || isShadowrocket){
47 | name = "#!name=" + decodeURIComponent(name);
48 | desc = "#!desc=" + decodeURIComponent(desc);
49 | }else if (isStashiOS){
50 | name = 'name: ' + '"' + decodeURIComponent(name) + '"';
51 | desc = 'desc: ' + '"' + decodeURIComponent(desc) + '"';
52 | };
53 |
54 | let npluginDesc = name + "\n" + desc;
55 |
56 | if(isLooniOS && iconStatus == "启用"){
57 | const stickerStartNum = 1001;
58 | const stickerSum = iconLibrary1.split("(")[1].split("P")[0];
59 | let randomStickerNum = parseInt(stickerStartNum + Math.random() * stickerSum).toString();
60 | icon = "#!icon=" + "https://github.com/Toperlock/Quantumult/raw/main/icon/" + iconLibrary2 + "/" + iconLibrary2 + "-" + randomStickerNum + ".png";
61 | };
62 | const pluginIcon = icon;
63 | console.log("插件图标:" + pluginIcon);
64 |
65 | !(async () => {
66 | let body = await http(req);
67 | //判断是否断网
68 | if(body == null || body == ""){if(isStashiOS || isSurgeiOS){
69 | console.log("Loon转换:未获取到body的链接为" + $request.url)
70 | $done({ response: { status: 404 ,body:{} } });}else{
71 | console.log("Loon转换:未获取到body的链接为" + $request.url)
72 | $done({ response: { status: 404 ,body:{} } });
73 | }//识别客户端通知
74 | }else{//以下开始重写及脚本转换
75 |
76 | original = body.replace(/^ *(#|;|\/\/)/g,'#').replace(/(^[^#].+)\x20+\/\/.+/g,"$1").split(/(\r\n)/);
77 |
78 | if (body.match(/\/\*+\n[\s\S]*\n\*+\/\n/)){
79 | body = body.replace(/[\s\S]*(\/\*+\n[\s\S]*\n\*+\/\n)[\s\S]*/,"$1").match(/[^\r\n]+/g);
80 | }else{
81 | body = body.match(/[^\r\n]+/g);};
82 |
83 | let pluginDesc = [];
84 | let httpFrame = "";
85 | let General = [];
86 | let rules = [];
87 | let script = [];
88 | let URLRewrite = [];
89 | let HeaderRewrite = [];
90 | let MapLocal = [];
91 | let cron = [];
92 | let providers = [];
93 | let MITM = "";
94 | let others = []; //不支持的内容
95 |
96 | body.forEach((x, y, z) => {
97 | x = x.replace(/^ *(#|;|\/\/)/,'#').replace(/, *REJECT/i,',REJECT').replace(/ reject/i,' reject').replace(/(^[^#].+)\x20+\/\/.+/,"$1").replace(/(hostname|force-http-engine-hosts|skip-proxy|always-real-ip)\x20*=/,'$1=').replace(/ *, *enabled *= *false/,"");
98 | //去掉注释
99 | if(Pin0 != null) {
100 | for (let i=0; i < Pin0.length; i++) {
101 | const elem = Pin0[i];
102 | if (x.indexOf(elem) != -1){
103 | x = x.replace(/^#/,"")
104 | }else{};
105 | };//循环结束
106 | }else{};//去掉注释结束
107 |
108 | //增加注释
109 | if(Pout0 != null){
110 | for (let i=0; i < Pout0.length; i++) {
111 | const elem = Pout0[i];
112 | if (x.indexOf(elem) != -1 && x.search(/^(hostname|force-http-engine-hosts|skip-proxy|always-real-ip)=/) == -1){
113 | x = "#" + x;
114 | }else{};
115 | };//循环结束
116 | }else{};//增加注释结束
117 |
118 | //添加主机名
119 | if (hnAdd != null){
120 | if (x.search(/^hostname=/) != -1){
121 | x = x.replace(/\x20/g,"").replace(/(.+)/,`$1,${hnAdd}`).replace(/,{2,}/g,",");
122 | }else{};
123 | }else{};//添加主机名结束
124 |
125 | //删除主机名
126 | if (hnDel != null && x.search(/^hostname=/) != -1){
127 | x = x.replace(/\x20/g,"").replace(/^hostname=/,"").replace(/%.*%/,"").replace(/,{2,}/g,",").split(",");
128 | for (let i=0; i < hnDel.length; i++) {
129 | const elem = hnDel[i];
130 | if (x.indexOf(elem) != -1){
131 | let hnInNum = x.indexOf(elem);
132 | delete x[hnInNum];
133 | }else{};
134 | };//循环结束
135 | x = "hostname=" + x;
136 | }else{};//删除主机名结束
137 |
138 | if (delNoteSc === true && x.match(/^#/) && x.indexOf("#!") == -1){
139 | x = "";
140 | };
141 |
142 | let type = x.match(
143 | /^#!|generic script-path=|http-re|\x20header-|cron |\x20reject|^hostname|^force-http-engine-hosts|^skip-proxy|^real-ip|\x20(302|307|header)($|\x20)|^#?(URL-REGEX|USER-AGENT|IP-CIDR|GEOIP|IP-ASN|DOMAIN)/
144 | )?.[0];
145 | //判断注释
146 | if (isLooniOS || isSurgeiOS || isShadowrocket){
147 |
148 | if (x.match(/^[^#]/)){
149 | var noteK = "";
150 | }else{
151 | var noteK = "#";
152 | };
153 | }else if (isStashiOS){
154 | if (x.match(/^[^#]/)){
155 | var noteKn8 = "\n ";
156 | var noteKn6 = "\n ";
157 | var noteKn4 = "\n ";
158 | var noteK4 = " ";
159 | var noteK2 = " ";
160 | }else{
161 | var noteKn8 = "\n# ";
162 | var noteKn6 = "\n# ";
163 | var noteKn4 = "\n# ";
164 | var noteK4 = "# ";
165 | var noteK2 = "# ";
166 | };
167 | };//判断注释结束
168 |
169 | if (type) {
170 | switch (type) {
171 | case "#!":
172 | if (isStashiOS){
173 | x = x.replace(/^#! *(name|desc) *= *(.*)/,'$1: "$2"');
174 |
175 | if (nName != null){
176 | x = x.replace(/^name:.*/,name).replace(/^desc:.*/,desc);
177 | };
178 | pluginDesc.push(x);
179 | };
180 |
181 | if (isLooniOS || isSurgeiOS || isShadowrocket){
182 | if (nName != null){
183 | x = x.replace(/^#!name *=.*/,name).replace(/^#!desc *=.*/,desc);};
184 | if (iconReplace == "启用"){
185 | x = x.replace(/^#!icon *=.*/,pluginIcon);
186 | };
187 | pluginDesc.push(x);
188 | };
189 |
190 | break;
191 |
192 | case "generic script-path=":
193 |
194 | if (isLooniOS){
195 | z[y - 1]?.match(/^#/) && script.push(z[y - 1]);
196 | script.push(x);};
197 | break;
198 |
199 | case "http-re":
200 |
201 | if (x.match(/http-(response|request)\x20/)){
202 | //脚本
203 | let ptn = x.replace(/\x20{2,}/g," ").split(" ")[1].replace(/"/gi,'');
204 |
205 | if (isSurgeiOS){
206 | ptn = ptn.replace(/(.*,.*)/,'"$1"');};
207 |
208 | let js = x.replace(/\x20/gi,"").split("script-path=")[1].split(",")[0];
209 |
210 | let sctype = x.match('http-response') ? 'response' : 'request';
211 |
212 | let scname = js.substring(js.lastIndexOf('/') + 1, js.lastIndexOf('.') );
213 |
214 | let arg = [];
215 |
216 | if (isSurgeiOS ||isShadowrocket){
217 | if (x.match(/,\x20*argument\x20*=.+/)){
218 | if (x.match(/,\x20*argument\x20*=\x20*"+.*?,.*?"+/)
219 | ){
220 | arg = ', argument=' + x.match(/,\x20*argument\x20*=\x20*("+.*?,.*?"+)/)[1];
221 | }else{
222 | arg = ", argument=" + x.replace(/,\x20*argument\x20*=/gi,",argument=").split(",argument=")[1].split(",")[0];}
223 | }else{};
224 |
225 | }else if (isStashiOS){
226 | if (x.match(/,\x20*argument\x20*=.+/)){
227 | if (x.match(/,\x20*argument\x20*=\x20*"+.*?,.*?"+/)
228 | ){
229 | arg = x.match(/,\x20*argument\x20*=\x20*("+.*?,.*?"+)/)[1];
230 |
231 | if (arg.match(/^".+"$/)){
232 | arg = `${noteKn6}argument: |-${noteKn8}` + arg.replace(/^"(.+)"$/,'$1');};
233 | }else{
234 | arg = `${noteKn6}argument: |-${noteKn8}` + x.replace(/,\x20*argument\x20*=/gi,",argument=").split(",argument=")[1].split(",")[0];}
235 |
236 | }else{};
237 |
238 | };
239 |
240 | if (isLooniOS){
241 |
242 | z[y - 1]?.match(/^#/) && script.push(z[y - 1]);
243 |
244 | script.push(x);
245 |
246 | }else if (isSurgeiOS || isShadowrocket){
247 |
248 | z[y - 1]?.match(/^#/) && script.push(z[y - 1]);
249 |
250 | let proto = x.replace(/\x20/gi,'').match('binary-body-mode=(true|1)') ? ', binary-body-mode=true' : '';
251 |
252 | let rebody = x.replace(/\x20/gi,'').match('requires-body=(true|1)') ? ', requires-body=true' : '';
253 |
254 | let size = x.replace(/\x20/g,'').match('requires-body=(true|1)') ? ', max-size=3145728' : '';
255 |
256 | script.push(
257 | `${noteK}${scname}_${y} = type=http-${sctype}, pattern=${ptn}, script-path=${js}${rebody}${size}${proto}, timeout=30${arg}`);
258 |
259 | }else if (isStashiOS){
260 |
261 | let proto = x.replace(/\x20/g,'').match('binary-body-mode=(true|1)') ? 'binary-mode: true' : '';
262 |
263 | let rebody = x.replace(/\x20/g,'').match('requires-body=(true|1)') ? 'require-body: true' : '';
264 |
265 | let size = x.replace(/\x20/g,'').match('requires-body=(true|1)') ? 'max-size: 3145728' : '';
266 |
267 | script.push(
268 | `${noteKn4}- match: ${ptn}${noteKn6}name: ${scname}_${y}${noteKn6}type: ${sctype}${noteKn6}timeout: 30${noteKn6}${rebody}${noteKn6}${size}${arg}${noteKn6}${proto}`
269 | );
270 | providers.push(
271 | `${noteK2}${scname}_${y}:${noteKn4}url: ${js}${noteKn4}interval: 86400`
272 | );
273 | };
274 |
275 | }else{
276 | let lineNum = (original.indexOf(x) + 2)/2;
277 | others.push(lineNum + "行" + x)};//整个http-re结束
278 |
279 | break;
280 |
281 | //HeaderRewrite
282 | case " header-":
283 |
284 | if (isLooniOS){
285 | z[y - 1]?.match(/^#/) && URLRewrite.push(z[y - 1]);
286 | URLRewrite.push(x)
287 |
288 | }else if (isStashiOS){
289 |
290 | z[y - 1]?.match(/^#/) && HeaderRewrite.push(" " + z[y - 1]);
291 |
292 | HeaderRewrite.push(`${noteK4}- ` + x.replace(/\x20header-/,`\x20request-`).replace(/^#/,""))
293 | }else if (isSurgeiOS){
294 |
295 | z[y - 1]?.match(/^#/) && HeaderRewrite.push(z[y - 1]);
296 |
297 | HeaderRewrite.push(`${noteK}http-request ` + x.replace(/^#/,""))
298 | }else if (isShadowrocket){
299 | let lineNum = (original.indexOf(x) + 2)/2;
300 | others.push(lineNum + "行" + x)
301 | };//HeaderRewrite结束
302 |
303 | break;
304 |
305 | //定时任务
306 | case "cron ":
307 |
308 | let cronExp = x.split('"')[1];
309 |
310 | let cronJs = x.replace(/\x20/gi,"").split("script-path=")[1].split(",")[0];
311 |
312 | let croName;
313 |
314 | if (x.search(/, *tag *=/) != -1){
315 | croName = x.replace(/\x20/g,"").split("tag=")[1].split(",")[0];
316 | }else{
317 | croName = cronJs.substring(cronJs.lastIndexOf('/') + 1, cronJs.lastIndexOf('.'));};
318 |
319 | if (isLooniOS){
320 |
321 | script.push(x);
322 |
323 | }else if (isStashiOS){
324 |
325 | cronExp = cronExp.replace(/[^\s]+ ([^\s]+ [^\s]+ [^\s]+ [^\s]+ [^\s]+)/,'$1');
326 |
327 | cron.push(
328 | `${noteKn4}- name: ${croName}${noteKn6}cron: "${cronExp}"${noteKn6}timeout: 60`
329 | );
330 | providers.push(
331 | `${noteK2}${croName}:${noteKn4}url: ${cronJs}${noteKn4}interval: 86400`
332 | );
333 |
334 | }else if (isSurgeiOS || isShadowrocket){
335 | script.push(
336 | `${noteK}${croName} = type=cron, cronexp="${cronExp}", script-path=${cronJs}, timeout=60, wake-system=1`
337 | )
338 | };
339 | break;
340 |
341 | //REJECT
342 |
343 | case " reject":
344 |
345 | let rejectType = x.split(" ")[x.split(" ").length - 1].toLowerCase().replace(/video/,"img");
346 |
347 | let rejectPtn = x.split(" ")[0].replace(/^#/,"");
348 |
349 | if (x.search(/ reject(-200|-img|-dict|-array|-video)?$/i) == -1){
350 |
351 | }else if (isLooniOS){
352 |
353 | z[y - 1]?.match(/^#/) && URLRewrite.push(z[y - 1]);
354 |
355 | URLRewrite.push(x);
356 |
357 | }else if (isStashiOS){
358 |
359 | z[y - 1]?.match(/^#/) && URLRewrite.push(" " + z[y - 1]);
360 |
361 | URLRewrite.push(
362 | `${noteKn4}- ${rejectPtn} - ${rejectType}`);
363 |
364 | }else if (isShadowrocket){
365 |
366 | z[y - 1]?.match(/^#/) && URLRewrite.push(z[y - 1]);
367 |
368 | URLRewrite.push(
369 | `${noteK}${rejectPtn} - ${rejectType}`);
370 |
371 | }else if (isSurgeiOS){
372 |
373 | if (rejectType.match("-")){
374 | //reject-
375 |
376 | z[y - 1]?.match(/^#/) && MapLocal.push(z[y - 1]);
377 |
378 | if (rejectType.match(/dict$/)){
379 | rejectType = "https://raw.githubusercontent.com/mieqq/mieqq/master/reject-dict.json"
380 | }else if (rejectType.match(/array$/)){
381 | rejectType = "https://raw.githubusercontent.com/mieqq/mieqq/master/reject-array.json"
382 | }else if (rejectType.match(/200$/)){
383 | rejectType = "https://raw.githubusercontent.com/mieqq/mieqq/master/reject-200.txt"
384 | }else if (rejectType.match(/img$/)){
385 | rejectType = "https://raw.githubusercontent.com/mieqq/mieqq/master/reject-img.gif"
386 | };
387 | MapLocal.push(
388 | `${rejectPtn} data="${rejectType}"`);
389 |
390 | }else{//reject
391 |
392 | z[y - 1]?.match(/^#/) && URLRewrite.push(z[y - 1]);
393 |
394 | URLRewrite.push(
395 | `${noteK}${rejectPtn} - reject`);
396 |
397 | }
398 |
399 | };
400 | break;
401 |
402 | //hostname
403 | case "hostname":
404 |
405 | if (isLooniOS){
406 | MITM = "[MITM]\n\n" + x.replace(/ *= */," = ").replace(/= ,+/,"= ");
407 | }else if (isSurgeiOS || isShadowrocket){
408 | MITM = x.replace(/%.*%/g,"").replace(/\x20/g,"").replace(/,{2,}/g,",").replace(/,*\x20*$/,"").replace(/hostname=(.*)/, `[MITM]\n\nhostname = %APPEND% $1`).replace(/%\x20,+/,"% ");
409 | }else if (isStashiOS){
410 | MITM = x.replace(/%.*%/g,"").replace(/\x20/g,"").replace(/,{2,}/g,",").replace(/,*\x20*$/,"").replace(/hostname=(.*)/, `t&2;mitm:\nt&hn;"$1"`).replace(/",+/,'"');
411 | };
412 | break;
413 |
414 | //general
415 |
416 | case "force-http-engine-hosts":
417 |
418 | if (isLooniOS){
419 | General.push(x);
420 | }else if(isSurgeiOS || isShadowrocket){
421 | General.push(x.replace(/\x20/g,"").replace(/=/," = %APPEND% "))
422 | }else if (isStashiOS){
423 | General.push(x.replace(/%.*%/g,"").replace(/\x20/g,"").replace(/,{2,}/g,",").replace(/,*\x20*$/,"").replace(/force-http-engine-hosts=(.*)/, `t&2;force-http-engine:\nt&hn;"$1"`).replace(/",+/,'"'))
424 | };
425 | break;
426 |
427 | case "skip-proxy":
428 |
429 | if (isLooniOS){
430 | General.push(x.replace(/%.*%/g,"").replace(/ *= */," = "));
431 | }else if(isSurgeiOS || isShadowrocket){
432 | General.push(x.replace(/\x20/g,"").replace(/=/," = %APPEND% "))
433 | }else if (isStashiOS){};
434 | break;
435 |
436 | case "real-ip":
437 |
438 | if (isLooniOS){
439 | General.push(x.replace(/%.*%/g,"").replace(/ *= */," = "));
440 | }else if(isSurgeiOS || isShadowrocket){
441 | General.push(x.replace(/\x20/g,"").replace(/=/," = %APPEND% "));
442 | }else if (isStashiOS){
443 | General.push(x.replace(/%.*%/g,"").replace(/\x20/g,"").replace(/,{2,}/g,",").replace(/,*\x20*$/,"").replace(/always-real-ip=(.*)/, `t&2;fake-ip-filter:\nt&hn;"$1"`).replace(/",+/,'"'))
444 | };
445 | break;
446 |
447 | default:
448 | //重定向
449 | if (type.match(/ 302|307|header/)){
450 | let rewType = x.match(/302|307|header/);
451 | if (isLooniOS){
452 | z[y - 1]?.match(/^#/) && URLRewrite.push(z[y - 1]);
453 |
454 | URLRewrite.push(x);
455 |
456 | }else if (isStashiOS){
457 |
458 | z[y - 1]?.match(/^#/) && URLRewrite.push(" " + z[y - 1]);
459 |
460 | URLRewrite.push(`${noteKn4}- ` + x.replace(/^#/,"").replace(/ (302|307|header) */," ").replace(/(.+)/,`$1 ${rewType}`).replace(/\x20{2,}/g," "));
461 | }else if(isSurgeiOS || isShadowrocket){
462 | z[y - 1]?.match(/^#/) && URLRewrite.push(z[y - 1]);
463 |
464 | URLRewrite.push(x.replace(/ (302|307|header) */," ").replace(/(.+)/,`$1 ${rewType}`).replace(/\x20{2,}/g," "));
465 |
466 | };
467 |
468 | }else{
469 |
470 | if (isLooniOS){
471 | z[y - 1]?.match(/^#/) && rules.push(z[y - 1]);
472 | rules.push(x);
473 |
474 | }else if (isSurgeiOS || isShadowrocket){
475 | if (x.match(/^#?(DOM|USER|URL|IP|GEO)[^,]+,[^,]+$/i) || x.match(/proxy$/i)){
476 | x = "";}else{rules.push(x.replace(/, *REJECT.*/i,",REJECT"));};
477 |
478 | }else if(isStashiOS){
479 |
480 | if (type.match(/URL-REGEX/i) && x.match(/,\x20*REJECT/i)){
481 |
482 | z[y - 1]?.match(/^#/) && URLRewrite.push(" " + z[y - 1]);
483 | x = x.replace(/\x20/,"");
484 |
485 | let Urx2Reject
486 |
487 | if (x.match(/DICT$/i)){
488 | Urx2Reject = '-dict';
489 | }else if (x.match(/ARRAY$/i)){
490 | Urx2Reject = '-array';
491 | }else if (x.match(/DROP$/i)){
492 | Urx2Reject = '-200';
493 | }else if (x.match(/IMG$|VIDEO$/i)){
494 | Urx2Reject = '-img';
495 | }else if (x.match(/REJECT$/i)){
496 | Urx2Reject = '';
497 | };
498 |
499 | URLRewrite.push(
500 | x.replace(/.*URL-REGEX,([^\s]+),[^,]+/,
501 | `${noteKn4}- $1 - reject${Urx2Reject}`)
502 | );
503 | }else if (x.match(/^#?(DOM|USER|URL|IP|GEO)[^,]+,[^,]+$/i) || x.match(/proxy$/i)){ x = "";}else if(type.match(/^#?(USER-AGENT|IP-CIDR|GEOIP|IP-ASN|DOMAIN)/)){
504 | z[y - 1]?.match(/^#/) && rules.push(" " + z[y - 1]);
505 |
506 | rules.push(x.replace(/\x20/g,"").replace(/.*DOMAIN-SET.+/,"").replace(/,REJECT.+/,",REJECT").replace(/^#?(.+)/,`${noteK2}- $1`))
507 | }else{
508 | let lineNum = (original.indexOf(x) + 2)/2;
509 | others.push(lineNum + "行" + x)};
510 | }//Stash rules处理完毕
511 | }//rules处理完毕
512 | } //switch结束
513 | }
514 | }); //循环结束
515 |
516 | if (isLooniOS){
517 | pluginDesc = (pluginDesc[0] || '') && `${pluginDesc.join("\n")}`;
518 |
519 | if (pluginDesc !="" && pluginDesc.search(/#! *name *=/) != -1){
520 |
521 | if (pluginDesc.search(/#! *icon *= *.+/) == -1){
522 | pluginDesc = pluginDesc + "\n" + pluginIcon;
523 |
524 | }else{pluginDesc = pluginDesc;};
525 |
526 | }else{
527 | pluginDesc = npluginDesc + "\n" + pluginIcon;
528 | };
529 |
530 | if (iconReplace == "启用" && pluginDesc.search(/#!icon=/) == -1 ){
531 | pluginDesc = pluginDesc + "\n" + pluginIcon};
532 |
533 | General = (General[0] || '') && `[General]\n\n${General.join("\n\n")}`;
534 |
535 | script = (script[0] || '') && `[Script]\n\n${script.join("\n\n")}`;
536 |
537 | URLRewrite = (URLRewrite[0] || '') && `[Rewrite]\n\n${URLRewrite.join("\n")}`;
538 |
539 | rules = (rules[0] || '') && `[Rule]\n\n${rules.join("\n")}`;
540 |
541 | others = (others[0] || '') && `${others.join("\n")}`;
542 |
543 | body = `${pluginDesc}
544 |
545 |
546 | ${General}
547 |
548 |
549 | ${rules}
550 |
551 |
552 | ${URLRewrite}
553 |
554 |
555 | ${script}
556 |
557 |
558 | ${MITM}`
559 | .replace(/t&zd;/g,',')
560 | .replace(/(#.+\n)\n+(?!\[)/g,'$1')
561 | .replace(/\n{2,}/g,'\n\n')
562 | }else if (isStashiOS){
563 | pluginDesc = (pluginDesc[0] || '') && `${pluginDesc.join("\n")}`;
564 |
565 | if (pluginDesc !="" && pluginDesc.search(/name: /) != -1){
566 | pluginDesc = pluginDesc;
567 | }else{
568 | pluginDesc = npluginDesc;
569 | };
570 |
571 | General = (General[0] || '') && `${General.join("\n")}`;
572 |
573 | rules = (rules[0] || '') && `rules:\n${rules.join("\n")}`;
574 |
575 | script = (script[0] || '') && ` script:\n${script.join("\n\n")}`;
576 |
577 | providers = (providers[0] || '') && `script-providers:\n${providers.join("\n")}`;
578 |
579 | cron = (cron[0] || '') && `cron:\n script:\n${cron.join("\n")}`;
580 |
581 | URLRewrite = (URLRewrite[0] || '') && ` rewrite:\n${URLRewrite.join("\n")}`;
582 |
583 | URLRewrite = URLRewrite.replace(/"/gi,'')
584 |
585 | HeaderRewrite = (HeaderRewrite[0] || '') && ` header-rewrite:\n${HeaderRewrite.join("\n")}`;
586 |
587 | HeaderRewrite = HeaderRewrite.replace(/"/gi,'')
588 |
589 | others = (others[0] || '') && `${others.join("\n")}`;
590 |
591 | General = General.replace(/t&2;/g,' ')
592 | .replace(/t&hn;/g,' - ')
593 | .replace(/\,/g,'"\n - "')
594 |
595 | MITM = MITM.replace(/t&2;/g,' ')
596 | .replace(/t&hn;/g,' - ')
597 | .replace(/\,/g,'"\n - "')
598 |
599 | if (URLRewrite != "" || script != "" || HeaderRewrite != "" || MITM != "" || General != ""){
600 | httpFrame = `http:
601 | ${General}
602 |
603 | ${HeaderRewrite}
604 |
605 | ${URLRewrite}
606 |
607 | ${script}
608 |
609 | ${MITM}`
610 | };
611 |
612 | body = `${pluginDesc}
613 |
614 |
615 | ${rules}
616 |
617 | ${httpFrame}
618 |
619 | ${cron}
620 |
621 | ${providers}`
622 | .replace(/t&zd;/g,',')
623 | .replace(/script-providers:\n+$/g,'')
624 | .replace(/# \n/gi,'\n')
625 | .replace(/ \n/g,"")
626 | .replace(/(#.+\n)\n+(?!\[)/g,'$1')
627 | .replace(/\n{2,}/g,'\n\n')
628 |
629 | }else if (isSurgeiOS || isShadowrocket){
630 | pluginDesc = (pluginDesc[0] || '') && `${pluginDesc.join("\n")}`;
631 |
632 | if (pluginDesc !="" && pluginDesc.search(/#! *name *=/) != -1){
633 | pluginDesc = pluginDesc;
634 | }else{
635 | pluginDesc = npluginDesc;
636 | };
637 |
638 | General = (General[0] || '') && `[General]\n\n${General.join("\n\n")}`;
639 |
640 | rules = (rules[0] || '') && `[Rule]\n\n${rules.join("\n")}`;
641 |
642 | script = (script[0] || '') && `[Script]\n\n${script.join("\n\n")}`;
643 |
644 | HeaderRewrite = (HeaderRewrite[0] || '') && `[Header Rewrite]\n\n${HeaderRewrite.join("\n")}`;
645 |
646 | URLRewrite = (URLRewrite[0] || '') && `[URL Rewrite]\n\n${URLRewrite.join("\n")}`;
647 |
648 | MapLocal = (MapLocal[0] || '') && `[Map Local]\n\n${MapLocal.join("\n\n")}`;
649 |
650 | others = (others[0] || '') && `${others.join("\n\n")}`;
651 |
652 | body = `${pluginDesc}
653 |
654 |
655 | ${General}
656 |
657 |
658 | ${rules}
659 |
660 |
661 | ${HeaderRewrite}
662 |
663 |
664 | ${URLRewrite}
665 |
666 |
667 | ${script}
668 |
669 |
670 | ${MapLocal}
671 |
672 |
673 | ${MITM}`
674 | .replace(/(#.+\n)\n+(?!\[)/g,'$1')
675 | .replace(/\n{2,}/g,'\n\n')
676 | }
677 |
678 |
679 | if (isStashiOS || isSurgeiOS) {
680 | others !=""
681 | } else if (isLooniOS || isShadowrocket) {
682 | others !="" && };
683 |
684 | $done({ response: { status: 200 ,body:body ,headers: {'Content-Type': 'text/plain; charset=utf-8'} } });
685 | }//判断是否断网的反括号
686 |
687 |
688 | })()
689 | .catch((e) => {
690 |
691 | $done()
692 | })
693 |
694 |
695 | function http(req) {
696 | return new Promise((resolve, reject) =>
697 | $httpClient.get(req, (err, resp,data) => {
698 | resolve(data)
699 | })
700 | )
701 | }
702 |
--------------------------------------------------------------------------------
/JS/webmailin.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | let isInitialized = false;
3 |
4 | // 简单日志函数
5 | function log(msg) {
6 | console.log('[PullToRefresh]', msg);
7 | }
8 |
9 | // 注入样式
10 | function injectStyle() {
11 | if (!document.querySelector('#ptr-style')) {
12 | const style = document.createElement('style');
13 | style.id = 'ptr-style';
14 | style.textContent = '.ptr--text, .ptr--icon { color: #9b685b !important; }';
15 | document.documentElement.appendChild(style);
16 | log('样式已注入');
17 | }
18 | }
19 |
20 | // 初始化下拉刷新
21 | function initPullToRefresh() {
22 | // 避免重复初始化
23 | if (isInitialized) return;
24 |
25 | injectStyle();
26 |
27 | // 确保 PullToRefresh 库已加载
28 | if (window.PullToRefresh) {
29 | try {
30 | PullToRefresh.init({
31 | // 外层监听区域
32 | mainElement: '#messagelist-header',
33 | // 判断是否允许下拉刷新的逻辑:只有当内部滚动容器处于最顶部时才允许
34 | shouldPullToRefresh() {
35 | const content = document.querySelector('#messagelist-content');
36 | // 如果内部容器存在且滚动到顶部则返回 true,否则返回 false
37 | return content && content.scrollTop === 0;
38 | },
39 | onRefresh() {
40 | log('触发刷新');
41 | window.location.reload();
42 | }
43 | });
44 | isInitialized = true;
45 | log('初始化成功');
46 | return;
47 | } catch (e) {
48 | log('初始化失败,重试中');
49 | }
50 | }
51 |
52 | // 如果库未加载,则动态加载库
53 | const script = document.createElement('script');
54 | script.src = 'https://cdn.jsdelivr.net/npm/pulltorefreshjs/dist/index.umd.min.js';
55 | script.onload = () => {
56 | log('库加载完成');
57 | setTimeout(initPullToRefresh, 100);
58 | };
59 | script.onerror = () => {
60 | log('库加载失败,重试中');
61 | setTimeout(initPullToRefresh, 100);
62 | };
63 | document.documentElement.appendChild(script);
64 | }
65 |
66 | // 检查外层元素是否存在,如果不存在则等待出现
67 | function waitForOuterElement() {
68 | const header = document.querySelector('#messagelist-header');
69 | if (header) {
70 | initPullToRefresh();
71 | } else {
72 | // MutationObserver 监听 DOM 变化
73 | const observer = new MutationObserver((mutations, obs) => {
74 | if (document.querySelector('#messagelist-header')) {
75 | initPullToRefresh();
76 | obs.disconnect();
77 | }
78 | });
79 | observer.observe(document.documentElement, {
80 | childList: true,
81 | subtree: true
82 | });
83 | }
84 | }
85 |
86 | // 开始执行
87 | waitForOuterElement();
88 | })();
89 |
90 | document.addEventListener("DOMContentLoaded", function() {
91 | // 检测是否为 PWA 模式(包括 standalone 模式或 iOS 的 navigator.standalone)
92 | if (window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone === true) {
93 | // 获取所有带 .footer 类的元素
94 | var footers = document.querySelectorAll('.footer');
95 |
96 | footers.forEach(function(footer) {
97 | // 获取当前 .footer 的计算后背景颜色
98 | var computedStyle = window.getComputedStyle(footer);
99 | var bgColor = computedStyle.backgroundColor;
100 |
101 | // 创建一个新的 div 元素,设置高度为 30px,宽度与 .footer 同宽,背景色一致
102 | var spacer = document.createElement('div');
103 | spacer.style.height = '12px';
104 | spacer.style.width = '100%';
105 | spacer.style.backgroundColor = bgColor;
106 |
107 | // 将 spacer 插入到 .footer 元素之后
108 | footer.parentNode.insertBefore(spacer, footer.nextSibling);
109 | });
110 | }
111 | });
112 |
113 | document.addEventListener("DOMContentLoaded", function() {
114 | // 检查是否为 PWA 模式(包括 standalone 模式或 iOS 的 navigator.standalone)
115 | if (window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone === true) {
116 | var fab = document.querySelector('.floating-action-buttons');
117 | if (fab) {
118 | // 设置固定定位,并调整距离底部为 50px
119 | fab.style.position = 'fixed';
120 | fab.style.bottom = '50px';
121 | }
122 | }
123 | });
124 |
125 |
126 | // 注册 Service Worker
127 | if ('serviceWorker' in navigator) {
128 | window.addEventListener('load', function() {
129 | navigator.serviceWorker.register('/pwa.js')
130 | .then(function(registration) {
131 | console.log('Service Worker 已成功注册,作用域为: ', registration.scope);
132 | })
133 | .catch(function(err) {
134 | console.log('Service Worker 注册失败: ', err);
135 | });
136 | });
137 | }
138 |
139 | // 动态创建或更新 meta viewport 标签
140 | function setViewportMeta() {
141 | let viewportMeta = document.querySelector('meta[name="viewport"]');
142 | if (!viewportMeta) {
143 | // 如果没有找到 viewport meta 标签,则创建一个新的
144 | viewportMeta = document.createElement('meta');
145 | viewportMeta.name = 'viewport';
146 | document.head.appendChild(viewportMeta);
147 | }
148 | // 强制更新或设置 content 属性
149 | viewportMeta.content =
150 | 'width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0';
151 | }
152 |
153 | // 初始化 viewport 设置
154 | setViewportMeta();
155 |
156 | // 使用 MutationObserver 实时监测 标签中的变化
157 | const observer = new MutationObserver(() => {
158 | setViewportMeta(); // 每当 发生变化时,调用 setViewportMeta 强制更新
159 | });
160 |
161 | // 配置 observer 监控 中的子节点变化
162 | observer.observe(document.head, {
163 | childList: true, // 监控子节点的增加或删除
164 | subtree: true // 监控整个 树
165 | });
166 |
--------------------------------------------------------------------------------
/LIST/beta-direct.list:
--------------------------------------------------------------------------------
1 | DOMAIN-SUFFIX,8nozh78rnry1y9uked0mor4whz4mxo.030101.xyz
2 |
--------------------------------------------------------------------------------
/LIST/cf.list:
--------------------------------------------------------------------------------
1 | IP-CIDR,173.245.48.0/20
2 | IP-CIDR,103.21.244.0/22
3 | IP-CIDR,103.22.200.0/22
4 | IP-CIDR,103.31.4.0/22
5 | IP-CIDR,141.101.64.0/18
6 | IP-CIDR,108.162.192.0/18
7 | IP-CIDR,190.93.240.0/20
8 | IP-CIDR,188.114.96.0/20
9 | IP-CIDR,197.234.240.0/22
10 | IP-CIDR,198.41.128.0/17
11 | IP-CIDR,162.158.0.0/15
12 | IP-CIDR,104.16.0.0/13
13 | IP-CIDR,104.24.0.0/14
14 | IP-CIDR,172.64.0.0/13
15 | IP-CIDR,131.0.72.0/22
16 | IP-CIDR6,2400:cb00::/32
17 | IP-CIDR6,2606:4700::/32
18 | IP-CIDR6,2803:f800::/32
19 | IP-CIDR6,2405:b500::/32
20 | IP-CIDR6,2405:8100::/32
21 | IP-CIDR6,2a06:98c0::/29
22 | IP-CIDR6,2c0f:f248::/32
23 |
--------------------------------------------------------------------------------
/LIST/ymy-direct.list:
--------------------------------------------------------------------------------
1 | # 自用list-direct
2 |
3 | # 捡漏
4 | DOMAIN-KEYWORD,gantanhao
5 | DOMAIN-KEYWORD,bs.svv.ink
6 | DOMAIN-KEYWORD,honghufly
7 | DOMAIN-KEYWORD,baidu
8 | DOMAIN-KEYWORD,vocalremover.org
9 | DOMAIN-SUFFIX,nodeseek.com
10 | DOMAIN-SUFFIX,erp.86899.xyz
11 | DOMAIN-SUFFIX,alist-doc.nn.ci
12 | DOMAIN-SUFFIX,ipv6.ddnspod.com
13 | DOMAIN-SUFFIX,chat.zhile.io
14 | DOMAIN-SUFFIX,trygpt.app
15 | DOMAIN-SUFFIX,akyopfm6mphultnyd.link
16 | DOMAIN-SUFFIX,ping0.cc
17 | DOMAIN-SUFFIX,030101.xyz
18 | DOMAIN-SUFFIX,dmflm.com
19 | DOMAIN-SUFFIX,xn--09ad.xn--y9a3aq
20 | DOMAIN-SUFFIX,sdk.cloudns.biz
21 | DOMAIN-SUFFIX,workers.dedyn.io
22 | DOMAIN-SUFFIX,youdao.com
23 | DOMAIN-SUFFIX,ssaeafaizlimoo.link
24 | DOMAIN-SUFFIX,sesezzzzzz.lpfwcukjywl.net
25 | DOMAIN-SUFFIX,whatshub.top
26 | DOMAIN-KEYWORD,nethely
27 | DOMAIN-SUFFIX,us.kg
28 | DOMAIN-SUFFIX,linux.do
29 | DOMAIN-SUFFIX,bi8bo.icu
30 | DOMAIN-SUFFIX,lyrcpx.org
31 | DOMAIN-SUFFIX,cloudns.nz
32 | DOMAIN-KEYWORD,oaifree
33 | DOMAIN-KEYWORD,mail3.serv00.com
34 | DOMAIN-KEYWORD,poczta.ct8.pl
35 | DOMAIN-KEYWORD,tongjiniao
36 | DOMAIN-KEYWORD,textr
37 | DOMAIN-KEYWORD,freeserver
38 | DOMAIN-KEYWORD,spaceship
39 | DOMAIN-SUFFIX,dash.nyc.mn
40 | DOMAIN-SUFFIX,work.tic.tc
--------------------------------------------------------------------------------
/LIST/ymy-proxy.list:
--------------------------------------------------------------------------------
1 | # 自用list-proxy
2 |
3 | #捡漏
4 | DOMAIN-SUFFIX,name.com
5 | DOMAIN-KEYWORD,minepi
6 | DOMAIN-KEYWORD,yfamily
7 | DOMAIN-KEYWORD,2rayse
8 | DOMAIN-SUFFIX,8181.030101.xyz
9 | DOMAIN-SUFFIX,cloudns.net
10 | DOMAIN-KEYWORD,vercel
11 | DOMAIN-KEYWORD,nmbot
12 | DOMAIN-SUFFIX,panel.serv00.com
13 | DOMAIN-SUFFIX,panel1.serv00.com
14 | DOMAIN-SUFFIX,panel2.serv00.com
15 | DOMAIN-SUFFIX,panel3.serv00.com
16 | DOMAIN-SUFFIX,panel4.serv00.com
17 | DOMAIN-SUFFIX,panel5.serv00.com
18 |
--------------------------------------------------------------------------------
/MODULE/Auto TF.module:
--------------------------------------------------------------------------------
1 | #!name=Auto TF
2 | #!desc=
3 | [Script]
4 |
5 | # TF信息获取
6 | #TF信息获取 = type=http-request,pattern=^https:\/\/testflight\.apple\.com\/v3\/accounts/.*\/apps$,requires-body=0,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/TF_keys.js
7 |
8 | # 自动加入 TestFlight 程序
9 | Auto join TF = type=cron,cronexp=*/6 * * * *,timeout=120,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/Auto_Join_TF.js
10 |
11 | [MITM]
12 | hostname = %APPEND% testflight.apple.com
13 |
--------------------------------------------------------------------------------
/MODULE/TF.module:
--------------------------------------------------------------------------------
1 | #!name=TF
2 | #!desc=监控
3 |
4 | [Script]
5 | TF监控 = type=cron, cronexp=0 */20 * * * *, timeout=120, script-path=https://raw.githubusercontent.com/seirhsiao/config/main/scripts/testflight.js
6 |
--------------------------------------------------------------------------------
/MODULE/TikTok.module:
--------------------------------------------------------------------------------
1 | #!name=TikTok
2 | #!desc=解锁🇯🇵地区
3 | [URL Rewrite]
4 | (?<=_region=)CN(?=&) JP 307
5 | (?<=&mcc_mnc=)4 2 307
6 | ^(https?:\/\/(tnc|dm)[\w-]+\.\w+\.com\/.+)(\?)(.+) $1$3 302
7 | (^https?:\/\/*\.\w{4}okv.com\/.+&.+)(\d{2}\.3\.\d)(.+) $118.0$3 302
8 |
9 | [MITM]
10 | hostname = *.tiktokv.com,*.byteoversea.com,*.tik-tokapi.com
11 |
--------------------------------------------------------------------------------
/MODULE/aliyun.module:
--------------------------------------------------------------------------------
1 | #!name=阿里云盘签到
2 | #!desc=
3 | [Script]
4 |
5 | 签到=type=cron,cronexp="5,10 0 * * *",wake-system=1,script-path=https://raw.githubusercontent.com/lowking/Scripts/master/ali/aliYunPanCheckIn.js
6 |
7 | #获取cookie=type=http-response,pattern=https:\/\/auth.aliyundrive.com\/v2\/account\/token,requires-body=1,script-path=https://raw.githubusercontent.com/lowking/Scripts/master/ali/aliYunPanCheckIn.js
8 |
9 | [MITM]
10 | hostname= %APPEND% auth.aliyundrive.com
11 |
--------------------------------------------------------------------------------
/PLUGIN/111.plugin:
--------------------------------------------------------------------------------
1 | #!name = GoAPI
2 | #!desc = goapi.pp.ua
3 | #!author = @Mingyu
4 | #!homepage = https://goapi.pp.ua
5 | #!icon = https://img.icons8.com/hatch/64/go.png
6 | #!date = 2024-01-19
7 |
8 | [Rule]
9 | DOMAIN-SUFFIX,goapi.pp.ua,DIRECT
10 |
11 | [Rewrite]
12 | ^https:\/\/(raw\.githubusercontent\.com|whatshub\.top|gitlab\.com) 302 https://goapi.pp.ua/$1
13 |
14 | [Mitm]
15 | hostname = raw.githubusercontent.com, whatshub.top, gitlab.com
16 |
--------------------------------------------------------------------------------
/PLUGIN/Auto TF.plugin:
--------------------------------------------------------------------------------
1 | #!name = 自动加入TF
2 | #!desc=
3 | #!openUrl = https://github.com/ymyuuu
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon = https://gitlab.com/lodepuly/iconlibrary/-/raw/master/App_icon/120px/TestFlight.png
7 | #!input = APP_ID
8 |
9 | [Rule]
10 | DOMAIN, testflight.apple.com, PROXY
11 |
12 | [Script]
13 | http-request ^https?:\/\/testflight\.apple\.com\/v3\/accounts\/.*\/apps$ script-path=https://gitlab.com/lodepuly/vpn_tool/-/raw/main/Resource/Script/TestFlight/TF_keys.js, tag = tfkey
14 | http-request ^https://testflight.apple.com/join/(.*) script-path=https://gitlab.com/lodepuly/vpn_tool/-/raw/main/Resource/Script/TestFlight/TF_keys.js, tag=appid
15 | cron "0 */10 * * * *" script-path=https://gitlab.com/lodepuly/vpn_tool/-/raw/main/Resource/Script/TestFlight/Auto_join_TF.js, tag=Auto TF, timeout=180
16 |
17 | [MITM]
18 | hostname = testflight.apple.com
19 |
--------------------------------------------------------------------------------
/PLUGIN/BiliBili.plugin:
--------------------------------------------------------------------------------
1 | #!name=BiliBili
2 | #!desc=签到
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon=https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/mini/bilibili.png
7 |
8 | # 订阅地址:https://raw.githubusercontent.com/ClydeTime/BiliBili/main/boxjs/BiliBili.boxjs.json
9 |
10 | [Script]
11 | cron "5 0 * * *" script-path=https://raw.githubusercontent.com/ClydeTime/BiliBili/main/js/BiliBiliDailyBonus.js, tag=签到
12 | http-request ^https?:\/\/app\.bilibili\.com\/x\/resource\/domain\? script-path=https://raw.githubusercontent.com/ClydeTime/BiliBili/main/js/BiliBiliDailyBonus.js, tag=BiliBiliCookie
13 |
14 | [MITM]
15 | hostname = app.bilibili.com, m.bilibili.com
16 |
--------------------------------------------------------------------------------
/PLUGIN/Bing AI.plugin:
--------------------------------------------------------------------------------
1 | #!name = Bing AI
2 | #!desc= Safari伪装Edge浏览器
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon = https://raw.githubusercontent.com/fmz200/wool_scripts/main/icons/lige47/bing(1).png
7 |
8 | [Rule]
9 | DOMAIN-SUFFIX, bing.com, PROXY
10 | DOMAIN-SUFFIX, bing.com.cn, PROXY
11 | DOMAIN-SUFFIX, bing.net, PROXY
12 | DOMAIN-SUFFIX, bingads.com, PROXY
13 | DOMAIN-SUFFIX, bingagencyawards.com, PROXY
14 | DOMAIN-SUFFIX, bingapistatistics.com, PROXY
15 | DOMAIN-SUFFIX, bingsandbox.com, PROXY
16 | DOMAIN-SUFFIX, bingvisualsearch.com, PROXY
17 | DOMAIN-SUFFIX, bingworld.com, PROXY
18 |
19 | [Script]
20 | http-request ^https:\/\/www\.bing\.com\/(search|new) script-path = https://gitlab.com/lodepuly/vpn_tool/-/raw/main/Resource/Script/Bing/BingAI.js, requires-body = false, tag = Bing AI
21 |
22 | [MITM]
23 | hostname = www.bing.com
24 |
--------------------------------------------------------------------------------
/PLUGIN/GlobalProxy.plugin:
--------------------------------------------------------------------------------
1 | #!name = GlobalProxy API
2 | #!desc = proxy.030101.xyz
3 | #!openUrl = https://raw.githubusercontent.com/ymyuuu/config/main/PLUGIN/GlobalProxy.plugin
4 | #!author = @Mingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon = https://img.icons8.com/color-glass/48/-jackalope.png
7 | #!date = 2024-08-11
8 |
9 | [Rule]
10 | DOMAIN-SUFFIX,proxy.030101.xyz,DIRECT
11 |
12 | [Rewrite]
13 | ^https:\/\/(raw\.githubusercontent\.com) 302 https://proxy.030101.xyz/$1
14 | ^https:\/\/(gitlab\.com) 302 https://proxy.030101.xyz/$1
15 |
16 | [Mitm]
17 | hostname = raw.githubusercontent.com, gitlab.com
18 |
--------------------------------------------------------------------------------
/PLUGIN/Host Speed.plugin:
--------------------------------------------------------------------------------
1 | #!name = Host Speed
2 | #!author = @Mingyu
3 | #!homepage = https://t.me/ymyuuu
4 | #!date = 2024-07-17
5 |
6 | [Host]
7 | linux.do = bestcf.030101.xyz
8 | *.linux.do = bestcf.030101.xyz
9 | *.cloudflare.com = bestcf.030101.xyz
10 | *.cloudflare.com = bestcf.030101.xyz
11 | *.nodeseek.com = bestcf.030101.xyz
12 | *.oaifree.com = bestcf.030101.xyz
13 | serv00.030101.xyz = bestcf.030101.xyz
14 | *.serv00.030101.xyz = bestcf.030101.xyz
15 | oai.030101.xyz = bestcf.030101.xyz
16 |
--------------------------------------------------------------------------------
/PLUGIN/JD price comparison.plugin:
--------------------------------------------------------------------------------
1 | #!name = JD price comparison
2 | #!desc =
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon = https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/mini/CrossWall.png
7 |
8 | [Script]
9 | http-response ^https?://api\.m\.jd\.com/client\.action\?functionId=(wareBusiness|serverConfig|basicConfig) script-path=https://raw.githubusercontent.com/deezertidal/private/main/jdprice.js, requires-body=true, timeout=10, tag=jd_price
10 |
11 |
12 | [MITM]
13 |
14 | hostname = api.m.jd.com
15 |
--------------------------------------------------------------------------------
/PLUGIN/Loon plugin control.plugin:
--------------------------------------------------------------------------------
1 | #!name=Loon plugin control
2 | #!desc=Loon插件控制
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon= switch.2
7 |
8 | # 本插件搬运自https://github.com/chengkongyiban/stash/tree/main/Rewrite_Parser_Wiki
9 |
10 | [Script]
11 | http-request \/[^/]+\.[^/]+loon$|loon\?(hndel|hnadd|n|y|x|del)= script-path=https://raw.githubusercontent.com/ymyuuu/config/main/JS/Loon%20plugin%20control.js
12 | , requires-body=true, tag=Loon插件控制器
13 |
14 | [MITM]
15 | hostname = github.com,raw.githubusercontent.com,gist.githubusercontent.com,gitlab.com,yfamily.ml,yfamily.vercel.app
16 |
--------------------------------------------------------------------------------
/PLUGIN/Node detection tool.plugin:
--------------------------------------------------------------------------------
1 | #!name = Node detection tool
2 | #!desc = Loon节点检测
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon = app.connected.to.app.below.fill
7 |
8 | [Script]
9 | generic script-path = https://gitlab.com/lodepuly/vpn_tool/-/raw/main/Resource/Script/Node_detection_tool/CloudflareSpeedtest.js, timeout = 10, tag = 节点网速测试, img-url = speedometer.system
10 | generic script-path = https://gitlab.com/lodepuly/vpn_tool/-/raw/main/Resource/Script/Node_detection_tool/LocationDetection.js, timeout = 10, tag = 地理位置查询, img-url = location.circle.system
11 | generic script-path = https://gitlab.com/lodepuly/vpn_tool/-/raw/main/Resource/Script/Node_detection_tool/NodeUnlockDetection.js, timeout = 20, tag = 节点解锁查询, img-url = play.circle.system
12 |
--------------------------------------------------------------------------------
/PLUGIN/NodeUnlockDetection.public:
--------------------------------------------------------------------------------
1 | #!name=节点解锁
2 | #!date=2025-05-01 15:25:28
3 |
4 | [Script]
5 | generic script-path=https://kelee.one/Resource/Script/Node_detection_tool/NetworkEntryAndExitQueries.js,timeout=10,tag=入口落地查询,img-url=globe.asia.australia.system
6 | generic script-path=https://kelee.one/Resource/Script/Node_detection_tool/LocationDetection.js,timeout=10,tag=地理位置查询,img-url=location.circle.system
7 | generic script-path=https://raw.githubusercontent.com/ymyuuu/config/refs/heads/main/JS/NodeUnlockDetection.js,timeout=20,tag=节点解锁查询,img-url=play.circle.system
8 |
--------------------------------------------------------------------------------
/PLUGIN/ProxyAPI.plugin:
--------------------------------------------------------------------------------
1 | #!name = ProxyAPI
2 | #!desc = proxyapi.workers.dedyn.io
3 | #!openUrl = https://raw.githubusercontent.com/ymyuuu/config/main/PLUGIN/ProxyAPI.plugin
4 | #!author = @Mingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon = https://img.icons8.com/external-flat-berkahicon/64/external-Speed-love-flat-berkahicon.png
7 | #!date = 2024-01-21
8 |
9 | [Rule]
10 | DOMAIN-SUFFIX,proxyapi.workers.dedyn.io,DIRECT
11 |
12 | [Rewrite]
13 | ^https:\/\/(raw\.githubusercontent\.com|whatshub\.top|gitlab\.com) 302 https://proxyapi.workers.dedyn.io/$1
14 |
15 | [Mitm]
16 | hostname = raw.githubusercontent.com, whatshub.top, gitlab.com
17 |
--------------------------------------------------------------------------------
/PLUGIN/Steps Update Love.plugin:
--------------------------------------------------------------------------------
1 | #!name = Steps Update love
2 | #!desc = 步数更改
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon = https://raw.githubusercontent.com/Semporia/Hand-Painted-icon/master/Social_Media/We_Heart_It.png
7 | #!input = Mingyu
8 | #!input = Ziyi
9 |
10 | [Script]
11 |
12 | cron "15 19,21 * * *" script-path=https://raw.githubusercontent.com/ymyuuu/config/main/JS/MingyuSteps.js, tag=Steps Update Mingyu, timeout=200
13 | cron "15 19,21 * * *" script-path=https://raw.githubusercontent.com/ymyuuu/config/main/JS/ZiyiSteps.js, tag=Steps Update Ziyi, timeout=200
14 |
--------------------------------------------------------------------------------
/PLUGIN/Steps Update Nolove.plugin:
--------------------------------------------------------------------------------
1 | #!name = Steps Update Nolove
2 | #!desc = 步数更改
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon = heart.slash.fill
7 | #!input = Mi
8 |
9 | [Script]
10 |
11 | cron "0 20 * * *" script-path=https://raw.githubusercontent.com/ymyuuu/config/main/JS/Steps%20Update.js, tag=Steps Update Nolove, timeout=200
12 |
--------------------------------------------------------------------------------
/PLUGIN/TF Account Management.plugin:
--------------------------------------------------------------------------------
1 | #!name=TF Account Management
2 | #!desc=自动存储/合并多个TestFlight账户列表, 并可分享/导出TestFlight APP.
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon = https://gitlab.com/lodepuly/iconlibrary/-/raw/master/App_icon/120px/TestFlight.png
7 |
8 | # [General]
9 | # skip-proxy = iosapps.itunes.apple.com
10 |
11 | [Script]
12 | http-request ^https:\/\/testflight\.apple\.com\/v\d\/(app|account|invite)s\/ requires-body=1,script-path=https://raw.githubusercontent.com/ymyuuu/config/main/JS/TF%20Account%20Management.js,tag=TF Account Management
13 |
14 | [MITM]
15 | hostname = testflight.apple.com
16 |
--------------------------------------------------------------------------------
/PLUGIN/TF Detection.plugin:
--------------------------------------------------------------------------------
1 | #!name = TF Detection
2 | #!desc =
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon = https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/mini/TestFlight.png
7 | #!input = appkey
8 | // 是否通知未检测到的appkey,默认为是(true)
9 | #!select = 是否通知未检测到的appkey, 是, 否
10 | // 是否删除已检测到的appkey,默认为不删除(false)
11 | #!select = 是否删除已检测到的appkey, 是, 否
12 |
13 | /**
14 | * 填入要监测的appkey,从testfligt地址获取
15 | * 例如"VCIvwk2g/wArXdacJ/2vnRvOTX/LzjySbQx/IdFRwmNy/qDkBu2ur/4Qt2lIm5/ZzqOu8tX/ftCqFe6F/fy7LvHVA/QKqitFwc"
16 | */
17 |
18 | [Script]
19 | cron "0 */10 * * * *" script-path=https://raw.githubusercontent.com/ymyuuu/config/main/JS/TF%20Detection.js,tag=TF Detection,timeout=180
20 |
21 | [MITM]
22 | hostname = testflight.apple.com
23 |
--------------------------------------------------------------------------------
/PLUGIN/TF monitoring.plugin:
--------------------------------------------------------------------------------
1 | #!name = TF monitoring
2 | #!desc =
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon = https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/mini/TestFlight.png
7 |
8 | # https://raw.githubusercontent.com/songyangzz/QuantumultX/master/syzzzf.box.json
9 |
10 | [Script]
11 | cron "0 */20 * * * *" script-path=https://raw.githubusercontent.com/seirhsiao/config/main/scripts/testflight.js,tag=TF monitoring,timeout=180
12 |
13 | [MITM]
14 | hostname = testflight.apple.com
15 |
--------------------------------------------------------------------------------
/PLUGIN/TF relief area.plugin:
--------------------------------------------------------------------------------
1 | #!name= TF relief area
2 | #!desc= TestFlight区域限制解除
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon= https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/Color/TestFlight_1.png
7 |
8 | [General]
9 | skip-proxy = iosapps.itunes.apple.com
10 |
11 | [Script]
12 | http-request ^https?:\/\/testflight\.apple\.com\/v\d\/accounts\/.+?\/install$ requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/ymyuuu/config/main/JS/TF%20relief%20area.js, tag=TF区域限制解除
13 |
14 | [MITM]
15 | hostname = testflight.apple.com
16 |
--------------------------------------------------------------------------------
/PLUGIN/TikTok JP.plugin:
--------------------------------------------------------------------------------
1 | #!name=TikTok JP
2 | #!desc=
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon= https://raw.githubusercontent.com/Semporia/Hand-Painted-icon/master/Social_Media/TikTok.png
7 |
8 | [Rewrite]
9 | ^https?://(www.)?g.cn 302 https://www.google.com
10 | ^https?://(www.)?google.cn 302 https://www.google.com
11 | (?<=_region=)CN(?=&) 307 JP
12 | (?<=&mcc_mnc=)4 307 2
13 | ^(https?:\/\/(tnc|dm)[\w-]+\.\w+\.com\/.+)(\?)(.+) 302 $1$3
14 | (^https?:\/\/*\.\w{4}okv.com\/.+&.+)(\d{2}\.3\.\d)(.+) 302 $118.0$3
15 |
16 | [MITM]
17 | hostname = *.google.cn,*.tiktokv.com,*.byteoversea.com,*.tik-tokapi.com
18 |
--------------------------------------------------------------------------------
/PLUGIN/Warp detection tool.plugin:
--------------------------------------------------------------------------------
1 | #!name=☁️ Warp detection tool
2 | #!desc = Warp节点检测
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon=https://is5-ssl.mzstatic.com/image/thumb/Purple122/v4/d3/c5/bb/d3c5bbed-08d4-481c-8585-f7d2e45abd5f/AppIcon-0-0-1x_U007emarketing-0-0-0-10-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/246x0w.png
7 |
8 | [Script]
9 | # WARP Panel
10 | generic script-path=https://raw.githubusercontent.com/VirgilClyne/Cloudflare/main/js/Cloudflare.1.1.1.1.panel.js, tag=☁ WARP Panel, img-url=lock.icloud.fill
11 |
12 | [MITM]
13 | hostname = api.cloudflareclient.com, zero-trust-client.cloudflareclient.com
14 |
--------------------------------------------------------------------------------
/PLUGIN/aisiiiii.plugin:
--------------------------------------------------------------------------------
1 | #!name = 爱思
2 | #!desc=
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon =
7 |
8 |
9 | [Rewrite]
10 | ^https?:\/\/list-app-m\.i4\.cn\/getopfstadinfo\.xhtml reject
11 |
12 | [Script]
13 |
14 | http-request ^https?:\/\/(search|list)-app-m\.i4\.cn\/(getHotSearchList|getAppList)\.xhtml script-path=https://github.com/chengkongyiban/Quantumultx/raw/main/js/i4AdBlock.js, requires-body = true, tag = 爱思
15 |
16 |
17 | [MITM]
18 | hostname = list-app-m.i4.cn,search-app-m.i4.cn
19 |
--------------------------------------------------------------------------------
/PLUGIN/aliyun auto.plugin:
--------------------------------------------------------------------------------
1 | #!name=aliyun auto
2 | #!desc=签到
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon=https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/mini/iCloud.png
7 |
8 | [Script]
9 | cron "5 0 * * *" script-path=https://raw.githubusercontent.com/Y-7-0101/ymy/main/JS/aliyu.js, timeout=300, tag=aliyun
10 | http-response https:api.alipan.com script-path=https://raw.githubusercontent.com/ymyuuu/config/main/JS/aliyu.js, requires-body=true, timeout=10, tag=aliyuntoken
11 |
12 | [MITM]
13 | hostname = auth.aliyundrive.com
14 |
--------------------------------------------------------------------------------
/PLUGIN/aliyun.plugin:
--------------------------------------------------------------------------------
1 | #!name=aliyun
2 | #!desc=签到
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon=https://raw.githubusercontent.com/Koolson/Qure/master/IconSet/mini/iCloud.png
7 |
8 | [Script]
9 | cron "5 0 * * *" script-path=https://raw.githubusercontent.com/lowking/Scripts/master/ali/aliYunPanCheckIn.js, timeout=300, tag=aliyun
10 |
--------------------------------------------------------------------------------
/PLUGIN/aliyuntoken.plugin:
--------------------------------------------------------------------------------
1 | #!name=aliyuntoken
2 | #!desc=
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon=https://raw.githubusercontent.com/Softlyx/Fileball/main/YUAN/ALiYun.png
7 |
8 | [Script]
9 | http-response https:\/\/auth.aliyundrive.com\/v2\/account\/token script-path=https://raw.githubusercontent.com/lowking/Scripts/master/ali/aliYunPanCheckIn.js, requires-body=true, timeout=10, tag=aliyuntoken
10 |
11 | [MITM]
12 | hostname = auth.aliyundrive.com
13 |
--------------------------------------------------------------------------------
/PLUGIN/caiyun.plugin:
--------------------------------------------------------------------------------
1 | #!name = caiyun
2 | #!desc=
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 | #!icon =
7 |
8 | [MITM]
9 | hostname=weather-data.apple.com, api.weather.com
10 | [Script]
11 | http-request https:\/\/((weather-data\.apple)|(api.weather))\.com script-path=https://raw.githubusercontent.com/Peng-YM/QuanX/master/Tasks/caiyun.js, require-body=false
12 |
--------------------------------------------------------------------------------
/PLUGIN/cloudflare.public:
--------------------------------------------------------------------------------
1 | #!name=Cloudflare 规则集
2 | #!desc=将 Cloudflare 相关 IP 段通过 PROXY 路由
3 |
4 | [Rule]
5 | IP-CIDR,173.245.48.0/20,PROXY
6 | IP-CIDR,103.21.244.0/22,PROXY
7 | IP-CIDR,103.22.200.0/22,PROXY
8 | IP-CIDR,103.31.4.0/22,PROXY
9 | IP-CIDR,141.101.64.0/18,PROXY
10 | IP-CIDR,108.162.192.0/18,PROXY
11 | IP-CIDR,190.93.240.0/20,PROXY
12 | IP-CIDR,188.114.96.0/20,PROXY
13 | IP-CIDR,197.234.240.0/22,PROXY
14 | IP-CIDR,198.41.128.0/17,PROXY
15 | IP-CIDR,162.158.0.0/15,PROXY
16 | IP-CIDR,104.16.0.0/13,PROXY
17 | IP-CIDR,104.24.0.0/14,PROXY
18 | IP-CIDR,172.64.0.0/13,PROXY
19 | IP-CIDR,131.0.72.0/22,PROXY
20 | IP-CIDR6,2400:cb00::/32,PROXY
21 | IP-CIDR6,2606:4700::/32,PROXY
22 | IP-CIDR6,2803:f800::/32,PROXY
23 | IP-CIDR6,2405:b500::/32,PROXY
24 | IP-CIDR6,2405:8100::/32,PROXY
25 | IP-CIDR6,2a06:98c0::/29,PROXY
26 | IP-CIDR6,2c0f:f248::/32,PROXY
--------------------------------------------------------------------------------
/PLUGIN/kongzh.plugin:
--------------------------------------------------------------------------------
1 | #!name = kongzhi
2 | #!desc =
3 | #!openUrl = https://github.com/Y-7-0101
4 | #!author = @YangMingyu
5 | #!homepage = https://t.me/ymyuuu
6 |
7 |
8 | /**
9 | * 填入要监测的appkey。从testfligt地址获取。
10 | * 例如"VCIvwk2g/wArXdacJ/2vnRvOTX/LzjySbQx/IdFRwmNy/qDkBu2ur/4Qt2lIm5/ZzqOu8tX/ftCqFe6F/fy7LvHVA/QKqitFwc"
11 | */
12 |
13 | [Script]
14 | http-request ^https:\/\/raw\.githubusercontent\.com\/.*\.pluginloon$|^https:\/\/.*\.pluginloon\?.* script-path=https://raw.githubusercontent.com/ymyuuu/config/main/JS/tes.js, requires-body=true, tag=Loon
15 |
16 | [MITM]
17 | hostname = raw.githubusercontent.com, *.pluginloon,github.com,raw.githubusercontent.com,gist.githubusercontent.com,gitlab.com,yfamily.ml
18 |
19 |
--------------------------------------------------------------------------------
/PLUGIN/talka.public:
--------------------------------------------------------------------------------
1 | #!name = Talkatone
2 | #!desc = Talkatone 日常使用模块
3 |
4 | [Rule]
5 | # Talkatone 内置去广告
6 | DOMAIN-SUFFIX,aax.amazon-adsystem.com,REJECT
7 | DOMAIN-SUFFIX,aax-fe.amazon-adsystem.com,REJECT
8 | DOMAIN-SUFFIX,aax-fe-sin.amazon-adsystem.com,REJECT
9 | DOMAIN-SUFFIX,ads.inmobi.com,REJECT
10 | DOMAIN-SUFFIX,ads.pubmatic.com,REJECT
11 | DOMAIN-SUFFIX,adsappier.com,REJECT
12 | DOMAIN-SUFFIX,amazon-adsystem.com,REJECT
13 | DOMAIN-SUFFIX,app-analytics-services.com,REJECT
14 | DOMAIN-SUFFIX,appier.net,REJECT
15 | DOMAIN-SUFFIX,appiersig.com,REJECT
16 | DOMAIN-SUFFIX,au.w.inmobi.com,REJECT
17 | DOMAIN-SUFFIX,b.de.inmobi.com,REJECT
18 | DOMAIN-SUFFIX,bidder.criteo.com,REJECT
19 | DOMAIN-SUFFIX,c.amazon-adsystem.com,REJECT
20 | DOMAIN-SUFFIX,cdn.liftoff-creatives.io,REJECT
21 | DOMAIN-SUFFIX,cdn.mobilefuse.com,REJECT
22 | DOMAIN-SUFFIX,cdn2.inner-active.mobi,REJECT
23 | DOMAIN-SUFFIX,cdn-f.adsmoloco.com,REJECT
24 | DOMAIN-SUFFIX,config.inmobi.com,REJECT
25 | DOMAIN-SUFFIX,cr.adsappier.com,REJECT
26 | DOMAIN-SUFFIX,criteo.com,REJECT
27 | DOMAIN-SUFFIX,dspbeacons.ihasdsp.inmobi.com,REJECT
28 | DOMAIN-SUFFIX,dspbeacons.old.ihasdsp.inmobi.com,REJECT
29 | DOMAIN-SUFFIX,ep7.facebook.com,REJECT
30 | DOMAIN-SUFFIX,et-eus.w.inmobi.com,REJECT
31 | DOMAIN-SUFFIX,ets-ap-southeast-1.track.smaato.net,REJECT
32 | DOMAIN-SUFFIX,exchange-b-events.inner-active.mobi,REJECT
33 | DOMAIN-SUFFIX,firebaseinstallations.googleapis.com,REJECT
34 | DOMAIN-SUFFIX,firebaselogging-pa.googleapis.com,REJECT
35 | DOMAIN-SUFFIX,firebaseremoteconfig.googleapis.com,REJECT
36 | DOMAIN-SUFFIX,firebase-settings.crashlytics.com,REJECT
37 | DOMAIN-SUFFIX,fundingchoicesmessages.google.com,REJECT
38 | DOMAIN-SUFFIX,googleads.g.doubleclick.net,REJECT
39 | DOMAIN-SUFFIX,googleads.g.doubleclick-cn.net,REJECT
40 | DOMAIN-SUFFIX,googlesyndication.com,REJECT
41 | DOMAIN-SUFFIX,gum.criteo.com,REJECT
42 | DOMAIN-SUFFIX,i.l.inmobicdn.net,REJECT
43 | DOMAIN-SUFFIX,i.l-dsp.inmobicdn.net,REJECT
44 | DOMAIN-SUFFIX,ic.de.inmobi.com,REJECT
45 | DOMAIN-SUFFIX,impression.link,REJECT
46 | DOMAIN-SUFFIX,impression-asia.liftoff.io,REJECT
47 | DOMAIN-SUFFIX,ins.track.tappx.com,REJECT
48 | DOMAIN-SUFFIX,lh3.googleadsserving.cn,REJECT
49 | DOMAIN-SUFFIX,mads.amazon-adsystem.com,REJECT
50 | DOMAIN-SUFFIX,mfx.mobilefuse.com,REJECT
51 | DOMAIN-SUFFIX,mt-usw.appiersig.com,REJECT
52 | DOMAIN-SUFFIX,pagead2.googlesyndication-cn.com,REJECT
53 | DOMAIN-SUFFIX,pubmatic.com,REJECT
54 | DOMAIN-SUFFIX,sdk-dnt.ad.smaato.net,REJECT
55 | DOMAIN-SUFFIX,sdk-events.inner-active.mobi,REJECT
56 | DOMAIN-SUFFIX,sdk-files.smaato.net,REJECT
57 | DOMAIN-SUFFIX,sdk-hb-cfg.smaato.net,REJECT
58 | DOMAIN-SUFFIX,skadnetworks.fyber.com,REJECT
59 | DOMAIN-SUFFIX,smaato.net,REJECT
60 | DOMAIN-SUFFIX,ssp.api.tappx.com,REJECT
61 | DOMAIN-SUFFIX,supply.inmobicdn.net,REJECT
62 | DOMAIN-SUFFIX,taboola.com,REJECT
63 | DOMAIN-SUFFIX,tappx.com,REJECT
64 | DOMAIN-SUFFIX,tpc.googlesyndication-cn.com,REJECT
65 | DOMAIN-SUFFIX,tr-asia.adsmoloco.com,REJECT
66 | DOMAIN-SUFFIX,view.adjust.com,REJECT
67 | DOMAIN-SUFFIX,vst.c.appier.net,REJECT
68 | DOMAIN-SUFFIX,wv.inner-active.mobi,REJECT
69 | DOMAIN-SUFFIX,www.googletagservices-cn.com,REJECT
70 |
71 | # Talkatone 必须走代理
72 | DOMAIN-SUFFIX,tktn.at,PROXY
73 | DOMAIN-SUFFIX,tktn.be,PROXY
74 | DOMAIN-SUFFIX,vm.talkatone.com,PROXY
75 | DOMAIN-SUFFIX,tenor.com,PROXY
76 |
77 | # Talkatone 可直连
78 | DOMAIN-SUFFIX,agkn.com,DIRECT
79 | DOMAIN-SUFFIX,cohere.com,DIRECT
80 | DOMAIN-SUFFIX,crashlytics.com,DIRECT
81 | DOMAIN-SUFFIX,inmobi.com,DIRECT
82 | DOMAIN-SUFFIX,inner-active.mobi,DIRECT
83 | DOMAIN-SUFFIX,ip-api.com,DIRECT
84 | DOMAIN-SUFFIX,kochava.com,DIRECT
85 | DOMAIN-SUFFIX,mobilefuse.com,DIRECT
86 | DOMAIN-SUFFIX,talkatone.com,DIRECT
87 | IP-CIDR,205.164.56.0/24,DIRECT
88 | IP-CIDR,216.172.154.0/24,DIRECT
89 | IP-CIDR,50.117.27.0/24,DIRECT
90 | IP-CIDR,63.251.124.0/24,DIRECT
91 | IP-CIDR,69.46.75.0/24,DIRECT
92 |
93 | [Rewrite]
94 | ^https?:\/\/alt-r\.my\.com\/mobile reject-dict
95 | ^https?:\/\/imgx\.jampp\.com\/imgsrv\/tn reject-img
96 |
97 | [Mitm]
98 | hostname = alt-r.my.com, imgx.jampp.com
99 |
--------------------------------------------------------------------------------
/PLUGIN/xn--09ad.xn--y9a3aq.plugin:
--------------------------------------------------------------------------------
1 | #!name = եգ.հայ
2 | #!desc = xn--09ad.xn--y9a3aq
3 | #!author = @Mingyu
4 | #!homepage = https://xn--09ad.xn--y9a3aq
5 | #!icon = https://img.icons8.com/external-flat-berkahicon/64/external-Speed-love-flat-berkahicon.png
6 | #!date = 2024-01-19
7 |
8 | [Rule]
9 | DOMAIN-SUFFIX,xn--09ad.xn--y9a3aq,DIRECT
10 |
11 | [Rewrite]
12 | ^https:\/\/(raw\.githubusercontent\.com|whatshub\.top|gitlab\.com) 302 https://xn--09ad.xn--y9a3aq/$1
13 |
14 | [Mitm]
15 | hostname = raw.githubusercontent.com, whatshub.top, gitlab.com
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 幸有我来山未孤
2 |
--------------------------------------------------------------------------------