├── Skin └── README.md ├── README.md ├── 584047B7-4D53-4429-9065-4D822D99E992.jpeg ├── scripts ├── Tx.js ├── pornhub.js ├── emby.js ├── baidulibrary.js ├── qtmusic.js ├── stay.js ├── TF_keys.js ├── miaojiexi2.js ├── caixin.js ├── bdcloud.js ├── TFT_Remove_ads.js ├── Auto_Join_TF.js ├── Surge_to_Shadowrocket.js ├── Loon_to_Shadowrocket.js ├── weibo_json.js ├── bilibili_json.js ├── QX_to_Shadowrocket.js ├── txt_read.js ├── qx-resource-preview.js ├── bilibili_cc.js ├── stream-all-shdow.js ├── HifiniSign.js └── Dualsub.js ├── test12.conf ├── Block ├── emby.module ├── baiducloud.module ├── stream-all-shadow.module ├── biliCC.module ├── stayRemoveAd.module ├── caixin.module ├── TestFlight.module ├── txt_read.module ├── TextEditorUnlock.module ├── BankcommAd.module ├── bilibiliSkin.module ├── xuexi.module ├── kuwo.module ├── NeteaseMusicAd.module ├── qtmusic.module ├── UnblockURLinWeChat.module ├── script-converter.module ├── xmlyCheckin.module ├── Tencentvideo.module ├── TikTokUnlockJP.module ├── BiliBiliCheckin.module ├── Auto_Join_TF.module ├── enhanced_github.module ├── test3.module ├── task.module ├── QX_to_Shadowrocket.module ├── weibolite.module ├── Remote_Cookie.module ├── AIOSearch.module ├── AIOSearchbd.module ├── bilibili.module ├── bili.module └── AdBlock.module └── scriptable └── ShadowrocketModuleTool.js /Skin/README.md: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # shadowrocket 2 | 3 | 本仓库全部搬运自互联网,方便个人使用 4 | 大部分都在里面添加了原作者的仓库地址 5 | -------------------------------------------------------------------------------- /584047B7-4D53-4429-9065-4D822D99E992.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengkongyiban/shadowrocket/HEAD/584047B7-4D53-4429-9065-4D822D99E992.jpeg -------------------------------------------------------------------------------- /scripts/Tx.js: -------------------------------------------------------------------------------- 1 | let size = ($request.headers["content-length"] || $request.headers["Content-Length"] ); 2 | if(size < 1500){$done();} 3 | $done({}); 4 | 5 | -------------------------------------------------------------------------------- /test12.conf: -------------------------------------------------------------------------------- 1 | 2 | http-request ^https?:\/\/script\.hub\/file\/_start_\/.+type=loon-plugin script-path=Loon-Rewrite-Parser.js, timeout=30, enabled=false, tag=Script Hub: Loon 插件控制器 -------------------------------------------------------------------------------- /scripts/pornhub.js: -------------------------------------------------------------------------------- 1 | /* 公众号墨鱼手记 crated by ddgksf2013 on 2022-05-28 */ 2 | var body = $response.body 3 | .replace(//, ''); 4 | $done({ body }); 5 | -------------------------------------------------------------------------------- /Block/emby.module: -------------------------------------------------------------------------------- 1 | #!name=Emby Premiere 2 | #!desc=Emby Premiere Unlock 3 | 4 | [Script] 5 | EmbyPremiere.js = type=http-response,pattern=^https?:\/\/mb3admin.com\/admin\/service\/registration\/validateDevice,requires-body=1,max-size=0,script-path=https://github.com/chengkongyiban/shadowrocket/raw/main/scripts/emby.js 6 | 7 | [MITM] 8 | hostname = %APPEND% mb3admin.com 9 | -------------------------------------------------------------------------------- /scripts/emby.js: -------------------------------------------------------------------------------- 1 | if ($request.url.indexOf('mb3admin.com/admin/service/registration/validateDevice') != -1) { 2 | if($response.status!=200){ 3 | $done({status: 200, headers: $response.headers, body: '{"cacheExpirationDays":999,"resultCode":"GOOD","message":"Device Valid"}' }) 4 | }else{ 5 | $done({}) 6 | } 7 | }else{ 8 | $done({}) 9 | } 10 | -------------------------------------------------------------------------------- /Block/baiducloud.module: -------------------------------------------------------------------------------- 1 | #!name=百度网盘解锁倍速 2 | #!desc=百度网盘解锁倍速 3 | #!author=Nobyda 4 | 5 | [Script] 6 | 7 | BaiduCloud = type=http-response,pattern=https:\/\/pan\.baidu\.com\/rest\/\d\.\d\/membership\/user,requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/bdcloud.js 8 | 9 | [MITM] 10 | 11 | hostname = %APPEND% pan.baidu.com 12 | -------------------------------------------------------------------------------- /Block/stream-all-shadow.module: -------------------------------------------------------------------------------- 1 | #!name=流媒体解锁检测 2 | #!desc=添加此模块后,点击小火箭首页右上角➕,类型选Subscribe,在URL填入http://www.stream-allshadow.com 后保存,以后检测只需刷新该订阅即可 3 | #!author=@LucaLin233 @Rabbit-Spec @xream @chengkongyiban 4 | 5 | [Script] 6 | 7 | 流媒体解锁检测 = type =http-request,pattern=^https?:\/\/(www\.)?stream-allshadow\.com,script-path=https://github.com/chengkongyiban/shadowrocket/raw/main/scripts/stream-all-shdow.js 8 | -------------------------------------------------------------------------------- /Block/biliCC.module: -------------------------------------------------------------------------------- 1 | #!name=B站简体字幕 2 | #!desc=B站cc字幕繁体转简体 3 | #搬运自ddgksf2013 4 | [Script] 5 | B站字幕转换 = type=http-response,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/bilibili_cc.js,pattern=^https?:\/\/i.\.hdslb\.com\/bfs\/subtitle\/.+\.json$,max-size=0,requires-body=true,timeout=10,script-update-interval=0,enable=true 6 | 7 | [MITM] 8 | hostname = %APPEND% i0.hdslb.com 9 | -------------------------------------------------------------------------------- /Block/stayRemoveAd.module: -------------------------------------------------------------------------------- 1 | #!name=stay去广告 2 | #!desc=stay去仓库广告 3 | #搬运自@ddgksf2013 4 | [Script] 5 | # ~ Stay(2022-10-17)@ddgksf2013 6 | 去仓库广告 = type=http-response,requires-body=1,max-size=0,pattern=^https?:\/\/api\.shenyin\.name\/stay-fork\/browse\/featured$,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/stay.js 7 | 8 | [MITM] 9 | hostname = %APPEND% api.shenyin.name 10 | -------------------------------------------------------------------------------- /Block/caixin.module: -------------------------------------------------------------------------------- 1 | #!name=财新解锁 2 | #!desc=财新解锁 3 | #搬运自@ddgksf2013 4 | [Script] 5 | 6 | # ~ 财新(2022-10-17)@ddgksf2013 7 | 财新解锁 = type=http-request,requires-body=0,max-size=0,pattern=^https?:\/\/gateway\.caixin\.com\/api\/app\-api\/auth\/(validate|validateAudioAuth),script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/caixin.js 8 | 9 | [MITM] 10 | 11 | hostname= %APPEND% gateway.caixin.com 12 | -------------------------------------------------------------------------------- /Block/TestFlight.module: -------------------------------------------------------------------------------- 1 | #!name=TF监控 2 | #!desc=TestFlight监控 3 | #搬运自songyangzz 4 | #订阅boxjs,https://raw.githubusercontent.com/songyangzz/QuantumultX/master/syzzzf.box.json在boxjs中填入appkey 5 | #pluwen的TF收集仓库https://github.com/pluwen/awesome-testflight-link/blob/main/scripts/data/ios.md 6 | 7 | [Script] 8 | TF监控 = type = cron,cronexp=0 */30 * * * *,timeout=30,script-path=https://raw.githubusercontent.com/seirhsiao/config/main/scripts/testflight.js 9 | -------------------------------------------------------------------------------- /Block/txt_read.module: -------------------------------------------------------------------------------- 1 | #!name=文本预览器 2 | #!desc=主要用于预览Safari浏览器无法直接预览,需要下载的文本,例如yaml snippet格式,在需要预览的链接末尾加.t_read.txt 3 | 4 | [Script] 5 | 6 | 文本预览器 = type=http-request,pattern=\.t_read\.txt$,requires-body=1,max-size=3145728,script-path=https://github.com/chengkongyiban/shadowrocket/raw/main/scripts/txt_read.js,script-update-interval=0 7 | 8 | [MITM] 9 | 10 | hostname = %APPEND% github.com,raw.githubusercontent.com,gist.githubusercontent.com,gitlab.com 11 | -------------------------------------------------------------------------------- /Block/TextEditorUnlock.module: -------------------------------------------------------------------------------- 1 | #!name=TextEditor解锁 2 | #!desc=TextEditor解锁 3 | #!AppStore链接:https://apps.apple.com/cn/app/text-editor/id1483790257 4 | #!搬运自I-am-r-e 5 | 6 | [Script] 7 | TextEditor解锁=type=http-response,pattern=^https:\/\/buy\.itunes\.apple\.com\/verifyReceipt,script-path=https://raw.githubusercontent.com/I-am-R-E/QuantumultX/main/JavaScript/TextEditor.js,requires-body=1,max-size=0 8 | 9 | [MITM] 10 | hostname= %APPEND% buy.itunes.apple.com 11 | -------------------------------------------------------------------------------- /Block/BankcommAd.module: -------------------------------------------------------------------------------- 1 | #!name=买单吧 2 | #!desc=旧版买单吧去升级提示 3 | [URL Rewrite] 4 | #买单吧4.7.2去开屏广告、升级提示 5 | ^https:\/\/creditcardapp\.bankcomm\.com\/mappweb_interaction\/json\/app\/appManage\/getApkUpdateInfo\.do - reject 6 | ^https:\/\/creditcardapp\.bankcomm\.com\/mappweb_interaction\/common\/getPopAds\.do - reject 7 | ^https:\/\/creditcardapp\.bankcomm\.com\/mappweb_interaction\/common\/queryGuidePageAds\.do - reject 8 | 9 | [MITM] 10 | hostname = %APPEND% *.bankcomm.com 11 | -------------------------------------------------------------------------------- /Block/bilibiliSkin.module: -------------------------------------------------------------------------------- 1 | #!name=B站魔改皮肤 2 | #!desc=魔改皮肤 3 | #作者@ClydeTime 4 | [Script] 5 | 魔改皮肤 = type=http-response,requires-body=1,max-size=0,pattern=^https?:\/\/ap(i|p)\.bilibili\.com\/x\/(vip|v2|resource)\/(space|account|web|price|top_panel_info|show)(\/|\?)(mine|myinfo|access|vip_center|panel|_bridge|skin\?).*,script-path=https://raw.githubusercontent.com/ClydeTime/Quantumult/main/Script/BiliBili/bili_info.js 6 | 7 | [MITM] 8 | hostname = %APPEND% api.bilibili.com,app.bilibili.com 9 | -------------------------------------------------------------------------------- /Block/xuexi.module: -------------------------------------------------------------------------------- 1 | #!name=学习网站 2 | #!desc=认真学习 3 | [URL Rewrite] 4 | # > 10 PornHub[网页优化]@ddgksf2013 - 网站地址:https://cn.pornhub.com 5 | ^https:\/\/(cn|www)\.pornhub\.com\/_xa\/ads - reject-dict 6 | 7 | [Script] 8 | pornhub = type=http-response,requires-body=1,max-size=0,pattern=^https?:/\/(cn|www)\.pornhub\.com(\/?$|\/([?]|view|video).*$),script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/pornhub.js 9 | 10 | [MITM] 11 | hostname = %APPEND% *.pornhub.com 12 | -------------------------------------------------------------------------------- /Block/kuwo.module: -------------------------------------------------------------------------------- 1 | #!name=酷我音乐 2 | #!desc=获取更多资源👉https://t.me/yqc_123 3 | #!搬运自nameking77👉https://github.com/nameking77?tab=repositories 4 | [MITM] 5 | hostname = %APPEND% *.kuwo.cn, *.lrts.me 6 | 7 | [Script] 8 | 酷我音乐 = type=http-response,script-path=https://raw.githubusercontent.com/nameking77/Qx/main/rewrite/kw.js,pattern=^https?:\/\/.*\.(kuwo|lrts)\.(cn|me)\/(a\.p|music\.pay|(vip\/(v2|enc)\/(theme|user\/vip))|(EcomResource|(Mobile)?Ad)Serv(er|ice)).*,max-size=131072,requires-body=true,timeout=10,script-update-interval=0,enable=true 9 | -------------------------------------------------------------------------------- /Block/NeteaseMusicAd.module: -------------------------------------------------------------------------------- 1 | #!name=网易云音乐去广告 2 | #!desc=网易云音乐去广告 3 | #!搬运自DivineEngine 4 | 5 | [URL Rewrite] 6 | ^https?:\/\/p\.du\.163\.com\/ad\/ - reject 7 | ^https?:\/\/support\.you\.163\.com\/xhr\/boot\/getBootMedia\.json - reject 8 | ^https?:\/\/interface(\d)?.music.163.com\/eapi\/ad\/ - reject 9 | ^https?:\/\/appconf\.mail\.163\.com\/mmad\/ - reject 10 | ^https?:\/\/interface3\.music\.163\.com\/eapi\/ad\/.+ - reject 11 | 12 | [MITM] 13 | hostname = %APPEND% appconf.mail.163.com,interface*.music.163.com,support.you.163.com,p.du.163.com 14 | -------------------------------------------------------------------------------- /Block/qtmusic.module: -------------------------------------------------------------------------------- 1 | #!name=趣听去弹窗 2 | #!desc=趣听去弹窗 3 | #作者@ddgksf2013 4 | #AppStore地址:https://apps.apple.com/us/app/%E9%9F%B3%E4%B9%90%E5%BC%B9%E5%B9%95-%E6%89%8B%E6%8C%81led%E9%9F%B3%E4%B9%90%E5%BC%B9%E5%B9%95/id1640507964?l=zh 5 | [Script] 6 | 7 | # ~ 趣听音乐☆自动激活APP(2022-10-26)@ddgksf2013 8 | 趣听去弹窗 = type=http-response,requires-body=1,max-size=0,pattern=^https?:\/\/api\.bspapp\.com\/client$,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/qtmusic.js 9 | 10 | [MITM] 11 | 12 | hostname=%APPEND% api.bspapp.com 13 | -------------------------------------------------------------------------------- /Block/UnblockURLinWeChat.module: -------------------------------------------------------------------------------- 1 | #!name=解除微信链接限制 2 | #!desc=跳过中间界面,支付宝链接、被封禁链接进行通知弹窗跳转,在微信中用快照显示被封禁的链接(可选),在微信中进行强制重定向(可选),iOS / macOS、微信 / WeChat 、群聊 / 扫码均可使用,可选项可在脚本 2、3 行更改,也可在 BoxJs 中更改,对于 4.11.0(2010)以后版本也可直接使用 argument 参数(实例见下方注释)。 3 | 4 | [MITM] 5 | hostname = %APPEND% security.wechat.com, weixin110.qq.com 6 | 7 | [Script] 8 | 解除微信链接限制 = type=http-response,pattern=^https\:\/\/(weixin110\.qq|security.wechat)\.com\/cgi-bin\/mmspamsupport-bin\/newredirectconfirmcgi\?,requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/UnblockURLinWeChat.js 9 | -------------------------------------------------------------------------------- /Block/script-converter.module: -------------------------------------------------------------------------------- 1 | #!name=脚本转换 2 | #!desc=目前在测试 QX 脚本(二进制请求暂不支持) 在结尾加上 _script-converter-(stash|surge|loon|shadowrocket).js 根据你自己的app填写 3 | #!author=@Peng-YM @xream 4 | 5 | [Script] 6 | 7 | #在QX脚本结尾加上 _script-converter-(stash|surge|loon|shadowrocket).js 根据你自己的app填写 8 | 脚本转换 = type=http-request,pattern=_script-converter-(stash|surge|loon|shadowrocket)\.js$,requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/xream/scripts/main/surge/modules/script-converter/script-converter.js 9 | 10 | [MITM] 11 | hostname = %APPEND% github.com:443, raw.githubusercontent.com:443,gist.githubusercontent.com,gitlab.com 12 | -------------------------------------------------------------------------------- /Block/xmlyCheckin.module: -------------------------------------------------------------------------------- 1 | #!name=喜马拉雅签到 2 | #!desc=喜马拉雅签到 3 | #原作者@ClydeTime,请将签到脚本剪切到配置文件中方便手动执行。 4 | [Script] 5 | #打开喜马拉雅客户端即可获取,获取到cookie后可关闭此模块 6 | 喜马拉雅cookie = type=http-request,pattern=^https?:\/\/mobile\.ximalaya\.com\/app-skin-service\/skin\/,script-path=https://raw.githubusercontent.com/ClydeTime/Quantumult/main/Script/Task/xmlySign.js 7 | #建议将下面的脚本剪切到配置,方便手动执行 8 | 喜马拉雅签到任务 = type=cron,cronexp=35 8 * * *,script-path=https://raw.githubusercontent.com/ClydeTime/Quantumult/main/Script/Task/xmlySign.js,timeout=15 9 | 10 | [MITM] 11 | hostname = %APPEND% mobile.ximalaya.com,180.153.255.10*,180.153.250.*,114.80.99.*,1.62.62.64 12 | -------------------------------------------------------------------------------- /scripts/baidulibrary.js: -------------------------------------------------------------------------------- 1 | /* 2 | [rewrite_local] 3 | 4 | # ~ 百度文库☆解锁VIP文档阅读权限(2022-10-17)@ddgksf2013 5 | ^https:\/\/appwk\.baidu\.com\/naapi\/user\/getinfo url script-response-body https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/baidulibrary.js 6 | 7 | [mitm] 8 | 9 | hostname=appwk.baidu.com 10 | 11 | ***********************************/ 12 | 13 | let ddgksf2013 = JSON.parse($response.body); 14 | ddgksf2013.data.vip.base_vip_info={"uid":12345678,"type":2,"start_time":1622222200,"end_time":4622222200,"is_vip":1,"remain_day":999,"pro_total":5,"normal_total":5}; 15 | $done({ body: JSON.stringify(ddgksf2013) }); 16 | -------------------------------------------------------------------------------- /scripts/qtmusic.js: -------------------------------------------------------------------------------- 1 | /**************************************** 2 | 3 | 项目功能:趣听音乐馆 屏蔽弹窗-自动激活App 4 | 使用声明:仅供学习与交流,请勿转载与贩卖!⚠️⚠️⚠️ 5 | 转载来自:墨鱼@ddgksf2013 6 | ***************************************** 7 | 8 | 9 | [rewrite_local] 10 | 11 | ^https?:\/\/api\.bspapp\.com\/client$ url script-response-body https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/qtmusic.js 12 | 13 | [mitm] 14 | 15 | hostname = api.bspapp.com 16 | 17 | ****************************************/ 18 | 19 | 20 | var body = $response.body.replace(/needVerify":true/g, 'needVerify":false').replace(/code":\d+/g, 'code":0'); 21 | $done({ body }); -------------------------------------------------------------------------------- /Block/Tencentvideo.module: -------------------------------------------------------------------------------- 1 | #!name=腾讯视频 2 | #!desc=去除腾讯视频广告 3 | #搬运自@天下第一小白脸,需先重装app,关掉模块,打开app登录账号后关掉app,再启用模块。 4 | 5 | [Rule] 6 | AND,((PROTOCOL,HTTPS), (DOMAIN,iacc.qq.com)),REJECT-NO-DROP 7 | 8 | [URL Rewrite] 9 | # > 腾讯开屏 10 | ^http:\/\/pgdt\.gtimg\.cn - reject-dict 11 | ^http:\/\/.+\/vmind\.qqvideo\.tc\.qq\.com\/.+mp4 - reject-dict 12 | 13 | [Script] 14 | #去片头广告 15 | 腾讯 = type=http-request,pattern=^(https:\/\/i\.video|http:\/\/iacc)\.qq\.com\/$,requires-body=0,max-size=0,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/Tx.js 16 | 17 | 18 | [MITM] 19 | hostname = %APPEND% i.video.qq.com,iacc.qq.com 20 | -------------------------------------------------------------------------------- /Block/TikTokUnlockJP.module: -------------------------------------------------------------------------------- 1 | #!name=TikTok JP 2 | #!desc=TikTok Unlock 3 | 4 | [URL Rewrite] 5 | (?<=_region=)CN(?=&) JP 307 6 | (^h.+v5\/)(.+) $1 302 7 | (?<=&mcc_mnc=)4 2 307 8 | (?<=eme\/v)2(?=\/f\w{2}d\/\?.*) 1 302 9 | 10 | [Script] 11 | TK去水印 = type=http-response,pattern=https?:\/\/.*\.tiktokv\.com\/aweme\/v\d\/(feed|mix\/aweme|aweme\/post|(multi\/)?aweme\/detail|follow\/feed|nearby\/feed|search\/item|general\/search\/single|hot\/search\/video\/list|aweme\/favorite),script-path=https://raw.githubusercontent.com/Tartarus2014/Script/master/Tiktok.js, requires-body=true, timeout=10 12 | 13 | [MITM] 14 | hostname = %APPEND% *.tiktokv.com,*.byteoversea.com,*.tik-tokapi.com 15 | -------------------------------------------------------------------------------- /Block/BiliBiliCheckin.module: -------------------------------------------------------------------------------- 1 | #!name=B站签到 2 | #!desc=B站签到 3 | #搬运自MartinsKing,感谢@mw418适配surge,loon等 4 | #使用方法:建议将B站签到脚本单独添加至配置文件里方便手动执行。 5 | # 1.打开手机B站客户端,提示获取cookie成功,获取成功后注释掉获取B站cookie脚本,cookie过期后可再次启用。 6 | # 2.等待定时任务执行,或手动执行。 7 | # 3.提示投币失败可尝试多次手动执行。 8 | 9 | [Script] 10 | # BiliBili cookie 11 | 获取B站cookie = type=http-request,requires-body=0,max-size=0,pattern=^https:\/\/app\.bilibili\.com\/x\/resource\/domain\?,script-path=https://raw.githubusercontent.com/ClydeTime/Quantumult/main/Script/Task/BiliBili.js 12 | 13 | B站签到 = type=cron,cronexp=30 8 * * *,timeout=30,script-path=https://raw.githubusercontent.com/ClydeTime/Quantumult/main/Script/Task/BiliBili.js 14 | 15 | [MITM] 16 | hostname = %APPEND% app.bilibili.com 17 | -------------------------------------------------------------------------------- /Block/Auto_Join_TF.module: -------------------------------------------------------------------------------- 1 | #!name=自动监控TF并加入 2 | #!desc=小火箭没有HTTP API功能,并不能自动关闭模块,请夜间使用一定要静音,经验之谈 3 | #!author = DecoAri 4 | #!使用方法,开启小火箭的HTTPS解密并信任证书,打开TF app,提示获取信息成功后注释掉TF信息获取的脚本,打开boxjs 点"我的"→数据查看器→在 数据键(Key)一栏输入APP_ID→点VIEW→然后在下面数据编辑器一栏填入需要监控的appkey,多个appkey用英文符的","隔开,例如i37NXl07,uN1vTqxk→点保存→然后回到模块,将Auto join TF前的注释去掉 就ok了 5 | 6 | [Script] 7 | 8 | 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 9 | 10 | #Auto join TF = type=cron,cronexp=*/1 * * * * *,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/Auto_Join_TF.js 11 | 12 | [MITM] 13 | 14 | hostname = %APPEND% testflight.apple.com 15 | -------------------------------------------------------------------------------- /scripts/stay.js: -------------------------------------------------------------------------------- 1 | /*********************************** 2 | 3 | > 应用名称:Stay去除仓库广告 4 | > 脚本作者:Cuttlefish 5 | > 更新时间:2022-10-17 6 | > 通知频道:https://t.me/ddgksf2021 7 | > 投稿助手:https://t.me/ddgksf2013_bot 8 | > 脚本功能:去除仓库广告 9 | > 问题反馈:📮 ddgksf2013@163.com 📮 10 | > 特别说明:⛔⛔⛔ 11 | 本脚本仅供学习交流使用,禁止转载售卖 12 | ⛔⛔⛔ 13 | 14 | [rewrite_local] 15 | 16 | # ~ Stay(2022-10-17)@ddgksf2013 17 | ^https?:\/\/api\.shenyin\.name\/stay-fork\/browse\/featured$ url script-response-body https://github.com/ddgksf2013/Cuttlefish/raw/master/Script/stay.js 18 | 19 | [mitm] 20 | 21 | hostname=api.shenyin.name 22 | 23 | ***********************************/ 24 | 25 | let ddgksf2013 = JSON.parse($response.body); 26 | if (ddgksf2013.biz) { 27 | ddgksf2013.biz = Object.values(ddgksf2013.biz).filter(item => !(item["type"]=="promoted")); 28 | } 29 | $done({ body: JSON.stringify(ddgksf2013) }); 30 | -------------------------------------------------------------------------------- /Block/enhanced_github.module: -------------------------------------------------------------------------------- 1 | #!name=GitHub 增强 2 | #!desc=允许引用私有库、禁用缓存 3 | #!author=@xream 4 | # ❤️ 感谢 Peng-YM 佬的 https://raw.githubusercontent.com/Peng-YM/QuanX/master/Rewrites/GithubPrivate/github-private-repo.js 5 | 6 | # 🔧 设置方法 7 | # 使用 BoxJs 订阅: https://raw.githubusercontent.com/xream/scripts/main/boxjs/boxjs.json 8 | # 在 http://boxjs.net/#/app/xream.enhanced_github 中设置 9 | 10 | # 📃 使用方法 11 | # 在链接的末尾添加 enhanced-github 12 | # 如 https://raw.githubusercontent.com/1/2/master/3.txt 13 | # 应为 https://raw.githubusercontent.com/1/2/master/3.txtenhanced-github 14 | 15 | 16 | [Script] 17 | 18 | enhanced_github = type=http-request,pattern=^https?:\/\/(raw|gist)\.githubusercontent\.com/.*?enhanced-github$,script-path=https://raw.githubusercontent.com/xream/scripts/main/surge/modules/enhanced-github/enhanced-github.js 19 | 20 | [MITM] 21 | 22 | hostname = %APPEND% raw.githubusercontent.com,gist.githubusercontent.com 23 | -------------------------------------------------------------------------------- /Block/test3.module: -------------------------------------------------------------------------------- 1 | youtube-response_9 = type=http-response, pattern=^https:\/\/youtubei\.googleapis\.com\/youtubei\/v1\/(browse|next|player|search|reel\/reel_watch_sequence|guide|account\/get_setting)\?, requires-body=true, max-size=3145728, binary-body-mode=true, script-path=https://raw.githubusercontent.com/RuCu6/QuanX/main/Scripts/youtube-response.js, timeout=60, script-update-interval=0 2 | 3 | ^https:\/\/youtubei\.googleapis\.com\/youtubei\/v1\/(browse|next|player|search|reel\/reel_watch_sequence|guide|account\/get_setting)\? url script-response-body https://raw.githubusercontent.com/RuCu6/QuanX/main/Scripts/youtube-response.js 4 | 5 | 40 8 * * * https://raw.githubusercontent.com/lowking/Scripts/master/ali/aliYunPanCheckIn.js, tag=阿里云盘签到, img-url=https://raw.githubusercontent.com/lowking/Scripts/master/doc/icon/aliYunPan.png, enabled=true 6 | 7 | 阿里云盘签到 = type=cron,cronexp="40 8 * * *",wake-system=1,script-path=https://raw.githubusercontent.com/lowking/Scripts/master/ali/aliYunPanCheckIn.js -------------------------------------------------------------------------------- /scripts/TF_keys.js: -------------------------------------------------------------------------------- 1 | /* 2 | author=DecoAri 3 | 小火箭用户不再错误的得到获取信息成功的通知,现在一碗粉就是一碗粉 4 | */ 5 | 6 | $persistentStore.write(null, 'request_id') 7 | let url = $request.url 8 | let key = url.replace(/(.*accounts\/)(.*)(\/apps)/, '$2') 9 | 10 | let session_id = $request.headers['X-Session-Id'] || $request.headers['x-session-id'] 11 | 12 | let session_digest = $request.headers['X-Session-Digest'] || $request.headers['x-session-digest'] 13 | 14 | let request_id = $request.headers['X-Request-Id'] || $request.headers['x-request-id'] 15 | 16 | $persistentStore.write(key, 'key') 17 | $persistentStore.write(session_id, 'session_id') 18 | $persistentStore.write(session_digest, 'session_digest') 19 | $persistentStore.write(request_id, 'request_id') 20 | 21 | if ($persistentStore.read('request_id')===null || $persistentStore.read('request_id')===undefined) { 22 | $notification.post('信息获取失败','请仔细阅读使用方法','') 23 | console.log('request_id为' + $persistentStore.read('request_id')) 24 | } else { 25 | $notification.post('请关闭本脚本', '信息获取成功','') 26 | } 27 | $done({}) 28 | -------------------------------------------------------------------------------- /Block/task.module: -------------------------------------------------------------------------------- 1 | #!name=定时任务 2 | #!desc=定时任务 3 | 4 | [Script] 5 | 6 | B站签到 = type=cron,script-path=https://raw.githubusercontent.com/ClydeTime/BiliBili/main/js/BiliBiliDailyBonus.js,cronexpr="30 8 * * *",timeout=30,script-update-interval=0,enable=true 7 | Hifini签到 = type=cron,script-path=https://raw.githubusercontent.com/lowking/Scripts/master/hifini/hifiniSign.js,cronexpr="0 0 * * *",timeout=10,script-update-interval=0,enable=true 8 | 喜马拉雅签到任务 = type=cron,cronexp=35 8 * * *,script-path=https://raw.githubusercontent.com/ClydeTime/Quantumult/main/Script/Task/xmlySign.js,timeout=15 9 | 10010v4-cron = type=cron,cronexp="0 0,12,23 * * *",timeout=60,script-path=https://raw.githubusercontent.com/xream/scripts/main/surge/modules/10010v4/10010.js 10 | 阿里云盘签到 = type=cron,cronexp="40 8 * * *",wake-system=1,script-path=https://raw.githubusercontent.com/lowking/Scripts/master/ali/aliYunPanCheckIn.js 11 | 捷停车 = type=cron,cronexp="15 9 * * *",script-path=https://raw.githubusercontent.com/FoKit/Scripts/main/scripts/jparking_sign.js,timeout=60 12 | #Bing积分 = type=cron,cronexp="0 10 0 * * ?",wake-system=1,script-path=https://raw.githubusercontent.com/lowking/Scripts/master/bing/bingPoint.js -------------------------------------------------------------------------------- /scripts/miaojiexi2.js: -------------------------------------------------------------------------------- 1 | /************************************* 2 | 3 | 项目名称:秒解析 4 | 下载地址:https://too.st/94O 5 | 更新日期:2024-03-30 6 | 脚本作者:chxm1023 7 | 电报频道:https://t.me/chxm1023 8 | 使用声明:⚠️仅供参考,🈲转载与售卖! 9 | 10 | ************************************** 11 | 12 | [rewrite_local] 13 | ^https?:\/\/tcb-api\.tencentcloudapi\.com\/web url script-response-body https://raw.githubusercontent.com/chengkongyiban/shadowrocket/refs/heads/main/scripts/miaojiexi2.js 14 | 15 | [mitm] 16 | hostname = tcb-api.tencentcloudapi.com 17 | 18 | *************************************/ 19 | 20 | 21 | //获取当前时间戳 22 | var currentTimeStamp = Date.now(); 23 | //获取response_data响应 24 | 25 | var body = $response.body 26 | if (/response_data/.test(body)) { 27 | var responseData = JSON.parse($response.body).data.response_data; 28 | 29 | //解析response_data中的data字段 30 | var data = JSON.parse(responseData).data; 31 | 32 | //修改数据 33 | data[0].jieshushijian = 4092599349000; 34 | data[0].kaitongshijian = currentTimeStamp; 35 | data[0].qixian = "永久免除所有广告"; 36 | 37 | //更新response_data中的data字段 38 | responseData = JSON.stringify({ data: data }); 39 | 40 | //更新原始数据 41 | var chxm1023 = JSON.parse(body); 42 | 43 | chxm1023.data.response_data = responseData; 44 | 45 | $done({ body: JSON.stringify(chxm1023) }); 46 | 47 | } else { 48 | $done({}) 49 | } 50 | -------------------------------------------------------------------------------- /scripts/caixin.js: -------------------------------------------------------------------------------- 1 | /*********************************** 2 | 3 | > 应用名称:财新 4 | > 软件版本:7.9.7 5 | > 下载地址:https://apps.apple.com/us/app/id356023612 6 | > 脚本作者:Cuttlefish 7 | > 微信账号:墨鱼手记 8 | > 更新时间:2022-10-22 9 | > 通知频道:https://t.me/ddgksf2021 10 | > 投稿助手:https://t.me/ddgksf2013_bot 11 | > 问题反馈:📮 ddgksf2013@163.com 📮 12 | > 使用说明:解锁文章,无需登录,请低调使用 13 | > 特别说明:⛔⛔⛔ 14 | 本脚本仅供学习交流使用,禁止转载、售卖 15 | ⛔⛔⛔ 16 | 17 | 18 | 19 | [rewrite_local] 20 | 21 | # ~ 财新(2022-10-17)@ddgksf2013 22 | ^https?:\/\/gateway\.caixin\.com\/api\/app\-api\/auth\/(validate|validateAudioAuth) url script-request-header https://github.com/ddgksf2013/Cuttlefish/raw/master/Crack/caixin.js 23 | 24 | [mitm] 25 | 26 | hostname=gateway.caixin.com 27 | 28 | ***********************************/ 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | var header=$request['headers']; 47 | var url=$request.url.replace(/uid=(\d+|)/g,"uid=12622061") 48 | .replace(/code=(\w+|)/g,"code=7258E07D155FE91FB868E545947DDCAB") 49 | .replace(/device=(\w+|)/g,"device=af491839f424cf75f07d7f4d6b7a30bde3296ea2") 50 | .replace(/deviceType=(\d+|)/g,"deviceType=1"); 51 | if($request['url']['indexOf']('validateAudioAuth')!=-0x1){ 52 | header['appinfo']='ddgksf2013'; 53 | } 54 | $done({'url':url,'headers':header}); 55 | -------------------------------------------------------------------------------- /Block/QX_to_Shadowrocket.module: -------------------------------------------------------------------------------- 1 | #!name=QX重写转化&规则集解析 2 | #!desc=现在默认缓存时间为1小时,可使用参数cachexp=修改缓存时间,单位:小时。使用方法在qx重写链接末尾加上qx 在surge模块链接末尾加sg 在loon插件链接末尾加上loon 在规则集链接末尾加r_parser.list 支持QX & Clash规则集解析 3 | #!author=@小白脸 @chengkongyiban 4 | #!使用手册https://github.com/chengkongyiban/stash/tree/main/Rewrite_Parser_Wiki 5 | #!问题反馈https://t.me/zhangpeifu 6 | 7 | [Script] 8 | 9 | QX转换 = type=http-request,pattern=^https?:\/\/.+\/[^/]+\.[^/]+(qx$|qx\?.+=),requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/chengkongyiban/stash/main/js/QX_Rewrite_Parser.js, timeout=60 10 | 11 | Loon插件转换 = type=http-request, pattern=^https?:\/\/.+\/[^/]+\.[^/]+(loon$|loon\?.+=), requires-body=1, max-size=0, script-path=https://github.com/chengkongyiban/stash/raw/main/js/Loon_Rewrite_Parser.js ,timeout=60 12 | 13 | #对Surge/小火箭模块使用 可自动修正笔误的reject类型,并支持使用参数。 14 | 模块控制器 = type=http-request,pattern=^https?:\/\/.+\/[^/]+\.[^/]+[^Ttm](sg$|sg\?.+=),requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/chengkongyiban/stash/main/js/Surge_Rewrite_Parser.js, timeout=60 15 | 16 | 规则集转换 = type=http-request,pattern=r_parser.list$|r_parser.list\?.*,requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/chengkongyiban/stash/main/js/rule_parser.js, timeout=60 17 | 18 | 脚本转换 = type=http-request,pattern=_script-converter-(stash|surge|loon|shadowrocket)\.js$,requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/xream/scripts/main/surge/modules/script-converter/script-converter.js, timeout=60 19 | 20 | 脚本转换2 = type=http-request,pattern=_script-converter-(STASH|SURGE|LOON|SHADOWROCKET)\.js$,requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/xream/scripts/main/surge/modules/script-converter/script-converter.js, timeout=60, argument="wrap_response=true" 21 | 22 | [MITM] 23 | hostname = %APPEND% github.com:443, raw.githubusercontent.com:443,gist.githubusercontent.com,gitlab.com,yfamily.ml 24 | -------------------------------------------------------------------------------- /scripts/bdcloud.js: -------------------------------------------------------------------------------- 1 | /* 2 | 百度网盘 解锁在线视频倍率/清晰度 3 | author:@Nobyda 4 | *************************** 5 | QuantumultX: 6 | 7 | [rewrite_local] 8 | https:\/\/pan\.baidu\.com\/rest\/\d\.\d\/membership\/user url script-response-body https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/bdcloud.js 9 | 10 | [mitm] 11 | hostname = pan.baidu.com 12 | 13 | *************************** 14 | Surge4 or Loon: 15 | 16 | [Script] 17 | http-response https:\/\/pan\.baidu\.com\/rest\/\d\.\d\/membership\/user requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/bdcloud.js 18 | 19 | [MITM] 20 | hostname = pan.baidu.com 21 | 22 | **************************/ 23 | 24 | if ($response.body) { 25 | $done({ 26 | body: JSON.stringify({ 27 | "product_infos": [{ 28 | "product_id": "5310897792128633390", 29 | "start_time": 2147483648, 30 | "end_time": 2877706811, 31 | "buy_time": "1417260485", 32 | "cluster": "offlinedl", 33 | "detail_cluster": "offlinedl", 34 | "product_name": "gz_telecom_exp" 35 | }, { 36 | "product_name": "svip2_nd", 37 | "product_description": "超级会员", 38 | "function_num": 0, 39 | "start_time": 1672502399, 40 | "buy_description": "", 41 | "buy_time": 0, 42 | "product_id": "1", 43 | "auto_upgrade_to_svip": 0, 44 | "end_time": 1791302400, 45 | "cluster": "vip", 46 | "detail_cluster": "svip", 47 | "status": 0 48 | }], 49 | "currenttime": 1672502399, 50 | "reminder": { 51 | "reminderWithContent": [], 52 | "advertiseContent": [] 53 | }, 54 | "request_id": 7501873289383874371 55 | }) 56 | }); 57 | } else { 58 | $done({}); 59 | } 60 | -------------------------------------------------------------------------------- /scripts/TFT_Remove_ads.js: -------------------------------------------------------------------------------- 1 | /* 2 | #!name=TFT云顶攻略助手去广告 3 | #!desc=移除烦人的广告 4 | 5 | [Script] 6 | 7 | http-response ^http:\/\/jcc\.tftplay\.com\/config\/info\/ requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/TFT_Remove_ads.js 8 | 9 | */ 10 | 11 | if ($response.body) { 12 | let qqq = JSON.parse($response.body); 13 | if (/userResult/.test($response.body)) { 14 | 15 | delete qqq.data.tipsV2; 16 | delete qqq.data.adTypeShow; 17 | qqq.data.userResult.user.vip = "true"; 18 | qqq.data.userResult.user.level = "100"; 19 | qqq.data.payShow = "0"; 20 | qqq.data.payStatus = "true"; 21 | 22 | }else{ 23 | let gameVersion = qqq.data.gameVersion; 24 | 25 | qqq = { 26 | "code": 1, 27 | "message": "", 28 | "data": { 29 | "hiddenMission": "1", 30 | "gameVersion": gameVersion, 31 | "showTeamImport": "1", 32 | "expressionMsg": "{\"url\":\"https:\/\/pan.baidu.com\/s\/1qyWStu7eimThWa6vhcFm-w?pwd=8888\",\"password\":\"8888\"}", 33 | "cardChangeShow": "1", 34 | "iosPageRecovery2": "1", 35 | "iapWay": "1,2,3", 36 | "speedShow": "0", 37 | "traitOptionShow": "1", 38 | "hiddenJulong": "1", 39 | "payShow": "0", 40 | "exchangeImgs": "group14", 41 | "bannerConfig": "{\"imgUrl\":\"https:\/\/static.miplus.cloud\/tft\/img\/activity\/banner2107222.png\",\"type\":3}", 42 | "lotteryShow": "1", 43 | "price": "6", 44 | "userResult": { 45 | "user": { 46 | "id": 1001, 47 | "nickname": "大吉大利", 48 | "fansCount": 0, 49 | "attentionCount": 0, 50 | "headImgUrl": "http:\/\/static.miplus.cloud\/tft\/img\/upload\/231121\/041109d3c349a7-00cc-4295-b8bd-34257f291cb6.jpg", 51 | "vip": "true", 52 | "postCount": 0, 53 | "motto": "未登录账号", 54 | "level": "100" 55 | } 56 | }, 57 | "showGameDownload": "1", 58 | "payStatus": "true" 59 | }, 60 | "success": true 61 | } 62 | 63 | } 64 | 65 | $done({ 66 | body: JSON.stringify(qqq) 67 | }); 68 | } else { 69 | $done({}); 70 | } 71 | -------------------------------------------------------------------------------- /Block/weibolite.module: -------------------------------------------------------------------------------- 1 | #!name=微博Lite 2 | #!desc=微博轻享版去广告 3 | #需重装微博轻享版 4 | #搬运自@ddgksf2013 5 | 6 | [Rule] 7 | 8 | RULE-SET,https://raw.githubusercontent.com/chengkongyiban/myself-rule-set/main/WeiboLiteAds.list,REJECT-DICT 9 | 10 | [URL Rewrite] 11 | 12 | # > 微博国际版_hot_search@ddgksf2013 13 | ^https?:\/\/weibointl\.api\.weibo\.c(n|om)\/portal\.php\?a=hot_search_users - reject-dict 14 | # > 微博国际版_热推荐@ddgksf2013 15 | ^https?:\/\/m?api\.weibo\.c(n|om)\/\d\/ad\/weibointl\? - reject-dict 16 | # > 微博国际版_屏蔽search_suggest@ddgksf2013 17 | # ^https?:\/\/m?api\.weibo\.c(n|om)\/\d\/page\/get_search_suggest - reject-dict 18 | # > 微博国际版_屏蔽searching_info@ddgksf2013 19 | ^https?:\/\/weibointl\.api\.weibo\.c(n|om)\/portal\.php.*user&a=get_searching_info - reject-dict 20 | # > 微博国际版_屏蔽search_topic@ddgksf2013 21 | ^https?:\/\/weibointl\.api\.weibo\.c(n|om)\/portal\.php.*feed&a=search_topic - reject-dict 22 | 23 | [Script] 24 | 25 | # > 微博国际版_屏蔽开屏广告@ddgksf2013 26 | weibo_json = type=http-response,pattern=^https?:\/\/weibointl\.api\.weibo\.c(n|om)\/portal\.php.*get_coopen_ads,requires-body=1,max-size=0,script-path=https://github.com/ddgksf2013/Scripts/raw/master/weibo_json.js 27 | # > 微博&国际版_sdkad@ddgksf2013 28 | weibo_json = type=http-response,pattern=^https?://(sdk|wb)app\.uve\.weibo\.com(/interface/sdk/sdkad.php|/wbapplua/wbpullad.lua),requires-body=1,max-size=0,script-path=https://github.com/ddgksf2013/Scripts/raw/master/weibo_json.js 29 | # > 微博国际版_趋势顶部CARD去广告@ddgksf2013 30 | weibo_json = type=http-response,pattern=^https?:\/\/weibointl\.api\.weibo\.c(n|om)\/portal\.php.*feed&a=trends,requires-body=1,max-size=0,script-path=https://github.com/ddgksf2013/Scripts/raw/master/weibo_json.js 31 | # > 微博国际版_用户中心@ddgksf2013 32 | weibo_json = type=http-response,pattern=^https?:\/\/weibointl\.api\.weibo\.cn\/portal\.php\?a=user_center,requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/weibo_json.js 33 | 34 | [MITM] 35 | 36 | hostname = %APPEND% *.uve.weibo.com,*api.weibo.cn,*api.weibo.com,h5.sinaimg.cn,new.vip.weibo.cn,*.sc.weibo.com,captcha.weibo.com,wx*.sinaimg.cn,js.t.sinajs.cn,*.e.weibo.com -------------------------------------------------------------------------------- /scripts/Auto_Join_TF.js: -------------------------------------------------------------------------------- 1 | /* 2 | author=@DecoAri 3 | 加了一条未读取到TF信息时候的通知,不再是默默的在log里报错 4 | 5 | */ 6 | 7 | !(async () => { 8 | ids = $persistentStore.read('APP_ID') 9 | if (ids == '') { 10 | $notification.post('所有TF已加入完毕','请手动关闭此模块','') 11 | $done($httpAPI('POST', '/v1/modules', {'Auto module for JavaScripts': 'false'})) 12 | } else { 13 | ids = ids.split(',') 14 | for await (const ID of ids) { 15 | await autoPost(ID) 16 | } 17 | } 18 | $done() 19 | })(); 20 | 21 | function autoPost(ID) { 22 | let Key = $persistentStore.read('key') 23 | let testurl = 'https://testflight.apple.com/v3/accounts/' + Key + '/ru/' 24 | let header = { 25 | 'X-Session-Id': `${$persistentStore.read('session_id')}`, 26 | 'X-Session-Digest': `${$persistentStore.read('session_digest')}`, 27 | 'X-Request-Id': `${$persistentStore.read('request_id')}` 28 | } 29 | return new Promise(function(resolve) { 30 | $httpClient.get({url: testurl + ID,headers: header}, function(error, resp, data) { 31 | if (error === null) { 32 | if (resp.status == 404) { 33 | ids = $persistentStore.read('APP_ID').split(',') 34 | ids = ids.filter(ids => ids !== ID) 35 | $persistentStore.write(ids.toString(),'APP_ID') 36 | console.log(ID + ' ' + '不存在该TF,已自动删除该APP_ID') 37 | $notification.post(ID, '不存在该TF', '已自动删除该APP_ID') 38 | resolve() 39 | } else { 40 | if (!$persistentStore.read('request_id')){ 41 | $notification.post('未读取到TF信息','请先获取TF信息再来','') 42 | $done({}) 43 | }else{ 44 | let jsonData = JSON.parse(data) 45 | if (jsonData.data == null) { 46 | console.log(ID + ' ' + jsonData.messages[0].message) 47 | resolve(); 48 | } else if (jsonData.data.status == 'FULL') { 49 | console.log(ID + ' ' + jsonData.data.message) 50 | resolve(); 51 | } else { 52 | $httpClient.post({url: testurl + ID + '/accept',headers: header}, function(error, resp, body) { 53 | let jsonBody = JSON.parse(body) 54 | $notification.post(jsonBody.data.name, 'TestFlight加入成功', '') 55 | console.log(jsonBody.data.name + ' TestFlight加入成功') 56 | ids = $persistentStore.read('APP_ID').split(',') 57 | ids = ids.filter(ids => ids !== ID) 58 | $persistentStore.write(ids.toString(),'APP_ID') 59 | resolve() 60 | }); 61 | } 62 | } 63 | }} else { 64 | if (error =='The request timed out.') { 65 | resolve(); 66 | } else { 67 | $notification.post('自动加入TF', error,'') 68 | console.log(ID + ' ' + error) 69 | resolve(); 70 | } 71 | } 72 | }) 73 | }) 74 | } 75 | -------------------------------------------------------------------------------- /Block/Remote_Cookie.module: -------------------------------------------------------------------------------- 1 | #!name=Cookie获取 2 | #!desc=自用Cookie获取 3 | 4 | [Script] 5 | #Safari浏览器打开登录 https://home.m.jd.com/myJd/newhome.action 点击"我的"页面 6 | #或者使用旧版网址 https://bean.m.jd.com/bean/signIndex.action 点击签到并且出现签到日历 7 | #如果通知获取Cookie成功, 则可以使用此签到脚本. 注: 请勿在京东APP内获取!!! 8 | #获取京东金融签到Body说明: 正确添加脚本配置后, 进入"京东金融"APP, 在"首页"点击"签到"并签到一次, 待通知提示成功即可. 9 | 获取京东Cookie = type=http-request,requires-body=1,pattern=^https:\/\/(api\.m|me-api|ms\.jr)\.jd\.com\/(client\.action\?functionId=signBean|user_new\/info\/GetJDUserInfoUnion\?|gw\/generic\/hy\/h5\/m\/appSign\?),script-path=https://raw.githubusercontent.com/NobyDa/Script/master/JD-DailyBonus/JD_DailyBonus.js 10 | 11 | #打开B站客户端首页即可获取 12 | B站Cookie(APP) = type=http-request,pattern=^https?:\/\/app\.bilibili\.com\/x\/resource\/domain\?,script-path=https://raw.githubusercontent.com/ClydeTime/BiliBili/main/js/BiliBiliDailyBonus.js,requires-body=0 13 | 14 | #打开https://www.hifini.com/my.htm获取cookie 15 | hifini签到cookie = type=http-request,pattern=https:\/\/www.hifini.com\/my.htm,script-path=https://raw.githubusercontent.com/lowking/Scripts/master/hifini/hifiniSign.js 16 | 17 | #打开喜马拉雅客户端即可获取 18 | 喜马拉雅cookie = type=http-request,pattern=^https?:\/\/mobile\.ximalaya\.com\/app-skin-service\/skin\/,script-path=https://raw.githubusercontent.com/ClydeTime/Quantumult/main/Script/Task/xmlySign.js 19 | 20 | #使用方法:打开 交管12123支付宝小程序 登录即可自动抓取 21 | 交管12123 = type=http-request,pattern=^https:\/\/miniappcsfw\.122\.gov\.cn:8443\/openapi\/invokeApi\/business\/biz,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/12123/index.js 22 | 23 | # > 阿里云盘签到 https://auth.aliyundrive.com/v2/account/token 24 | 阿里云盘签到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 25 | 26 | # > Bing积分 登录 https://rewards.bing.com 获取 Cookie 备注:可切换地区领取积分(有些地区貌似不支持或活动做不完) 27 | Bing积分cookie = requires-body=0,type=http-request,pattern=https:\/\/rewards\.bing\.com,script-path=https://raw.githubusercontent.com/mw418/Loon/main/script/bingPoint.js 28 | 29 | #捷停车 30 | 捷停车 = type=http-request, pattern=^https:\/\/sytgate\.jslife\.com\.cn\/core-gateway\/order\/carno\/pay\/info, requires-body=true, max-size=3145728, script-path=https://raw.githubusercontent.com/FoKit/Scripts/main/scripts/jparking_sign.js, timeout=60 31 | 32 | #获取Cookie等信息方法 ,QX开重写,进入【高德地图,打车,福利中心】,如果没提醒,重新打开APP重新进入 33 | 高德地图 = type=http-response, pattern=^https:\/\/m5(-zb)?\.amap\.com\/ws\/yuece\/(act|openapi)\/(activity\/current\/)?query, requires-body=true, max-size=3145728, script-path=https://raw.githubusercontent.com/wf021325/qx/master/task/ampDache.js, timeout=60, script-update-interval=0 34 | 35 | [MITM] 36 | 37 | hostname = %APPEND% *.hifini.com,app.bilibili.com,ms.jr.jd.com,me-api.jd.com,api.m.jd.com,mobile.ximalaya.com,180.153.255.10*,180.153.250.*,114.80.99.*,1.62.62.64,miniappcsfw.122.gov.cn:8443,miniappcsfw.122.gov.cn,auth.aliyundrive.com,rewards.bing.com,sytgate.jslife.com.cn,*.amap.com 38 | -------------------------------------------------------------------------------- /Block/AIOSearch.module: -------------------------------------------------------------------------------- 1 | #!name=All-In-One-Search 2 | #!desc=Safari全能搜索(需要把Safari的搜索引擎设置为:duckduckgo) 3 | #!system=ios 4 | #搬运自ATorNinja 5 | 6 | [URL Rewrite] 7 | # Safari全能搜索 8 | # 以下为Safari全能搜索、需要把Safari的搜索引擎设置为:duckduckgo 9 | 10 | #wk (Wikipedia中文) 11 | ^https:\/\/duckduckgo.com\/\?q=wk\+([^&]+).+ https://zh.wikipedia.org/wiki/$1 302 12 | 13 | #wiki (Wikipedia) 14 | ^https:\/\/duckduckgo.com\/\?q=wiki\+([^&]+).+ https://wikipedia.org/wiki/$1 302 15 | 16 | # yd (有道词典) 17 | ^https:\/\/duckduckgo.com\/\?q=yd\+([^&]+).+ https://dict.youdao.com/search?q=$1 302 18 | 19 | # trc (Google 译至中) 20 | ^https:\/\/duckduckgo.com\/\?q=trc\+([^&]+).+ https://translate.google.com/#view=home&op=translate&sl=auto&tl=zh-CN&text=$1 302 21 | 22 | # tre (Google 译至英) 23 | ^https:\/\/duckduckgo.com\/\?q=tre\+([^&]+).+ https://translate.google.com/#view=home&op=translate&sl=auto&tl=en&text=$1 302 24 | 25 | # trj (Google 译至日) 26 | ^https:\/\/duckduckgo.com\/\?q=trj\+([^&]+).+ https://translate.google.com/#view=home&op=translate&sl=auto&tl=ja&text=$1 302 27 | 28 | # gm (Google图片) 29 | ^https:\/\/duckduckgo.com\/\?q=gm\+([^&]+).+ https://www.google.com/search?&tbm=isch&q=$1 302 30 | 31 | # gh (GitHub) 32 | ^https:\/\/duckduckgo.com\/\?q=gh\+([^&]+).+ https://github.com/search?q=$1 302 33 | 34 | # tf (Google 搜索 TestFlight) 35 | ^https:\/\/duckduckgo.com\/\?q=tf\+([^&]+).+ https://www.google.com/search?as_q=$1&as_sitesearch=testflight.apple.com 302 36 | 37 | # wb (微博) 38 | ^https:\/\/duckduckgo.com\/\?q=wb\+([^&]+).+ https://s.weibo.com/weibo/$1 302 39 | 40 | # wx (微信) 41 | ^https:\/\/duckduckgo.com\/\?q=wx\+([^&]+).+ https://weixin.sogou.com/weixinwap?query=$1 302 42 | 43 | # jd (京东) 44 | ^https:\/\/duckduckgo.com\/\?q=jd\+([^&]+).+ https://so.m.jd.com/ware/search.action?keyword=$1 302 45 | 46 | # tb (淘宝) 47 | ^https:\/\/duckduckgo.com\/\?q=tb\+([^&]+).+ https://s.m.taobao.com/h5?q=$1 302 48 | 49 | # tm (天猫) 50 | ^https:\/\/duckduckgo.com\/\?q=tm\+([^&]+).+ https://s.m.tmall.com/m/search.htm?q=$1 302 51 | 52 | # ytb (YouTube) 53 | ^https:\/\/duckduckgo.com\/\?q=ytb\+([^&]+).+ https://www.youtube.com/results?search_query=$1 302 54 | 55 | #vf(voflix视频网站) 56 | ^https:\/\/duckduckgo.com\/\?q=vf\+([^&]+).+ https://www.voflix.com/search/-------------.html?wd=$1 302 57 | 58 | # ph (PornHub) 59 | ^https:\/\/duckduckgo.com\/\?q=ph\+([^&]+).+ https://cn.pornhub.com/video/search?search=$1 302 60 | 61 | # bi (必应) 62 | ^https:\/\/duckduckgo.com\/\?q=bi\+([^&]+).+ https://cn.bing.com/search?q=$1 302 63 | 64 | # bd (百度) 65 | ^https:\/\/duckduckgo.com\/\?q=bd\+([^&]+).+ https://www.baidu.com/s?wd=$1 302 66 | 67 | # ccn (App Store 临时换至中国区) 68 | ^https:\/\/duckduckgo.com\/\?q=ccn&. https://itunes.apple.com/WebObjects/MZStore.woa/wa/resetAndRedirect?dsf=143465&mt=8&url=/WebObjects/MZStore.woa/wa/viewSoftware?mt=8&id=1108187390&cc=cn&urlDesc= 302 69 | 70 | # uus (App Store 临时换至美国区) 71 | ^https:\/\/duckduckgo.com\/\?q=uus&. https://itunes.apple.com/WebObjects/MZStore.woa/wa/resetAndRedirect?dsf=143441&mt=8&url=/WebObjects/MZStore.woa/wa/viewSoftware?mt=8&id=1108187390&cc=us&urlDesc= 302 72 | 73 | # jjp (APP Store 切换至JP) 74 | ^https:\/\/duckduckgo.com\/\?q=jjp&. https://itunes.apple.com/WebObjects/MZStore.woa/wa/resetAndRedirect?dsf=143462&mt=8&url=/WebObjects/MZStore.woa/wa/viewSoftware?mt=8&id=1108187390&cc=jp&urlDesc= 302 75 | 76 | # ttr (APP Store 切换至TR) 77 | ^https:\/\/duckduckgo.com\/\?q=ttr&. https://itunes.apple.com/WebObjects/MZStore.woa/wa/resetAndRedirect?dsf=143480&mt=8&url=/WebObjects/MZStore.woa/wa/viewSoftware?mt=8&id=1108187390&cc=tr&urlDesc= 302 78 | 79 | # ddg (DuckDuckGo) 80 | ^https:\/\/duckduckgo.com\/\?q=ddg\+([^&]+).+ https://duckduckgo.com/?ia=about&q=$1 302 81 | 82 | # 无指令 (Google) 83 | ^https:\/\/duckduckgo.com\/\?q=([^&]+).+ https://www.google.com/search?q=$1 302 84 | 85 | [MITM] 86 | hostname = %APPEND% duckduckgo.com 87 | -------------------------------------------------------------------------------- /Block/AIOSearchbd.module: -------------------------------------------------------------------------------- 1 | #!name=All-In-One-Search 2 | #!desc=Safari全能搜索(需要把Safari的搜索引擎设置为:百度) 3 | #搬运自ATorNinja 4 | 5 | [URL Rewrite] 6 | # Safari全能搜索 7 | # 以下为Safari全能搜索、需要把Safari的搜索引擎设置为:百度 8 | 9 | #wk (Wikipedia中文) 10 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=wk\+([^&]+) https://zh.wikipedia.org/wiki/$1 302 11 | 12 | #wiki (Wikipedia) 13 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=wiki\+([^&]+) https://wikipedia.org/wiki/$1 302 14 | 15 | # yd (有道词典) 16 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=yd\+([^&]+) https://dict.youdao.com/search?q=$1 302 17 | 18 | # trc (Google 译至中) 19 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=trc\+([^&]+) https://translate.google.com/#view=home&op=translate&sl=auto&tl=zh-CN&text=$1 302 20 | 21 | # tre (Google 译至英) 22 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=tre\+([^&]+) https://translate.google.com/#view=home&op=translate&sl=auto&tl=en&text=$1 302 23 | 24 | # trj (Google 译至日) 25 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=trj\+([^&]+) https://translate.google.com/#view=home&op=translate&sl=auto&tl=ja&text=$1 302 26 | 27 | # gm (Google图片) 28 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=gm\+([^&]+) https://www.google.com/search?&tbm=isch&q=$1 302 29 | 30 | # gh (GitHub) 31 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=gh\+([^&]+) https://github.com/search?q=$1 302 32 | 33 | # tf (Google 搜索 TestFlight) 34 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=tf\+([^&]+) https://www.google.com/search?as_q=$1&as_sitesearch=testflight.apple.com 302 35 | 36 | # wb (微博) 37 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=wb\+([^&]+) https://s.weibo.com/weibo/$1 302 38 | 39 | # wx (微信) 40 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=wx\+([^&]+) https://weixin.sogou.com/weixinwap?query=$1 302 41 | 42 | # jd (京东) 43 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=jd\+([^&]+) https://so.m.jd.com/ware/search.action?keyword=$1 302 44 | 45 | # tb (淘宝) 46 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=tb\+([^&]+) https://s.m.taobao.com/h5?q=$1 302 47 | 48 | # tm (天猫) 49 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=tm\+([^&]+) https://s.m.tmall.com/m/search.htm?q=$1 302 50 | 51 | # ytb (YouTube) 52 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=ytb\+([^&]+) https://www.youtube.com/results?search_query=$1 302 53 | 54 | # ph (PornHub) 55 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=ph\+([^&]+) https://cn.pornhub.com/video/search?search=$1 302 56 | 57 | # bi (必应) 58 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=bi\+([^&]+) https://cn.bing.com/search?q=$1 302 59 | 60 | # bd (百度) 61 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=bd\+([^&]+) https://www.baidu.com/s?wd=$1 302 62 | 63 | # ccn (App Store 临时换至中国区) 64 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=ccn https://itunes.apple.com/WebObjects/MZStore.woa/wa/resetAndRedirect?dsf=143465&mt=8&url=/WebObjects/MZStore.woa/wa/viewSoftware?mt=8&id=1108187390&cc=cn&urlDesc= 302 65 | 66 | # uus (App Store 临时换至美国区) 67 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=uus https://itunes.apple.com/WebObjects/MZStore.woa/wa/resetAndRedirect?dsf=143441&mt=8&url=/WebObjects/MZStore.woa/wa/viewSoftware?mt=8&id=1108187390&cc=us&urlDesc= 302 68 | 69 | # jjp (APP Store 切换至JP) 70 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=jjp https://itunes.apple.com/WebObjects/MZStore.woa/wa/resetAndRedirect?dsf=143462&mt=8&url=/WebObjects/MZStore.woa/wa/viewSoftware?mt=8&id=1108187390&cc=jp&urlDesc= 302 71 | 72 | # ttr (APP Store 切换至TR) 73 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=ttr https://itunes.apple.com/WebObjects/MZStore.woa/wa/resetAndRedirect?dsf=143480&mt=8&url=/WebObjects/MZStore.woa/wa/viewSoftware?mt=8&id=1108187390&cc=tr&urlDesc= 302 74 | 75 | # ddg (DuckDuckGo) 76 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=ddg\+([^&]+) https://duckduckgo.com/?ia=about&q=$1 302 77 | 78 | # 无指令 (Google) 79 | ^https:\/\/m\.baidu\.com/s\?from=.+&word=([^&]+) https://www.google.com/search?q=$1 302 80 | 81 | [MITM] 82 | hostname = %APPEND% m.baidu.com 83 | -------------------------------------------------------------------------------- /scripts/Surge_to_Shadowrocket.js: -------------------------------------------------------------------------------- 1 | /**************************** 2 | 原脚本作者@小白脸 脚本修改@chengkongyiban 3 | 感谢@xream 的指导 4 | 说明 5 | t&zd; = { , } 花括号中的逗号 6 | 7 | ***************************/ 8 | let req = $request.url.replace(/sg$/,''); 9 | 10 | !(async () => { 11 | let body = await http(req); 12 | //判断是否断网 13 | if(body == null){$notification.post("Surge转换:未获取到body","请检查网络及节点是否畅通\n" + "源链接为" + $request.url,"认为是bug?点击通知反馈","https://t.me/zhangpeifu") 14 | $done({ response: { status: 404 ,body:{} } }); 15 | }else{//以下开始重写及脚本转换 16 | 17 | if (body.match(/\/\*+\n[\s\S]*\n\*+\/\n/)){ 18 | body = body.replace(/[\s\S]*(\/\*+\n[\s\S]*\n\*+\/\n)[\s\S]*/,"$1").match(/[^\r\n]+/g); 19 | }else{ 20 | body = body.match(/[^\r\n]+/g);}; 21 | 22 | let uHalf = []; 23 | let lHalf = []; 24 | let mods = []; 25 | let others = []; 26 | let URLRewrite = []; 27 | let script = []; 28 | 29 | body.forEach((x, y, z) => { 30 | x = x.replace(/^ *(#|;|\/\/)/g,'#'); 31 | 32 | //判断注释 33 | 34 | if (x.match(/^[^#]/)){ 35 | var noteK = ""; 36 | }else{ 37 | var noteK = "#"; 38 | }; 39 | 40 | if (x.match(/\x20data=/)){ 41 | 42 | //Mock转reject/request 43 | 44 | let ptn = x.replace(/\x20{2,}/g," ").split(" data=")[0].replace(/^#|"/g,""); 45 | let file = x.split(' data="')[1].split('"')[0]; 46 | let fileName = file.substring(file.lastIndexOf('/') + 1); 47 | let scname = fileName.split(".")[0]; 48 | 49 | if (fileName.match(/(img|dict|array|200|blank|tinygif)\.[^.]+$/i)){ 50 | 51 | let mock2Reject 52 | 53 | if (fileName.match(/dict\.[^.]+$/i)){ 54 | mock2Reject = "-dict"; 55 | 56 | }else if (fileName.match(/array\.[^.]+$/i)){ 57 | mock2Reject = "-array"; 58 | 59 | }else if (fileName.match(/(200|blank)\.[^.]+$/i)){ 60 | mock2Reject = "-200"; 61 | 62 | }else if (fileName.match(/(img|tinygif)\.[^.]+$/i)){ 63 | mock2Reject = "-200"; 64 | }; 65 | 66 | z[y - 1]?.match(/^#/) && URLRewrite.push(z[y - 1]); 67 | 68 | URLRewrite.push( 69 | `${noteK}${ptn} - reject${mock2Reject}`) 70 | }else{ 71 | z[y - 1]?.match(/^#/) && script.push(z[y - 1]); 72 | 73 | script.push( 74 | `${noteK}${scname} = type=http-request,pattern=${ptn},script-path=https://raw.githubusercontent.com/xream/scripts/main/surge/modules/echo-response/index.js,argument=type=text/json&url=${file}`) 75 | } 76 | 77 | }else{ 78 | others.push(x); 79 | } 80 | 81 | }); //循环结束 82 | 83 | script = (script[0] || '') && `${script.join("\n")}`; 84 | 85 | URLRewrite = (URLRewrite[0] || '') && `${URLRewrite.join("\n")}`; 86 | 87 | others = (others[0] || '') && `${others.join("\n\n")}`; 88 | 89 | if (URLRewrite !== "" && others.match("[URL Rewrite]")){ 90 | uHalf = others.split(/\[URL Rewrite\]/i)[0]; 91 | lHalf = others.split(/\[URL Rewrite\]/i)[1]; 92 | mods = `${uHalf}\n\n[URL Rewrite]\n\n${URLRewrite}\n\n${lHalf}`; 93 | }else{if (URLRewrite != ""){ 94 | mods = `${others}${URLRewrite}` 95 | 96 | }else{ 97 | mods = `${others}`; 98 | } 99 | }; 100 | 101 | if (script !== "" && mods.match("[Script]")){ 102 | uHalf = mods.split(/\[Script\]/i)[0]; 103 | lHalf = mods.split(/\[Script\]/i)[1]; 104 | mods = `${uHalf}\n\n[Script]\n\n${script}\n\n${lHalf}`; 105 | }else{if (script != ""){ 106 | mods = `${mods}${script}` 107 | 108 | }else{ 109 | mods = `${mods}`; 110 | } 111 | }; 112 | 113 | 114 | body = `${mods}` 115 | .replace(/t&zd;/g,',') 116 | .replace(/\[Map\x20?Local\]/gi,'') 117 | .replace(/undefined$/,'') 118 | .replace(/(#.+\n)\n+(?!\[)/g,'$1') 119 | .replace(/\n{2,}/g,'\n\n') 120 | 121 | $done({ response: { status: 200 ,body:body ,headers: {'Content-Type': 'text/plain; charset=utf-8'} } }); 122 | }//判断是否断网的反括号 123 | 124 | })() 125 | .catch((e) => { 126 | $notification.post(`${e}`,'',''); 127 | $done() 128 | }) 129 | 130 | 131 | function http(req) { 132 | return new Promise((resolve, reject) => 133 | $httpClient.get(req, (err, resp,data) => { 134 | resolve(data) 135 | }) 136 | ) 137 | } -------------------------------------------------------------------------------- /scripts/Loon_to_Shadowrocket.js: -------------------------------------------------------------------------------- 1 | /**************************** 2 | 原脚本作者@小白脸 脚本修改@chengkongyiban 3 | 感谢@xream 的指导 4 | 说明 5 | t&zd; = { , } 花括号中的逗号 6 | 7 | ***************************/ 8 | 9 | const modStore = "https://loon-plugin.vercel.app/"; 10 | 11 | let req = $request.url; 12 | 13 | !(async () => { 14 | let body = await http(req); 15 | //判断是否断网 16 | if(body == null){$notification.post("模块商店:未获取到body","请检查网络及节点是否畅通\n" + "源链接为" + $request.url,"认为是bug?点击通知反馈","https://t.me/zhangpeifu") 17 | $done({ response: { status: 404 ,body:{} } }); 18 | }else{//以下开始重写及脚本转换 19 | 20 | if (body.match(/\/\*+\n[\s\S]*\n\*+\/\n/)){ 21 | body = body.replace(/[\s\S]*(\/\*+\n[\s\S]*\n\*+\/\n)[\s\S]*/,"$1").match(/[^\r\n]+/g); 22 | }else{ 23 | body = body.match(/[^\r\n]+/g);}; 24 | 25 | let Rule = []; 26 | let urlRewrite = []; 27 | let plugin = []; 28 | let MapLocal = []; 29 | let uHalf = []; 30 | let lHalf = []; 31 | let mods = []; 32 | 33 | body.forEach((x, y, z) => { 34 | x = x.replace(/^ *(#|;|\/\/)/,"#").replace(" _ reject"," - reject").replace(/(\{[0-9]+)\,([0-9]*\})/gi,'$1t&zd;$2').replace(/\[URL\x20Rewrite\]/i,"[Rewrite]"); 35 | 36 | if (x.match(/^[^#].+(\x20-)?\x20+reject-?/)){ 37 | 38 | z[y - 1]?.match(/^#/) && urlRewrite.push(z[y - 1]); 39 | urlRewrite.push(x.replace(/(^#)?(.+?)(\x20+-)?\x20+(reject(-.+)?)/,`$1$2 - $4`)); 40 | 41 | }else if (x.match(/^(DOM|U|IP|GEO)[^,]+,[^,]+,.+/)){ 42 | z[y - 1]?.match(/^#/) && Rule.push(z[y - 1]); 43 | 44 | Rule.push(x); 45 | 46 | }else if (x.match(/^(DOM|USER|URL|IP|GEO)[^,]+,[^,]+$/)){ 47 | x.replace(/^(DOM|USER|URL|IP|GEO)[^,]+,[^,]+$/,""); 48 | }else if (x.match(/\x20+(302|307)\x20+/)){ 49 | 50 | z[y - 1]?.match(/^#/) && urlRewrite.push(z[y - 1]); 51 | 52 | urlRewrite.push(x.replace(/(.+)\x20+(302|307)\x20+(.+)/,"$1 $3 $2")); 53 | }else{ 54 | plugin.push(x) 55 | }; 56 | 57 | }); //循环结束 58 | 59 | plugin = (plugin[0] || '') && `${plugin.join("\n\n")}`; 60 | 61 | Rule = (Rule[0] || '') && `${Rule.join("\n")}`; 62 | 63 | urlRewrite = (urlRewrite[0] || '') && `${urlRewrite.join("\n\n")}`; 64 | 65 | if (urlRewrite !== "" && plugin.match("[Rewrite]")){ 66 | uHalf = plugin.split(/\[Rewrite\]/i)[0]; 67 | lHalf = plugin.split(/\[Rewrite\]/i)[1]; 68 | mods = `${uHalf}\n\n[Rewrite]\n\n${urlRewrite}\n\n${lHalf}`; 69 | }else{if (urlRewrite != ""){ 70 | mods = `${plugin}${urlRewrite}` 71 | }else{ 72 | mods = `${plugin}`; 73 | } 74 | }; 75 | 76 | if (Rule !== "" && mods.match("[Rule]")){ 77 | uHalf = mods.split(/\[Rule\]/i)[0]; 78 | lHalf = mods.split(/\[Rule\]/i)[1]; 79 | mods = `${uHalf}\n\n[Rule]\n\n${Rule}\n\n${lHalf}`; 80 | }else{if (Rule != ""){ 81 | mods = `${mods}${Rule}` 82 | }else{ 83 | mods = `${mods}`; 84 | } 85 | }; 86 | 87 | body = `${mods}` 88 | .replace(/t&zd;/g,',') 89 | .replace(/\[Rewrite\]/gi,'\n[URL Rewrite]\n') 90 | .replace(/\[MITM\]/gi,'\n[MITM]\n') 91 | .replace(/\[Script\]/gi,'\n[Script]\n') 92 | .replace(/\[Rule\]/gi,'\n[Rule]\n') 93 | .replace(/\[General\]/gi,'\n[General]\n') 94 | .replace(/hostname\x20*=\x20*(.*)/gi,"hostname = %APPEND% $1") 95 | .replace(/skip-proxy\x20*=\x20*(.*)/gi,"skip-proxy = %APPEND% $1") 96 | .replace(/bypass-tun\x20*=\x20*(.*)/gi,"tun-excluded-routes = %APPEND% $1") 97 | .replace(/real-ip\x20*=\x20*(.*)/gi,"always-real-ip = %APPEND% $1") 98 | .replace(/(#.+\n)\n+/g,'$1') 99 | .replace(/\n{2,}/g,'\n\n') 100 | .replace(/hostname\x20=\x20%APPEND%\x20\n\n安装失败\n\n1、请检查模块商店是否安装\n\n2、请检查是否开启HTTPS解密\n\n小火箭开启HTTPS解密教程https:\/\/t\.me\/h5683577\/3\n\nSurge开启HTTPS解密\(MITM\)教程https:\/\/t\.me\/h5683577\/135/,"hostname = %APPEND% \n\n模块商店已成功安装!!!") 101 | 102 | 103 | if (body.match("验证结果↓↓↓") != null && body.match("请检查模块商店是否安装") == null) { 104 | $notification.post("已成功安装模块商店","点击通知跳转模块商店","https://loon-gallery.vercel.app/",modStore) 105 | }else{}; 106 | 107 | 108 | $done({ response: { status: 200 ,body:body ,headers: {'Content-Type': 'text/plain; charset=utf-8'} } }); 109 | }//判断是否断网的反括号 110 | 111 | })() 112 | .catch((e) => { 113 | $notification.post(`${e}`,'',''); 114 | $done() 115 | }) 116 | 117 | 118 | function http(req) { 119 | return new Promise((resolve, reject) => 120 | $httpClient.get(req, (err, resp,data) => { 121 | resolve(data) 122 | }) 123 | ) 124 | } -------------------------------------------------------------------------------- /scripts/weibo_json.js: -------------------------------------------------------------------------------- 1 | /******************************************************** 2 | 3 | *应用名称:自用微博国际版去广告脚本 4 | *脚本作者:Cuttlefish 5 | *微信账号:公众号墨鱼手记 6 | *更新时间:2022-12-10 7 | *脚本版本:(0.0.10) 8 | *通知频道:https://t.me/ddgksf2021 9 | *问题反馈:ddgksf2013@163.com 10 | 11 | *******************************************************/ 12 | const mainConfig = {}; 13 | const modifyCardsUrls = ['/cardlist', 'video/community_tab', '/searchall']; 14 | const modifyTimeUrls = ['statuses/friends_timeline', 'statuses/unread_hot_timeline', 'groups/timeline']; 15 | const modifyOtherUrls = { 16 | 'ct=feed&a=trends': 'removeTopics',/* 屏蔽探索页面下的一些Topic */ 17 | 'search_topic' : 'modifiedSearchTopic', 18 | 'user_center' : 'modifiedUserCenter' 19 | } 20 | function getModifyMethod(url) { 21 | for (const s of modifyCardsUrls) { 22 | if(url.indexOf(s) > -1) { 23 | return 'removeCards'; 24 | } 25 | } 26 | for (const s of modifyTimeUrls) { 27 | if(url.indexOf(s) > -1) { 28 | return 'removeTimeLine'; 29 | } 30 | } 31 | for(const [path, method] of Object.entries(modifyOtherUrls)) { 32 | if(url.indexOf(path) > -1) { 33 | return method; 34 | } 35 | } 36 | return null; 37 | } 38 | function modifiedSearchTopic(data) { 39 | data = {"data":[],"info":"","retcode":0,"ext":{"search_hot_simple":{"title":"\u70ed\u95e8\u641c\u7d22","desc":"","more":"\u66f4\u591a\u70ed\u641c"},"search_hot":{"title":"\u5fae\u535a\u70ed\u641c\u699c","desc":"\u5b9e\u65f6\u70ed\u70b9\uff0c\u6bcf\u5206\u949f\u66f4\u65b0\u4e00\u6b21","more":""},"search_city":{"title":"\u540c\u57ce\u70ed\u70b9","desc":"","more":""}}}; 40 | } 41 | function modifiedUserCenter(data) { 42 | if(!data.data||data.data.length===0) { 43 | return data; 44 | } 45 | if(data.data.cards){ 46 | data.data.cards=Object.values(data.data.cards).filter((item) => !(item.items[0].type=='personal_vip')); 47 | } 48 | return data; 49 | } 50 | function removeTopics(data) { 51 | if(!data.data) { 52 | return data; 53 | } 54 | //if(data.data.search_topic) {delete data.data.search_topic;} 55 | if(data.data.topics) {delete data.data.topics;} 56 | if(data.data.discover) {delete data.data.discover;} 57 | 58 | return data; 59 | } 60 | function isAd(data) { 61 | if(!data) { 62 | return false; 63 | } 64 | if(data.mblogtypename == '广告' || data.mblogtypename == '热推') {return true}; 65 | if(data.mblogtypename == '廣告' || data.mblogtypename == '熱推') {return true}; 66 | if(data.readtimetype == 'adMblog') {return true}; 67 | if(data.promotion && data.promotion.type == 'ad') {return true}; 68 | return false; 69 | } 70 | 71 | function isBlock(data) { 72 | let blockIds = mainConfig.blockIds || []; 73 | if(blockIds.length === 0) { 74 | return false; 75 | } 76 | let uid = data.user.id; 77 | for (const blockId of blockIds) { 78 | if(blockId == uid) { 79 | return true; 80 | } 81 | } 82 | return false; 83 | } 84 | 85 | function removeTimeLine(data) { 86 | for (const s of ["ad", "advertises", "trends"]) { 87 | if(data[s]) { 88 | delete data[s]; 89 | } 90 | } 91 | if(!data.statuses) { 92 | return; 93 | } 94 | let newStatuses = []; 95 | for (const s of data.statuses) { 96 | if(!isAd(s)) { 97 | //lvZhouHandler(s); 98 | if(!isBlock(s)) { 99 | newStatuses.push(s); 100 | } 101 | } 102 | } 103 | data.statuses = newStatuses; 104 | } 105 | function removeCards(data) { 106 | if(!data.cards) { 107 | return; 108 | } 109 | let newCards = []; 110 | for (const card of data.cards) { 111 | let cardGroup = card.card_group; 112 | if(cardGroup && cardGroup.length > 0) { 113 | let newGroup = []; 114 | for (const group of cardGroup) { 115 | let cardType = group.card_type; 116 | if(cardType != 118) { 117 | newGroup.push(group); 118 | } 119 | } 120 | card.card_group = newGroup; 121 | newCards.push(card); 122 | } else { 123 | let cardType = card.card_type; 124 | if([9,165].indexOf(cardType) > -1) { 125 | if(!isAd(card.mblog)) { 126 | newCards.push(card); 127 | } 128 | } else { 129 | newCards.push(card); 130 | } 131 | } 132 | } 133 | data.cards = newCards; 134 | } 135 | var body = $response.body; 136 | var url = $request.url; 137 | let method = getModifyMethod(url); 138 | if(method) { 139 | var func = eval(method); 140 | let data = JSON.parse(body); 141 | new func(data); 142 | body = JSON.stringify(data); 143 | } 144 | $done({body}); -------------------------------------------------------------------------------- /scripts/bilibili_json.js: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | > 应用名称:墨鱼自用B站去广告脚本 3 | > 脚本作者:@ddgksf2013 4 | > 微信账号:墨鱼手记 5 | > 更新时间:2023-01-17 6 | > 通知频道:https://t.me/ddgksf2021 7 | > 贡献投稿:https://t.me/ddgksf2013_bot 8 | > 问题反馈:ddgksf2013@163.com 9 | > 特别提醒:如需转载请注明出处,谢谢合作! 10 | ***********************************************/ 11 | 12 | 13 | 14 | 15 | const version = 'V2.0.103'; 16 | 17 | let body=$response.body;if(body){switch(!0){case/^https:\/\/app\.bilibili\.com\/x\/v2\/feed\/index\?/.test($request.url):try{let t=JSON.parse(body),i=[];for(let a of t.data.items)if(!a.hasOwnProperty("banner_item")){if(!(!a.hasOwnProperty("ad_info")&&-1===a.card_goto?.indexOf("ad")&&["small_cover_v2","large_cover_v1","large_cover_single_v9"].includes(a.card_type)))continue;else i.push(a)}t.data.items=i,body=JSON.stringify(t)}catch(e){console.log("bilibili index:"+e)}break;case/^https?:\/\/app\.bilibili\.com\/x\/v2\/feed\/index\/story\?/.test($request.url):try{let s=JSON.parse(body),l=[];for(let d of s.data.items)d.hasOwnProperty("ad_info")||-1!==d.card_goto.indexOf("ad")||l.push(d);s.data.items=l,body=JSON.stringify(s)}catch(o){console.log("bilibili Story:"+o)}break;case/^https?:\/\/app\.bilibili\.com\/x\/v\d\/account\/teenagers\/status\?/.test($request.url):try{let r=JSON.parse(body);r.data.teenagers_status=0,body=JSON.stringify(r)}catch(b){console.log("bilibili teenagers:"+b)}break;case/^https?:\/\/app\.bilibili\.com\/x\/resource\/show\/tab/.test($request.url):try{let p=new Set([177,178,179,181,102,104,106,486,488,489]),c=JSON.parse(body);if(c.data?.tab&&(c.data.tab=[{id:39,name:"直播",uri:"bilibili://live/home",tab_id:"直播tab",pos:1},{id:40,name:"推荐",uri:"bilibili://pegasus/promo",tab_id:"推荐tab",pos:2,default_selected:1},{id:41,name:"热门",uri:"bilibili://pegasus/hottopic",tab_id:"hottopic",pos:3},{id:545,name:"番剧",uri:"bilibili://pgc/home",tab_id:"bangumi",pos:4},{id:151,name:"影视",uri:"bilibili://pgc/cinema-tab",tab_id:"film",pos:5}]),c.data.top&&(c.data.top=[{id:481,icon:"http://i0.hdslb.com/bfs/archive/d43047538e72c9ed8fd8e4e34415fbe3a4f632cb.png",name:"消息",uri:"bilibili://link/im_home",tab_id:"消息Top",pos:1}]),c.data.bottom){let n=c.data.bottom.filter(t=>p.has(t.id));c.data.bottom=n}body=JSON.stringify(c)}catch(y){console.log("bilibili tab processing:"+y)}break;case/^https?:\/\/app\.bilibili\.com\/x\/v2\/account\/mine/.test($request.url):try{let u=JSON.parse(body),f=new Set([396,397,398,399,407,410,402,404,425,426,427,428,430,432,433,434,494,495,496,497,500,501]);u.data.sections_v2.forEach((t,i)=>{let a=t.items.filter(t=>f.has(t.id));u.data.sections_v2[i].items=a,u.data.sections_v2[i].button={},delete u.data.sections_v2[i].be_up_title,delete u.data.sections_v2[i].tip_icon,delete u.data.sections_v2[i].tip_title,"创作中心"==u.data.sections_v2[i].title&&(delete u.data.sections_v2[i].title,delete u.data.sections_v2[i].type)}),delete u.data.vip_section_v2,delete u.data.vip_section,u.data.hasOwnProperty("live_tip")&&(u.data.live_tip={}),u.data.hasOwnProperty("answer")&&(u.data.answer={}),u.data.vip_type=2,u.data.vip.type=2,u.data.vip.status=1,u.data.vip.vip_pay_type=1,u.data.vip.due_date=4669824160,body=JSON.stringify(u)}catch(h){console.log("bilibili mypage:"+h)}break;case/^https?:\/\/api\.live\.bilibili\.com\/xlive\/app-room\/v1\/index\/getInfoByRoom/.test($request.url):try{let m=JSON.parse(body);m.data.activity_banner_info=null,body=JSON.stringify(m)}catch(v){console.log("bilibili live broadcast:"+v)}break;case/^https?:\/\/app\.bilibili\.com\/x\/resource\/top\/activity/.test($request.url):try{let g=JSON.parse(body);g.data&&(g.data.hash="ddgksf2013",g.data.online.icon=""),body=JSON.stringify(g)}catch(_){console.log("bilibili right corner:"+_)}break;case/^https?:\/\/app\.bilibili\.com\/x\/v2\/search\/square/.test($request.url):try{let $=JSON.parse(body);$.data={type:"history",title:"搜索历史",search_hotword_revision:2},body=JSON.stringify($)}catch(x){console.log("bilibili hot search:"+x)}break;case/https?:\/\/app\.bilibili\.com\/x\/v2\/account\/myinfo\?/.test($request.url):try{let k=JSON.parse(body);k.data.vip.type=2,k.data.vip.status=1,k.data.vip.vip_pay_type=1,k.data.vip.due_date=4669824160,body=JSON.stringify(k)}catch(w){console.log("bilibili 1080p:"+w)}break;case/pgc\/page\/(bangumi|cinema\/tab\?)/.test($request.url):try{let O=JSON.parse(body);O.result.modules.forEach(t=>{t.style.startsWith("banner")&&(t.items=t.items.filter(t=>-1!=t.link.indexOf("play"))),t.style.startsWith("function")&&(t.items=t.items.filter(t=>-1==t.blink.indexOf("www.bilibili.com")),[1283,241,1441,1284].includes(t.module_id)&&(t.items=[])),t.style.startsWith("tip")&&(t.items=[])}),body=JSON.stringify(O)}catch(P){console.log("bilibili fanju:"+P)}break;case/^https:\/\/app\.bilibili\.com\/x\/v2\/splash\/list/.test($request.url):try{let W=JSON.parse(body);if(W.data&&W.data.list)for(let E of W.data.list)E.duration=0,E.begin_time=2240150400,E.end_time=2240150400;body=JSON.stringify(W)}catch(j){console.log("bilibili openad:"+j)}break;case/^https:\/\/api\.live\.bilibili\.com\/xlive\/app-interface\/v2\/index\/feed/.test($request.url):try{let q=JSON.parse(body);q.data&&q.data.card_list&&(q.data.card_list=q.data.card_list.filter(t=>"banner_v1"!=t.card_type)),body=JSON.stringify(q)}catch(B){console.log("bilibili xlive:"+B)}break;default:$done({})}$done({body})}else $done({}); -------------------------------------------------------------------------------- /Block/bilibili.module: -------------------------------------------------------------------------------- 1 | #!name=哔哩哔哩 2 | #!desc=哔哩哔哩功能整合 3 | # ==UserScript== 4 | # @ScriptName BiliBili_AdBlock_DIY 5 | # @Author @ddgksf2013, @blackmatrix7, @app2smile, @yjqiang 6 | //B站解锁普通视频高码率仅适用国区粉色APP,外区为自我安慰 7 | [MITM] 8 | hostname = %APPEND% *.hdslb.com,app.bilibili.com,api.live.bilibili.com,api.vc.bilibili.com,api.bilibili.com,manga.bilibili.com,grpc.biliapi.net,api.biliapi.net,-broadcast.chat.bilibili.com,-*cdn*.biliapi.net,-*tracker*.biliapi.net,upos-hz-mirrorakam.akamaized.net 9 | 10 | 11 | [URL Rewrite] 12 | 13 | #UPOS服务器替换为腾讯Cos对象存储 14 | ^https?:\/\/upos-hz-mirrorakam\.akamaized\.net\/(.*) https://upos-sz-mirrorcos.bilivideo.com/$1 302 15 | # ~ BiliBili_哔哩哔哩_屏蔽直播间商品广告浮窗@ddgksf2013 16 | ^https?:\/\/api\.live\.bilibili\.com\/xlive\/e-commerce-interface\/v\d\/ecommerce-user\/get_shopping_info\? - reject-dict 17 | # ~ BiliBili_哔哩哔哩_屏蔽广告浮窗@ddgksf2013 18 | ^https?:\/\/api\.bilibili\.com\/pgc\/activity\/deliver\/material\/receive - reject-dict 19 | # ~ BiliBili_哔哩哔哩_屏蔽IP请求@ddgksf2013 20 | ^https?:\/\/app\.bilibili\.com\/x\/resource\/ip - reject 21 | # ~ BiliBili_哔哩哔哩_屏蔽DefaultWord@ddgksf2013 22 | ^https?:\/\/app\.bilibili\.com\/bilibili\.app\.interface\.v1\.Search\/Default - reject 23 | # ~ BiliBili_哔哩哔哩_应用开屏去广告@bm7 24 | ^https://app.bilibili.com/x/v2/splash/show - reject-dict 25 | # ~ BiliBili_哔哩哔哩_Defaultword@ddgksf2013 26 | ^https://app.bilibili.com/x/v2/search/defaultwords - reject-dict 27 | # ~ BiliBili_哔哩哔哩_Material_Ad@ddgksf2013 28 | ^https?:\/\/api\.bilibili\.com\/x\/vip\/ads\/material\/report - reject-dict 29 | # ~ BiliBili_哔哩哔哩_小卡片广告@ddgksf2013 30 | ^https://api.bilibili.com/pgc/season/player/cards - reject-dict 31 | # ~ BiliBili_哔哩哔哩_漫画去广告@ddgksf2013 32 | ^https?:\/\/manga\.bilibili\.com\/twirp\/comic\.v\d\.Comic\/(Flash|ListFlash) - reject-dict 33 | 34 | [Script] 35 | 36 | # ~ BiliBili_哔哩哔哩_屏蔽首页右上活动@ddgksf2013 37 | bilibili_json = type=http-response,pattern=^https?:\/\/app\.bilibili\.com\/x\/resource\/top\/activity,requires-body=1,max-size=3145728,script-path=https://github.com/ddgksf2013/Scripts/raw/master/bilibili_json.js,script-update-interval=0 38 | 39 | # ~ BiliBili_哔哩哔哩_观影页面去广告@ddgksf2013 40 | bilibili_json = type=http-response,pattern=^https?:\/\/api\.(bilibili|biliapi)\.(com|net)\/pgc\/page\/cinema\/tab\?,requires-body=1,max-size=3145728,script-path=https://github.com/ddgksf2013/Scripts/raw/master/bilibili_json.js,script-update-interval=0 41 | 42 | # ~ BiliBili_哔哩哔哩_应用开屏广告预加载@yjqiang 43 | bilibili_json = type=http-response,pattern=^https:\/\/app\.bilibili\.com\/x\/v2\/splash\/list,requires-body=1,max-size=3145728,script-path=https://github.com/ddgksf2013/Scripts/raw/master/bilibili_json.js,script-update-interval=0 44 | 45 | #魔改皮肤脚本自带解锁4k,和我的页面处理功能,自行选择 46 | 47 | # ~ BiliBili_哔哩哔哩_我的页面处理@ddgksf2013 48 | bilibili_json = type=http-response,pattern=^https?:\/\/app\.bilibili\.com\/x\/v2\/account\/mine,requires-body=1,max-size=3145728,script-path=https://github.com/ddgksf2013/Scripts/raw/master/bilibili_json.js,script-update-interval=0 49 | 50 | # ~ BiliBili_哔哩哔哩_1080P高码率+4K画质(番剧和影视除外)@ddgksf2013 51 | bilibili_json = type=http-response,pattern=^https?:\/\/app\.bilibili\.com\/x\/v2\/account\/myinfo\?,requires-body=1,max-size=3145728,script-path=https://github.com/ddgksf2013/Scripts/raw/master/bilibili_json.js,script-update-interval=0 52 | 53 | #魔改皮肤 作者@ClydeTime 54 | #魔改皮肤 = type=http-response,requires-body=1,max-size=3145728,timeout=60,pattern=^https?:\/\/ap(i|p)\.bilibili\.com\/x\/(vip|v2|resource)\/(space|account|web|price|top_panel_info|show)(\/|\?)(mine|myinfo|access|vip_center|panel|_bridge|skin\?).*,script-path=https://raw.githubusercontent.com/ClydeTime/Quantumult/main/Script/BiliBili/bili_info.js 55 | 56 | # ~ BiliBili_哔哩哔哩_热搜发现@ddgksf2013 57 | bilibili_json = type=http-response,pattern=^https://app.bilibili.com/x/v2/search/square,requires-body=1,max-size=3145728,script-path=https://github.com/ddgksf2013/Scripts/raw/master/bilibili_json.js,script-update-interval=0 58 | 59 | # ~ BiliBili_哔哩哔哩_推荐去广告@ddgksf2013 60 | bilibili_json = type=http-response,pattern=^https?:\/\/app\.bilibili\.com\/x\/v2\/feed\/index,requires-body=1,max-size=3145728,script-path=https://github.com/ddgksf2013/Scripts/raw/master/bilibili_json.js,script-update-interval=0 61 | 62 | # ~ BiliBili_哔哩哔哩_追番去广告@ddgksf2013 63 | bilibili_json = type=http-response,pattern=^https?:\/\/api\.(bilibili|biliapi)\.(com|net)\/pgc\/page\/bangumi,requires-body=1,max-size=3145728,script-path=https://github.com/ddgksf2013/Scripts/raw/master/bilibili_json.js,script-update-interval=0 64 | 65 | # ~ BiliBili_哔哩哔哩_直播去广告@bm7 66 | bilibili_json = type=http-response,pattern=^https?:\/\/api\.live\.bilibili\.com\/xlive\/app-room\/v1\/index\/getInfoByRoom,requires-body=1,max-size=3145728,script-path=https://github.com/ddgksf2013/Scripts/raw/master/bilibili_json.js,script-update-interval=0 67 | 68 | # ~ BiliBili_哔哩哔哩_标签页处理@ddgksf2013 69 | bilibili_json = type=http-response,pattern=^https?:\/\/app\.bilibili\.com\/x\/resource\/show\/tab,requires-body=1,max-size=3145728,script-path=https://github.com/ddgksf2013/Scripts/raw/master/bilibili_json.js,script-update-interval=0 70 | 71 | # ~ BiliBili_哔哩哔哩_Proto去广告@app2smile 72 | bilibili_proto = type=http-response,pattern=^https:\/\/(grpc\.biliapi\.net|app\.bilibili\.com)\/bilibili\.app\.(view\.v1\.View\/View|dynamic\.v2\.Dynamic\/DynAll|playurl\.v1\.PlayURL\/PlayView)$,requires-body=1,max-size=3145728,binary-body-mode=1,script-path=https://github.com/ddgksf2013/Scripts/raw/master/bilibili_proto.js,script-update-interval=0 73 | 74 | # ~ BiliBili_哔哩哔哩_繁体CC字幕转中文简体@ddgksf2013 75 | bilibili_cc = type=http-response,pattern=^https?:\/\/i.\.hdslb\.com\/bfs\/subtitle\/.+\.json$,requires-body=1,max-size=3145728,script-path=https://github.com/ddgksf2013/Scripts/raw/master/bilibili_cc.js,script-update-interval=0 76 | 77 | #以下切区脚本仅国际版B站有效,需设置分流和策略组,教程链接https://t.me/weltyfjd/4 请看完教程再考虑是否启用 78 | 79 | #B站切区 作者@Nobyda 80 | #Bili Region = type=http-response,pattern=^https:\/\/ap(p|i)\.bili(bili|api)\.(com|net)\/(pgc\/view\/v\d\/app\/season|x\/offline\/version)\?,requires-body=1,max-size=3145728,timeout=60,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Bili_Auto_Regions.js 81 | #可选, 适用于搜索指定地区的番剧 作者@Nobyda 82 | #Bili Search = type=http-request,timeout=60,pattern=^https:\/\/ap(p|i)\.bili(bili|api)\.(com|net)\/x\/v\d\/search(\/type)?\?.+?%20(%E6%B8%AF|%E5%8F%B0|%E4%B8%AD)&,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Bili_Auto_Regions.js 83 | -------------------------------------------------------------------------------- /Block/bili.module: -------------------------------------------------------------------------------- 1 | #!url=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/Block/bilibili.module 2 | #!name=哔哩哔哩 3 | #!desc=哔哩哔哩功能整合 4 | # ==UserScript== 5 | # @ScriptName BiliBili_AdBlock_DIY 6 | # @Author @ddgksf2013, @blackmatrix7, @app2smile, @yjqiang 7 | //B站解锁普通视频高码率仅适用国区粉色APP,外区为自我安慰 8 | [MITM] 9 | hostname = %APPEND% *.hdslb.com,app.bilibili.com,api.live.bilibili.com,api.vc.bilibili.com,api.bilibili.com,manga.bilibili.com,grpc.biliapi.net,api.biliapi.net,-broadcast.chat.bilibili.com,-*cdn*.biliapi.net,-*tracker*.biliapi.net,upos-hz-mirrorakam.akamaized.net 10 | 11 | [Rule] 12 | #防止tun模式下切区脚本失效 13 | IP-CIDR,203.107.1.1/24,REJECT,no-resolve 14 | 15 | [URL Rewrite] 16 | #UPOS服务器替换为腾讯Cos对象存储 17 | ^https?:\/\/upos-hz-mirrorakam\.akamaized\.net\/(.*) https://upos-sz-mirrorcos.bilivideo.com/$1 302 18 | # ~ BiliBili_哔哩哔哩_屏蔽广告浮窗@ddgksf2013 19 | ^https?:\/\/api\.bilibili\.com\/pgc\/activity\/deliver\/material\/receive - reject-dict 20 | # ~ BiliBili_哔哩哔哩_屏蔽IP请求@ddgksf2013 21 | ^https?:\/\/app\.bilibili\.com\/x\/resource\/ip - reject 22 | # ~ BiliBili_哔哩哔哩_屏蔽DefaultWord@ddgksf2013 23 | ^https?:\/\/app\.bilibili\.com\/bilibili\.app\.interface\.v1\.Search\/Default - reject 24 | # ~ BiliBili_哔哩哔哩_应用开屏去广告@bm7 25 | ^https://app.bilibili.com/x/v2/splash/show - reject-dict 26 | # ~ BiliBili_哔哩哔哩_Defaultword@ddgksf2013 27 | ^https://app.bilibili.com/x/v2/search/defaultwords - reject-dict 28 | # ~ BiliBili_哔哩哔哩_Material_Ad@ddgksf2013 29 | ^https?:\/\/api\.bilibili\.com\/x\/vip\/ads\/material\/report - reject-dict 30 | # ~ BiliBili_哔哩哔哩_小卡片广告@ddgksf2013 31 | ^https://api.bilibili.com/pgc/season/player/cards - reject-dict 32 | # ~ BiliBili_哔哩哔哩_去除动态中的话题@bm7 33 | ^https?:\/\/api\.vc\.bilibili\.com\/topic_svr\/v1\/topic_svr - reject-dict 34 | # ~ BiliBili_哔哩哔哩_漫画去广告@ddgksf2013 35 | ^https?:\/\/manga\.bilibili\.com\/twirp\/comic\.v\d\.Comic\/(Flash|ListFlash) - reject-dict 36 | 37 | [Script] 38 | # ~ 嗶哩嗶哩繁體CC字幕轉中文簡體(2022-04-02)@ddgksf2013 39 | 简体字幕 = type=http-response,requires-body=1,max-size=3145728,timeout=60,pattern=^https?:\/\/i.\.hdslb\.com\/bfs\/subtitle\/.+\.json$,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/bilibili_cc.js 40 | # ~ BiliBili_哔哩哔哩_观影页面去广告@ddgksf2013 41 | 观影页广告 = type=http-response,requires-body=1,max-size=3145728,timeout=60,pattern=^https?:\/\/api\.(bilibili|biliapi)\.(com|net)\/pgc\/page\/cinema\/tab\?,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/bilibili_json.js 42 | # ~ BiliBili_哔哩哔哩_应用开屏广告预加载@yjqiang 43 | 开屏预加载 = type=http-response,requires-body=1,max-size=3145728,timeout=60,pattern=^https:\/\/app\.bilibili\.com\/x\/v2\/splash\/list,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/bilibili_json.js 44 | # ~ BiliBili_哔哩哔哩_热搜发现@ddgksf2013 45 | 热搜 = type=http-response,requires-body=1,max-size=3145728,timeout=60,pattern=^https://app.bilibili.com/x/v2/search/square,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/bilibili_json.js 46 | # ~ BiliBili_哔哩哔哩_屏蔽首页右上活动@ddgksf2013 47 | 屏蔽首页右上角活动 = type=http-response,requires-body=1,max-size=3145728,timeout=60,pattern=^https?:\/\/app\.bilibili\.com\/x\/resource\/top\/activity,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/bilibili_json.js 48 | # ~ BiliBili_哔哩哔哩_推荐去广告@ddgksf2013 49 | 推荐去广告 = type=http-response,requires-body=1,max-size=3145728,timeout=60,pattern=^https?:\/\/app\.bilibili\.com\/x\/v2\/feed\/index,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/bilibili_json.js 50 | # ~ BiliBili_哔哩哔哩_追番去广告@ddgksf2013 51 | 追番去广告 = type=http-response,requires-body=1,max-size=3145728,timeout=60,pattern=^https?:\/\/api\.(bilibili|biliapi)\.(com|net)\/pgc\/page\/bangumi,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/bilibili_json.js 52 | # ~ BiliBili_哔哩哔哩_直播去广告@bm7 53 | 直播去广告 = type=http-response,requires-body=1,max-size=3145728,timeout=60,pattern=^https?:\/\/api\.live\.bilibili\.com\/xlive\/app-room\/v1\/index\/getInfoByRoom,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/bilibili_json.js 54 | # ~ BiliBili_哔哩哔哩_标签页处理@ddgksf2013 55 | 标签页处理 = type=http-response,requires-body=1,max-size=3145728,timeout=60,pattern=^https?:\/\/app\.bilibili\.com\/x\/resource\/show\/tab,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/bilibili_json.js 56 | # ~ BiliBili_哔哩哔哩_Proto去广告@app2smile 57 | bili-proto = type=http-response,pattern=^https:\/\/(grpc\.biliapi\.net|app\.bilibili\.com)\/bilibili\.app\.(view\.v1\.View\/View|dynamic\.v2\.Dynamic\/DynAll|playurl\.v1\.PlayURL\/PlayView)$,requires-body=1,binary-body-mode=1,max-size=0,script-path=https://raw.githubusercontent.com/app2smile/rules/master/js/bilibili-proto.js,script-update-interval=0 58 | #魔改皮肤脚本自带解锁4k,和我的页面处理功能,自行选择 59 | # ~ BiliBili_哔哩哔哩_我的页面处理@ddgksf2013 60 | #我的页面处理 = type=http-response,requires-body=1,max-size=3145728,timeout=60,pattern=^https?:\/\/app\.bilibili\.com\/x\/v2\/account\/mine,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/bilibili_json.js 61 | # ~ BiliBili_哔哩哔哩_1080P高码率+4K画质(番剧和影视除外)@ddgksf2013 62 | #解锁高码率 = type=http-response,requires-body=1,max-size=3145728,timeout=60,pattern=^https?:\/\/app\.bilibili\.com\/x\/v2\/account\/myinfo\?,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/bilibili_json.js 63 | #魔改皮肤 作者@ClydeTime 64 | 魔改皮肤 = type=http-response,requires-body=1,max-size=3145728,timeout=60,pattern=^https?:\/\/ap(i|p)\.bilibili\.com\/x\/(vip|v2|resource)\/(space|account|web|price|top_panel_info|show)(\/|\?)(mine|myinfo|access|vip_center|panel|_bridge|skin\?).*,script-path=https://raw.githubusercontent.com/ClydeTime/Quantumult/main/Script/BiliBili/bili_info.js 65 | 66 | #以下切区脚本需设置分流和策略组,教程链接https://t.me/weltyfjd/4 请看完教程再考虑是否启用 67 | 68 | #B站切区 作者@Nobyda 69 | #Bili Region = type=http-response,pattern=^https:\/\/ap(p|i)\.bili(bili|api)\.(com|net)\/(pgc\/view\/v\d\/app\/season|x\/offline\/version)\?,requires-body=1,max-size=3145728,timeout=60,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Bili_Auto_Regions.js 70 | #可选, 适用于搜索指定地区的番剧 作者@Nobyda 71 | #Bili Search = type=http-request,timeout=60,pattern=^https:\/\/ap(p|i)\.bili(bili|api)\.(com|net)\/x\/v\d\/search(\/type)?\?.+?%20(%E6%B8%AF|%E5%8F%B0|%E4%B8%AD)&,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/Bili_Auto_Regions.js 72 | -------------------------------------------------------------------------------- /Block/AdBlock.module: -------------------------------------------------------------------------------- 1 | #!name=广告屏蔽 2 | #!desc=通用广告屏蔽 3 | #搬运自zqzess 4 | 5 | [General] 6 | force-http-engine-hosts = %APPEND% *.cp31.ott.cibntv.net 7 | 8 | [Rule] 9 | 10 | #爱思去广告 11 | URL-REGEX,^https?:\/\/d\.image\.i4\.cn\/adInfo\/.+,REJECT 12 | #酷我9.1.0去广告 13 | #DOMAIN-SUFFIX,wapi.kuwo.cn,REJECT 14 | URL-REGEX,^https?:\/\/wapi\.kuwo\.cn\/api\/mobile\/index\/feed\?.+,REJECT 15 | URL-REGEX,fvedio\.kuwo\.cn,REJECT-DICT 16 | #美团 17 | URL-REGEX,^https?:\/\/(s3plus|flowplus)\.meituan\.net\/v\d\/\w+\/linglong\/\w+\.(gif|jpg|mp4),REJECT 18 | # 有兔阅读 19 | DOMAIN,app.zhoudamozi.com,DIRECT 20 | DOMAIN-SUFFIX,youzibank.com,DIRECT 21 | DOMAIN-SUFFIX,mituyuedu.com,DIRECT 22 | DOMAIN,img.allahall.com,DIRECT 23 | DOMAIN,img.dailmo.com,DIRECT 24 | DOMAIN,activation.crossutility.com,DIRECT 25 | 26 | # 书旗广告域名,这广告实在太多了,可能误杀,不认识的全禁止了 27 | DOMAIN-SUFFIX,pangolin-sdk-toutiao.com,REJECT 28 | DOMAIN-SUFFIX,xwuad.com,REJECT 29 | DOMAIN-SUFFIX,tobapplog.ctobsnssdk.com,REJECT 30 | DOMAIN-SUFFIX,render.shuqireader.com,REJECT 31 | DOMAIN-SUFFIX,ali-stats.jpush.cn,REJECT 32 | DOMAIN-SUFFIX,toblog.ctobsnssdk.com,REJECT 33 | DOMAIN-SUFFIX,sdk.kaijia.com,REJECT 34 | DOMAIN-SUFFIX,tobapplog.ctobsnssdk.com,REJECT 35 | DOMAIN-SUFFIX,amdc.m.taobao.com,REJECT 36 | DOMAIN-SUFFIX,iyes.youku.com,REJECT 37 | DOMAIN-SUFFIX,sq.sljkj.com,REJECT 38 | DOMAIN-SUFFIX,s2s.adjust.com,REJECT 39 | DOMAIN-SUFFIX,pglstatp-toutiao,REJECT 40 | # 百度移动广告联盟,可能误杀 41 | DOMAIN-SUFFIX,mobads.baidu.com,REJECT 42 | # 腾讯广告联盟,可能误杀 43 | DOMAIN-SUFFIX,mi.gdt.qq.com,REJECT 44 | DOMAIN-SUFFIX,jcollection.shuqireader.com,REJECT 45 | DOMAIN-SUFFIX,stats.jpush.cn,REJECT 46 | DOMAIN-SUFFIX,sdk.kaijiawan.com,REJECT 47 | 48 | # 爱奇艺 49 | DOMAIN,cr-status.iqiyi.com,REJECT 50 | DOMAIN,f74f7f7765f8a2f6.ngaa.net.cn,REJECT 51 | DOMAIN,ef-dongfeng.tanx.com,REJECT 52 | DOMAIN,iqiyim.adtrack.enlightent.cn,REJECT 53 | DOMAIN,t7z.cupid.iqiyi.com,DIRECT 54 | DOMAIN,paopao-monitor.iqiyi.com,REJECT 55 | DOMAIN,puma-api.iqiyi.com,REJECT 56 | DOMAIN-SUFFIX,gdt.qq.com,REJECT 57 | DOMAIN-SUFFIX,upqzfile.com,REJECT 58 | DOMAIN,mbdlog.iqiyi.com,REJECT 59 | DOMAIN-SUFFIX,cupid.iqiyi.com,REJECT 60 | DOMAIN,myg.qy.net,REJECT 61 | DOMAIN,www.qchannel01.cn,REJECT 62 | DOMAIN,iqiyi-mipdx.cn.miaozhen.com,REJECT 63 | DOMAIN,show.ssports.com,REJECT 64 | DOMAIN-SUFFIX,afdback.ppsimg.com,REJECT 65 | #米读 66 | URL-REGEX,^https:\/\/apiwz\.midukanshu\.com\/advert\/getPopup$,REJECT 67 | URL-REGEX,^https:\/\/apiwz\.midukanshu\.com\/advert\/treasureInfo$,REJECT 68 | URL-REGEX,^https:\/\/apiwz\.midukanshu\.com\/config\/getAds$,REJECT 69 | DOMAIN,bid.adview.cn,REJECT 70 | 71 | # 优酷去片头广告(by Choler) 72 | # force-http-engine-hosts = %APPEND% *.cp31.ott.cibntv.net 73 | URL-REGEX,^http:\/\/.*\.cp31\.ott\.cibntv\.net\/youku\/,REJECT-TINYGIF 74 | 75 | # 高德地图 76 | DOMAIN,optimus-ads.amap.com,REJECT 77 | 78 | #backiee 79 | URL-REGEX,^https:\/\/www\.google\.com\.hk\/ads,REJECT 80 | DOMAIN,stats.g.doubleclick.net,REJECT 81 | DOMAIN,pagead2.googlesyndication.com,REJECT 82 | DOMAIN,googleads.g.doubleclick.net,REJECT 83 | DOMAIN,app-measurement.com,REJECT 84 | DOMAIN,ade.googlesyndication.com,REJECT 85 | DOMAIN,googleads4.g.doubleclick.net,REJECT 86 | 87 | DOMAIN,bymh26.com,REJECT 88 | 89 | # 下厨房 90 | DOMAIN,ulogs.umengcloud.com,REJECT 91 | DOMAIN,ulogs.umeng.com,REJECT 92 | DOMAIN,sdk.e.qq.com,REJECT 93 | DOMAIN,mi.gdt.qq.com,REJECT 94 | DOMAIN,open.e.kuaishou.com,REJECT 95 | DOMAIN,api-access.pangolin-sdk-toutiao.com,REJECT 96 | DOMAIN,sdk.open.talk.getui.net,REJECT 97 | DOMAIN,sdk.open.talk.getui.com,REJECT 98 | DOMAIN,errlog.umeng.com,REJECT 99 | DOMAIN,tnc3-aliec2.snssdk.com,REJECT 100 | DOMAIN,sf3-fe-tos.pglstatp-toutiao.com,REJECT 101 | DOMAIN,qzs.gdtimg.com,REJECT 102 | 103 | [URL Rewrite] 104 | #京东屏蔽开屏广告 105 | ^https?:\/\/api\.m\.jd\.com\/client\.action\*functionId=start - reject-dict 106 | ^https?:\/\/api\.m\.jd.com\/client\.action\*functionId=queryMaterialAdverts - reject-dict 107 | ^https?:\/\/api\.m\.jd\.com\/client\.action*functionId=msgEntranceV710 - reject-200 108 | ^https?:\/\/api\.m\.jd\.com\/client\.action*functionId=xview2Config - reject-200 109 | 110 | #中国招商银行 111 | ^https?:\/\/mlife\.cmbchina\.com\/ClientFaceService\/preCacheAdvertise\.json - reject 112 | ^https?:\/\/mlife\.cmbchina\.com\/ClientFaceService\/getAdvertisement\.json - reject 113 | ^https?:\/\/pic1cdn\.cmbchina\.com\/appinitads\/ - reject 114 | 115 | #买单吧4.7.2开屏,升级提示 116 | ^https:\/\/creditcardapp\.bankcomm\.com\/mappweb_interaction\/json\/app\/appManage\/getApkUpdateInfo\.do - reject 117 | ^https:\/\/creditcardapp\.bankcomm\.com\/mappweb_interaction\/common\/getPopAds\.do - reject 118 | ^https:\/\/creditcardapp\.bankcomm\.com\/mappweb_interaction\/common\/queryGuidePageAds\.do - reject 119 | 120 | # 有兔阅读(米兔)去羞耻的开屏广告图片 121 | ^http:\/\/img\.dailmo\.com\/img\/61\/23c7125bfe6166d69f3bff5b0ca4d31e\.jpg - reject 122 | ^http:\/\/img\.dailmo\.com\/img\/50\/edb40c6392f848df37f9c31d8a6f90f6\.jpg - reject 123 | ^http:\/\/img\.dailmo\.com\/img\/6\/90585d9e96c73dd49644af57d8501624\.jpg - reject 124 | ^http:\/\/img\.dailmo\.com\/img\/5\/6cb2aa237ce1f65944aa1ecb29fbdeef\.jpg - reject 125 | ^http:\/\/img\.allahall\.com\/img\/61\/23c7125bfe6166d69f3bff5b0ca4d31e\.jpg - reject 126 | ^http:\/\/img\.allahall\.com\/img\/50\/edb40c6392f848df37f9c31d8a6f90f6\.jpg - reject 127 | ^http:\/\/img\.allahall\.com\/img\/6\/90585d9e96c73dd49644af57d8501624\.jpg - reject 128 | ^http:\/\/img\.allahall\.com\/img\/5\/6cb2aa237ce1f65944aa1ecb29fbdeef\.jpg - reject 129 | ^http:\/\/img\.allahall\.com\/img\/59\/6a13a75dfe46ebfdac96bd27ef098885\.jpg - reject 130 | ^https?:\/\/img\.alipaycashyuan\.com\/img\/59\/6a13a75dfe46ebfdac96bd27ef098885\.+ - reject 131 | ^http:\/\/app\.zhoudamozi\.com\/ad\/.+ - reject 132 | 133 | 134 | 135 | # 书旗小说去广告 136 | ^http:\/\/ut2\.shuqistat\.com\/.+\.gif - reject 137 | ^https?:\/\/sq\.sljkj\.com\/api\/sdk\/ads2 - reject 138 | ^https?:\/\/ocean\.shuqireader\.com\/api\/ad\/adserver\/.+ - reject 139 | ^https?:\/\/ocean\.shuqireader\.com\/api\/route\/iosReadPage\/ad.+ - reject 140 | ^https?:\/\/img-tailor\.11222\.cn\/pm\/app\/.+\.gif - reject 141 | ^https?:\/\/img-tailor\.11222\.cn\/cms\/upload\/img\/.+ - reject 142 | ^http:\/\/message\.shuqireader\.com\/message\/.+ - reject 143 | ^https?:\/\/mobads\.baidu\.com\/cpro\/ui\/mads.+ - reject 144 | ^http:\/\/101\.91\.69\.26:8080\/.+ - reject 145 | ^http:\/\/feedback.uc.cn\/feedback\/api\/get_unread_status - reject 146 | ^http:\/\/.+\.shuqireader\.com\/sapi\/.+ - reject 147 | 148 | 149 | # 每日优鲜开屏广告->j-image.missfresh.cn 150 | ^https:\/\/j-image\.missfresh\.cn\/img_(.+)\.gif$ - reject 151 | ^https:\/\/j-image\.missfresh\.cn\/img_(.+)\.(jpg|jpeg|gif|png)\?iopcmd=convert&dst=webp&q=85$ - reject 152 | 153 | # 网易云广告->m.ads.8le8le.com,iadmusicmat.music.com 154 | ^https?:\/\/iadmusicmat\.music\.126\.net\/.+\.jpg - reject 155 | ^http:\/\/interface\.music\.163\.com\/eapi\/ad\/config\/get - reject 156 | ^https?:\//m\.ads\.8le8le\.com\/adShow - reject 157 | 158 | # 高德地图广告 159 | https:\/\/m5\.amap\.com\/ws\/shield\/nest\/updatable\/v1\/preUpgrade\? - reject 160 | ^http:\/\/ems\.youku\.com\/imp\? - reject 161 | ^http:\/\/optimus-ads\.amap\.com\/uploadimg\/.+ - reject 162 | ^https?:\/\/m5.amap.com\/ws\/valueadded\/ - reject 163 | 164 | # 携程广告->ma-adx.ctrip.com,m.ctrip.com 165 | ^https:\/\/ma-adx\.ctrip\.com\/_ma\.gif - reject 166 | ^https:\/\/m\.ctrip\.com\/restapi\/.+\/json\/tripAds - reject 167 | 168 | ^https:\/\/mbd\.baidu\.com\/newspage\/api\/getmobads\?page\=landingshare - reject 169 | 170 | # 爱奇艺广告屏蔽 171 | ^http:\/\/.+\.iqiyipic\.com\/image\/.+\/ad\/.+\.jpg - reject 172 | ^http:\/\/static-s\.iqiyi\.com\/common\/.+\/Small_video/a2/af/.+\.png - reject 173 | ^http://msga/.cupid/.iqiyi/.com\/scp2\.gif - reject 174 | https?:\/\/ssports\.iqiyi\.com\/app\/ - reject 175 | https?:\/\/ssports\.iqiyi\.com\/json\/shop\/shopInfo - reject 176 | https?:\/\/.+\.iqiyi\.com\/videos\/other\/20$ - reject 177 | https?:\/\/.+\.iqiyipic\.com\/image\/20*_100000 - reject 178 | #https?:\/\/static\.iqiyi\.com\/js\/common\/.+\.js - reject 179 | https?:\/\/t7z\.cupid\.iqiyi\.com\/show - reject 180 | # 搬运爱奇艺(by gitee-木剑)->act.vip.iqiyi.com 181 | ^https?:\/\/iface\.iqiyi\.com\/api\/getNewAdInfo - reject 182 | ^https?:\/\/act\.vip\.iqiyi\.com\/interact\/api\/show\.do - reject 183 | ^https?:\/\/act\.vip\.iqiyi\.com\/interact\/api\/v\d\/show - reject 184 | 185 | # 网易邮箱->appconf.mail.163.com,analytics.163.com 186 | https:\/\/appconf\.mail\.163\.com\/mmad\/get\.do - reject 187 | http:\/\/analytics\.163\.com\/ntes - reject 188 | 189 | 190 | # 搬运淘宝(by gitee-木剑)->gw.alicdn.com,heic.alicdn.com 191 | ^https?:\/\/(gw|heic)\.alicdn\.com\/\w{2}s\/.+\.jpg_(9\d{2}|\d{4}) - reject 192 | ^https?:\/\/(gw|heic)\.alicdn\.com\/imgextra\/.+\d{4}-\d{4}\.jpg_(9\d{2}|\d{4}) - reject 193 | 194 | [Script] 195 | # 微信公众号广告屏蔽(By Choler) 196 | 微信公众号广告屏蔽=type=http-response,pattern=^https?:\/\/mp\.weixin\.qq\.com\/mp\/getappmsgad,requires-body=1,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/File/Wechat.js 197 | 198 | 199 | [MITM] 200 | hostname = %APPEND% appconf.mail.163.com,analytics.163.com,mbd.baidu.com,m.ads.8le8le.com,iadmusicmat.music.com,ma-adx.ctrip.com,m.ctrip.com,api.m.jd.com,bdsp-x.jd.com,dsp-x.jd.com,mp.weixin.qq.com,ocean.shuqireader.com,mi.gdt.qq.com,mobads.baidu.com,sq.sljkj.com,img-tailor.11222.cn,j-image.missfresh.cn,act.vip.iqiyi.com,gw.alicdn.com,heic.alicdn.com,apiwz.midukanshu.com,*.iqiyipic.com,*.iqiyi.com,m5.amap.com,flowplus.meituan.net,*.bankcomm.com 201 | -------------------------------------------------------------------------------- /scripts/QX_to_Shadowrocket.js: -------------------------------------------------------------------------------- 1 | /****************** 2 | 原脚本作者@小白脸 脚本修改@chengkongyiban 3 | 感谢@xream 的指导 4 | 使用方法 在qx重写链接末尾加上qx 5 | 6 | [Script] 7 | QX转换 = type=http-request,pattern=qx$|qx\?.*,requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/QX_to_Shadowrocket.js 8 | 9 | [MITM] 10 | hostname = %APPEND% github.com:443, raw.githubusercontent.com:443 11 | ******************/ 12 | const ua = $request.headers['User-Agent'] || $request.headers['user-agent'] 13 | const isStashiOS = 'undefined' !== typeof $environment && $environment['stash-version'] && ua.indexOf('Macintosh') === -1 14 | const isSurgeiOS = 'undefined' !== typeof $environment && $environment['surge-version']; 15 | const isShadowrocket = 'undefined' !== typeof $rocket; 16 | const isLooniOS = 'undefined' != typeof $loon && /iPhone/.test($loon); 17 | 18 | var name = ""; 19 | var desc = ""; 20 | let req = $request.url.replace(/qx$|qx\?.*/,''); 21 | let urlArg = $request.url.replace(/.+qx(\?.*)/,'$1'); 22 | var original = [];//用于获取原文行号 23 | //获取参数 24 | var nName = urlArg.indexOf("n=") != -1 ? (urlArg.split("n=")[1].split("&")[0].split("+")) : null; 25 | var Pin0 = urlArg.indexOf("y=") != -1 ? (urlArg.split("y=")[1].split("&")[0].split("+")).map(decodeURIComponent) : null; 26 | var Pout0 = urlArg.indexOf("x=") != -1 ? (urlArg.split("x=")[1].split("&")[0].split("+")).map(decodeURIComponent) : null; 27 | //修改名字和简介 28 | if (nName === null){ 29 | name = req.match(/.+\/(.+)\.(conf|js|snippet|txt)/)?.[1] || '无名'; 30 | desc = name; 31 | }else{ 32 | name = nName[0] != "" ? nName[0] : req.match(/.+\/(.+)\.(conf|js|snippet|txt)/)?.[1]; 33 | desc = nName[1] != undefined ? nName[1] : nName[0]; 34 | }; 35 | name = "#!name=" + decodeURIComponent(name); 36 | desc = "#!desc=" + decodeURIComponent(desc); 37 | 38 | !(async () => { 39 | let body = await http(req); 40 | //判断是否断网 41 | if(body == null){if(isSurgeiOS || isStashiOS){ 42 | $notification.post("重写转换:未获取到body","请检查网络及节点是否畅通","认为是bug?点击通知反馈",{url:"https://t.me/zhangpeifu"}) 43 | $done({ response: { status: 404 ,body:{} } });}else{$notification.post("重写转换:未获取到body","请检查网络及节点是否畅通","认为是bug?点击通知反馈","https://t.me/zhangpeifu") 44 | $done({ response: { status: 404 ,body:{} } }); 45 | }//识别客户端通知 46 | }else{//以下开始重写及脚本转换 47 | 48 | original = body.replace(/^ *(#|;|\/\/)/g,'#').replace(/\x20+url\x20+/g," url ").replace(/(^[^#].+)\x20+\/\/.+/g,"$1").split("\n"); 49 | body = body.match(/[^\r\n]+/g); 50 | 51 | let script = []; 52 | let URLRewrite = []; 53 | let others = []; 54 | let MITM = ""; 55 | 56 | body.forEach((x, y, z) => { 57 | x = x.replace(/^ *(#|;|\/\/)/,'#').replace(/\x20+url\x20+/," url ").replace(/hostname\x20*=/,"hostname=").replace(/(^[^#].+)\x20+\/\/.+/,"$1"); 58 | //去掉注释 59 | if(Pin0 != null) { 60 | for (let i=0; i < Pin0.length; i++) { 61 | const elem = Pin0[i]; 62 | if (x.indexOf(elem) != -1){ 63 | x = x.replace(/^#/,"") 64 | }else{}; 65 | };//循环结束 66 | }else{};//去掉注释结束 67 | 68 | //增加注释 69 | if(Pout0 != null){ 70 | for (let i=0; i < Pout0.length; i++) { 71 | const elem = Pout0[i]; 72 | if (x.indexOf(elem) != -1 && x.indexOf("hostname=") == -1){ 73 | x = x.replace(/(.+)/,"#$1") 74 | }else{}; 75 | };//循环结束 76 | }else{};//增加注释结束 77 | 78 | let type = x.match( 79 | /\x20url\x20script-|enabled=|\x20url\x20reject|\x20echo-response\x20|-header\x20|^hostname| url 30|\x20(request|response)-body/ 80 | )?.[0]; 81 | 82 | //判断注释 83 | if (x.match(/^[^#]/)){ 84 | var noteK = ""; 85 | }else{ 86 | var noteK = "#"; 87 | }; 88 | 89 | if (type) { 90 | switch (type) { 91 | //脚本 92 | case " url script-": 93 | z[y - 1]?.match(/^#/) && script.push(z[y - 1]); 94 | let sctype = x.match(' script-response') ? 'response' : 'request'; 95 | 96 | let rebody = x.match(/\x20script[^\s]*(-body|-analyze)/) ? ',requires-body=1' : ''; 97 | 98 | let size = x.match(/\x20script[^\s]*(-body|-analyze)/) ? ',max-size=3145728' : ''; 99 | 100 | let urlInNum = x.replace(/\x20{2,}/g," ").split(" ").indexOf("url"); 101 | 102 | let ptn = x.replace(/\x20{2,}/g," ").split(" ")[urlInNum - 1].replace(/#/,""); 103 | 104 | let js = x.replace(/\x20{2,}/g," ").split(" ")[urlInNum + 2]; 105 | 106 | let proto = js.match('proto.js') ? ',binary-body-mode=1' : ''; 107 | 108 | let scname = js.substring(js.lastIndexOf('/') + 1, js.lastIndexOf('.') ); 109 | script.push( 110 | `${noteK}${scname}_${y} = type=http-${sctype},pattern=${ptn}${rebody}${size}${proto},script-path=${js},script-update-interval=0` 111 | ); 112 | break; 113 | //定时任务 114 | case "enabled=": 115 | z[y - 1]?.match(/^#/) && script.push(z[y - 1]); 116 | 117 | let cronExp = x.replace(/\x20{2,}/g," ").split(" http")[0].replace(/#/,''); 118 | 119 | let cronJs = x.split("://")[1].split(",")[0].replace(/(.+)/,'https://$1'); 120 | 121 | let croName = x.replace(/\x20/g,"").split("tag=")[1].split(",")[0]; 122 | 123 | script.push( 124 | `${noteK}${croName} = type=cron,script-path=${cronJs},timeout=60,cronexp=${cronExp},wake-system=1` 125 | ); 126 | break; 127 | //reject 128 | case " url reject": 129 | 130 | z[y - 1]?.match(/^#/) && URLRewrite.push(z[y - 1]); 131 | URLRewrite.push(x.replace(/\x20{2,}/g," ").replace(/(^#)?(.*?)\x20url\x20(reject-200|reject-img|reject-dict|reject-array|reject)/, `${noteK}$2 - $3`)); 132 | break; 133 | 134 | //(request|response)-header 135 | 136 | case "-header ": 137 | z[y - 1]?.match(/^#/) && script.push(z[y - 1]); 138 | 139 | let reHdType = x.match(' response-header ') ? 'response' : 'request'; 140 | 141 | let reHdPtn = x.replace(/\x20{2,}/g," ").split(" url re")[0].replace(/^#/,""); 142 | 143 | let reHdArg1 = x.split(" " + reHdType + "-header ")[1]; 144 | 145 | let reHdArg2 = x.split(" " + reHdType + "-header ")[2]; 146 | 147 | script.push(`${noteK}replaceHeader_${y} = type=http-${reHdType},pattern=${reHdPtn},script-path=https://raw.githubusercontent.com/xream/scripts/main/surge/modules/replace-header/index.js,argument=${reHdArg1}->${reHdArg2}`) 148 | 149 | break; 150 | 151 | case " echo-response ": 152 | 153 | let arg = x.split(" echo-response ")[2]; 154 | 155 | if(/^(https?|ftp|file):\/\/.*/.test(arg)){ 156 | 157 | z[y - 1]?.match(/^#/) && script.push(z[y - 1]); 158 | 159 | let urlInNum = x.replace(/\x20{2,}/g," ").split(" ").indexOf("url"); 160 | 161 | let ptn = x.replace(/\x20{2,}/g," ").split(" ")[urlInNum - 1].replace(/^#/,""); 162 | 163 | let scname = arg.substring(arg.lastIndexOf('/') + 1, arg.lastIndexOf('.') ); 164 | 165 | script.push( 166 | `${noteK}${scname}_${y} = type=http-request,pattern=${ptn},script-path=https://raw.githubusercontent.com/xream/scripts/main/surge/modules/echo-response/index.js,argument=type=text/json&url=${arg}`) 167 | 168 | }else{ 169 | let lineNum = original.indexOf(x) + 1; 170 | others.push(lineNum + "行" + x)} 171 | 172 | break; 173 | 174 | //mitm 175 | 176 | case "hostname": 177 | MITM = x.replace(/%.*%/g,"").replace(/\x20/g,"").replace(/hostname=(.*)/, `[MITM]\n\nhostname = %APPEND% $1`).replace(/,$/,""); 178 | break; 179 | 180 | //302/307 181 | case " url 30": 182 | z[y - 1]?.match(/^#/) && URLRewrite.push(z[y - 1]); 183 | URLRewrite.push(x.replace(/\x20{2,}/g," ").replace(/(^#)?(.*?)\x20url\x20(302|307)\s(.+)/, `${noteK}$2 $4 $3`)); 184 | 185 | break; 186 | 187 | default: 188 | 189 | //带参数脚本argument 190 | z[y - 1]?.match(/^#/) && script.push(z[y - 1]); 191 | 192 | let reBdType = x.match(' response-body ') ? 'response' : 'request'; 193 | 194 | let reBdPtn = x.replace(/\x20{2,}/g," ").split(" url re")[0].replace(/^#/,""); 195 | let reBdArg1 = x.split(" " + reBdType + "-body ")[1]; 196 | 197 | let reBdArg2 = x.split(" " + reBdType + "-body ")[2]; 198 | 199 | script.push( 200 | 201 | `${noteK}replaceBody_${y} = type=http-${reBdType},pattern=${reBdPtn},requires-body=1,max-size=3145728,script-path=https://raw.githubusercontent.com/mieqq/mieqq/master/replace-body.js,argument=${reBdArg1}->${reBdArg2}`, 202 | 203 | ); 204 | } 205 | 206 | } //switch结束 207 | 208 | }); //循环结束 209 | 210 | script = (script[0] || '') && `[Script]\n\n${script.join("\n\n")}`; 211 | 212 | URLRewrite = (URLRewrite[0] || '') && `[URL Rewrite]\n\n${URLRewrite.join("\n")}`; 213 | 214 | others = (others[0] || '') && `${others.join("\n\n")}`; 215 | 216 | body = `${name} 217 | ${desc} 218 | 219 | 220 | ${URLRewrite} 221 | 222 | 223 | ${script} 224 | 225 | 226 | ${MITM}` 227 | .replace(/t&zd;/g,',') 228 | .replace(/(#.+\n)\n+/g,'$1') 229 | .replace(/\n{2,}/g,'\n\n') 230 | 231 | if (isSurgeiOS || isStashiOS) { 232 | others !="" && $notification.post("不支持的类型已跳过","第" + others,"点击查看原文,长按可展开查看跳过行",{url:req}); 233 | } else {if (isLooniOS || isShadowrocket) { 234 | others !="" && $notification.post("不支持的类型已跳过","第" + others,"点击查看原文,长按可展开查看跳过行",req);}}; 235 | 236 | $done({ response: { status: 200 ,body:body ,headers: {'Content-Type': 'text/plain; charset=utf-8'} } }); 237 | }//判断是否断网的反括号 238 | 239 | })() 240 | .catch((e) => { 241 | $notification.post(`${e}`,'',''); 242 | $done() 243 | }) 244 | 245 | function http(req) { 246 | return new Promise((resolve, reject) => 247 | $httpClient.get(req, (err, resp,data) => { 248 | resolve(data) 249 | }) 250 | ) 251 | } -------------------------------------------------------------------------------- /scripts/txt_read.js: -------------------------------------------------------------------------------- 1 | /*************************** 2 | #!name=文本预览器 3 | #!desc=主要用于预览yaml及snippet 等Safari需要下载的文本 4 | 在需要预览的链接末尾加上.t_read.txt 5 | 6 | [MITM] 7 | 8 | hostname = %APPEND% github.com, raw.githubusercontent.com,gitlab.com,gist.githubusercontent.com,gitlab.com 9 | 10 | [rewrite_local] 11 | 12 | \.t_read\.txt$ url script-echo-response https://raw.githubusercontent.com/chengkongyiban/shadowrocket/main/scripts/txt_read.js 13 | 14 | ****************************/ 15 | const $ = new Env(`文本预览器`) 16 | 17 | let req = $request.url.replace(/\.t_read\.txt$/,''); 18 | 19 | !(async () => { 20 | 21 | body = (await $.http.get(req)).body; 22 | 23 | let ret = {body:body ,headers: {'Content-Type': 'text/plain; charset=utf-8'}}; 24 | 25 | $done($.isQuanX() ? ret : {response: ret }); 26 | 27 | })() 28 | .catch((e) => { 29 | $.msg("文本预览器",`${e}`,""); 30 | result = { 31 | response: { 32 | status: 500, 33 | body: `${e}`, 34 | headers: { 35 | 'Content-Type': 'text/plain; charset=utf-8', 36 | 'Access-Control-Allow-Origin': '*', 37 | 'Access-Control-Allow-Methods': 'POST,GET,OPTIONS,PUT,DELETE', 38 | 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept', 39 | }, 40 | }, 41 | } 42 | }) 43 | 44 | 45 | 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,a)=>{s.call(this,t,(t,s,r)=>{t?a(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("",`🔔${this.name}, 开始!`)}getEnv(){return"undefined"!=typeof $environment&&$environment["surge-version"]?"Surge":"undefined"!=typeof $environment&&$environment["stash-version"]?"Stash":"undefined"!=typeof module&&module.exports?"Node.js":"undefined"!=typeof $task?"Quantumult X":"undefined"!=typeof $loon?"Loon":"undefined"!=typeof $rocket?"Shadowrocket":void 0}isNode(){return"Node.js"===this.getEnv()}isQuanX(){return"Quantumult X"===this.getEnv()}isSurge(){return"Surge"===this.getEnv()}isLoon(){return"Loon"===this.getEnv()}isShadowrocket(){return"Shadowrocket"===this.getEnv()}isStash(){return"Stash"===this.getEnv()}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const a=this.getdata(t);if(a)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,a)=>e(a))})}runScript(t,e){return new Promise(s=>{let a=this.getdata("@chavy_boxjs_userCfgs.httpapi");a=a?a.replace(/\n/g,"").trim():a;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[i,o]=a.split("@"),n={url:`http://${o}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":i,Accept:"*/*"},timeout:r};this.post(n,(t,e,a)=>s(a))}).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),a=!s&&this.fs.existsSync(e);if(!s&&!a)return{};{const a=s?t:e;try{return JSON.parse(this.fs.readFileSync(a))}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),a=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):a?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const a=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of a)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,a)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[a+1])>>0==+e[a+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,a]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,a,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,a,r]=/^@(.*?)\.(.*?)$/.exec(e),i=this.getval(a),o=a?"null"===i?null:i||"{}":"{}";try{const e=JSON.parse(o);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),a)}catch(e){const i={};this.lodash_set(i,r,t),s=this.setval(JSON.stringify(i),a)}}else s=this.setval(t,e);return s}getval(t){switch(this.getEnv()){case"Surge":case"Loon":case"Stash":case"Shadowrocket":return $persistentStore.read(t);case"Quantumult X":return $prefs.valueForKey(t);case"Node.js":return this.data=this.loaddata(),this.data[t];default:return this.data&&this.data[t]||null}}setval(t,e){switch(this.getEnv()){case"Surge":case"Loon":case"Stash":case"Shadowrocket":return $persistentStore.write(t,e);case"Quantumult X":return $prefs.setValueForKey(t,e);case"Node.js":return this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0;default:return this.data&&this.data[e]||null}}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){switch(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"],delete t.headers["content-type"],delete t.headers["content-length"]),t.params&&(t.url+="?"+this.queryStr(t.params)),this.getEnv()){case"Surge":case"Loon":case"Stash":case"Shadowrocket":default:this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,a)=>{!t&&s&&(s.body=a,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,a)});break;case"Quantumult X":this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:a,headers:r,body:i,bodyBytes:o}=t;e(null,{status:s,statusCode:a,headers:r,body:i,bodyBytes:o},i,o)},t=>e(t&&t.error||"UndefinedError"));break;case"Node.js":let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:a,statusCode:r,headers:i,rawBody:o}=t,n=s.decode(o,this.encoding);e(null,{status:a,statusCode:r,headers:i,rawBody:o,body:n},n)},t=>{const{message:a,response:r}=t;e(a,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";switch(t.body&&t.headers&&!t.headers["Content-Type"]&&!t.headers["content-type"]&&(t.headers["content-type"]="application/x-www-form-urlencoded"),t.headers&&(delete t.headers["Content-Length"],delete t.headers["content-length"]),this.getEnv()){case"Surge":case"Loon":case"Stash":case"Shadowrocket":default:this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,a)=>{!t&&s&&(s.body=a,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,a)});break;case"Quantumult X":t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:a,headers:r,body:i,bodyBytes:o}=t;e(null,{status:s,statusCode:a,headers:r,body:i,bodyBytes:o},i,o)},t=>e(t&&t.error||"UndefinedError"));break;case"Node.js":let a=require("iconv-lite");this.initGotEnv(t);const{url:r,...i}=t;this.got[s](r,i).then(t=>{const{statusCode:s,statusCode:r,headers:i,rawBody:o}=t,n=a.decode(o,this.encoding);e(null,{status:s,statusCode:r,headers:i,rawBody:o,body:n},n)},t=>{const{message:s,response:r}=t;e(s,r,r&&a.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let a={"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 a)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?a[e]:("00"+a[e]).substr((""+a[e]).length)));return t}queryStr(t){let e="";for(const s in t){let a=t[s];null!=a&&""!==a&&("object"==typeof a&&(a=JSON.stringify(a)),e+=`${s}=${a}&`)}return e=e.substring(0,e.length-1),e}msg(e=t,s="",a="",r){const i=t=>{switch(typeof t){case void 0:return t;case"string":switch(this.getEnv()){case"Surge":case"Stash":default:return{url:t};case"Loon":case"Shadowrocket":return t;case"Quantumult X":return{"open-url":t};case"Node.js":return}case"object":switch(this.getEnv()){case"Surge":case"Stash":case"Shadowrocket":default:{let e=t.url||t.openUrl||t["open-url"];return{url:e}}case"Loon":{let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}case"Quantumult X":{let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,a=t["update-pasteboard"]||t.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":a}}case"Node.js":return}default:return}};if(!this.isMute)switch(this.getEnv()){case"Surge":case"Loon":case"Stash":case"Shadowrocket":default:$notification.post(e,s,a,i(r));break;case"Quantumult X":$notify(e,s,a,i(r));break;case"Node.js":}if(!this.isMuteLog){let t=["","==============📣系统通知📣=============="];t.push(e),s&&t.push(s),a&&t.push(a),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){switch(this.getEnv()){case"Surge":case"Loon":case"Stash":case"Shadowrocket":case"Quantumult X":default:this.log("",`❗️${this.name}, 错误!`,t);break;case"Node.js":this.log("",`❗️${this.name}, 错误!`,t.stack)}}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;switch(this.log("",`🔔${this.name}, 结束! 🕛 ${s} 秒`),this.log(),this.getEnv()){case"Surge":case"Loon":case"Stash":case"Shadowrocket":case"Quantumult X":default:$done(t);break;case"Node.js":process.exit(1)}}}(t,e)} 46 | -------------------------------------------------------------------------------- /scriptable/ShadowrocketModuleTool.js: -------------------------------------------------------------------------------- 1 | let ToolVersion = "1.97"; 2 | async function delay(milliseconds) { 3 | var before = Date.now(); 4 | while (Date.now() < before + milliseconds) {}; 5 | return true; 6 | } 7 | function convertToValidFileName(str) { 8 | // 替换非法字符为下划线 9 | const invalidCharsRegex = /[\/:*?"<>|]/g; 10 | const validFileName = str.replace(invalidCharsRegex, '_'); 11 | 12 | // 删除多余的点号 13 | const multipleDotsRegex = /\.{2,}/g; 14 | const fileNameWithoutMultipleDots = validFileName.replace(multipleDotsRegex, '.'); 15 | 16 | // 删除文件名开头和结尾的点号和空格 17 | const leadingTrailingDotsSpacesRegex = /^[\s.]+|[\s.]+$/g; 18 | const finalFileName = fileNameWithoutMultipleDots.replace(leadingTrailingDotsSpacesRegex, ''); 19 | 20 | return finalFileName; 21 | } 22 | 23 | 24 | 25 | let idx 26 | let fromUrlScheme 27 | let checkUpdate 28 | // if (args.queryParameters.url && args.queryParameters.name) { 29 | if (args.queryParameters.url) { 30 | fromUrlScheme = true 31 | } 32 | if (fromUrlScheme) { 33 | idx = 1 34 | } else { 35 | let alert = new Alert() 36 | alert.title = "Shadowrocket 模块工具" 37 | //alert.addDestructiveAction("更新文件夹内全部文件") 38 | alert.addDestructiveAction("更新本脚本") 39 | alert.addAction("从链接创建") 40 | alert.addAction("更新单个模块") 41 | alert.addAction("更新全部模块") 42 | alert.addCancelAction("取消") 43 | idx = await alert.presentAlert() 44 | } 45 | 46 | 47 | 48 | let folderPath 49 | let files = [] 50 | let contents = [] 51 | const fm = FileManager.iCloud() 52 | if (idx == 3) { 53 | folderPath = await DocumentPicker.openFolder() 54 | files = fm.listContents(folderPath) 55 | } else if (idx == 2) { 56 | const filePath = await DocumentPicker.openFile() 57 | folderPath = filePath.substring(0, filePath.lastIndexOf('/')) 58 | files = [filePath.substring(filePath.lastIndexOf('/')+1)] 59 | } else if (idx == 1) { 60 | let url 61 | let name 62 | if (fromUrlScheme) { 63 | url = args.queryParameters.url 64 | name = args.queryParameters.name 65 | } else { 66 | alert = new Alert() 67 | alert.title = '将自动添加后缀 .sgmodule' 68 | alert.addTextField('名称(选填)', '') 69 | alert.addTextField('链接(必填)', '') 70 | alert.addAction("下载") 71 | alert.addCancelAction("取消") 72 | await alert.presentAlert() 73 | url = alert.textFieldValue(1).replace(/target=[^&]+?-[^&]+/,"target=shadowrocket-module") 74 | name = alert.textFieldValue(0) 75 | console.log(url) 76 | } 77 | if (url) { 78 | if (!name) { 79 | const plainUrl = url.split('?')[0] 80 | const fullname = plainUrl.substring(plainUrl.lastIndexOf('/')+1) 81 | if (fullname) { 82 | name = fullname.replace(/\.sgmodule$/, '') 83 | } 84 | if (!name) { 85 | name = `untitled-${new Date().toLocaleString()}` 86 | } 87 | } 88 | name = convertToValidFileName(name) 89 | files = [`${name}.sgmodule`] 90 | contents = [`#!url=${url}`] 91 | } 92 | } else if (idx == 0) { 93 | console.log("检查更新") 94 | checkUpdate = true 95 | await update() 96 | } 97 | 98 | 99 | let report = { 100 | success: 0, 101 | fail: [], 102 | noUrl: 0 103 | } 104 | 105 | 106 | for await (const [index, file] of files.entries()) { 107 | if (file && !/\.(conf|txt|js|list)$/i.test(file)) { 108 | // console.log(file); 109 | let originalName 110 | let originalDesc 111 | let noUrl 112 | try { 113 | let content 114 | let filePath 115 | if (contents.length > 0) { 116 | content = contents[index] 117 | } else { 118 | filePath = `${folderPath}/${file}` 119 | content = fm.readString(filePath) 120 | 121 | } 122 | const originalNameMatched = `${content}`.match(/^#\!name\s*?=\s*(.*?)\s*(\n|$)/im) 123 | if (originalNameMatched) { 124 | originalName = originalNameMatched[1] 125 | } 126 | const originalDescMatched = `${content}`.match(/^#\!desc\s*?=\s*(.*?)\s*(\n|$)/im) 127 | if (originalDescMatched) { 128 | originalDesc = originalDescMatched[1] 129 | if (originalDesc) { 130 | originalDesc = originalDesc.replace(/^🔗.*?]\s*/i, '') 131 | } 132 | } 133 | const matched = `${content}`.match(/^(#SUBSCRIBED |#!url=)(.+)/im) 134 | if (!matched) { 135 | noUrl = true 136 | throw new Error('无订阅链接') 137 | } 138 | const subscribed = "#!url=" + matched[2]; 139 | const url = matched[2].replace(/target=[^&]+?-[^&]+/,"target=shadowrocket-module") 140 | if (!url) { 141 | noUrl = true 142 | throw new Error('无订阅链接') 143 | } 144 | 145 | 146 | 147 | const req = new Request(url); 148 | req.timeoutInterval = 10; 149 | req.method = 'GET'; 150 | let res = await req.loadString(); 151 | const statusCode = req.response.statusCode 152 | if (statusCode < 200 || statusCode >= 400) { 153 | throw new Error(`statusCode: ${statusCode}`) 154 | } 155 | if (!res) { 156 | throw new Error(`未获取到模块内容`) 157 | } 158 | 159 | const nameMatched = `${res}`.match(/^#\!name\s*?=\s*?\s*(.*?)\s*(\n|$)/im) 160 | if (!nameMatched) { 161 | throw new Error(`不是合法的模块内容`) 162 | } 163 | const name = nameMatched[1] 164 | if (!name) { 165 | throw new Error('模块无名称字段') 166 | } 167 | const descMatched = `${res}`.match(/^#\!desc\s*?=\s*?\s*(.*?)\s*(\n|$)/im) 168 | let desc 169 | if (descMatched) { 170 | desc = descMatched[1] 171 | } 172 | if (!desc) { 173 | res = `#!desc=\n${res}` 174 | } 175 | // console.log(res); 176 | res = `#!url=${url}\n` + res; 177 | content = `${res}`.replace(/^#!desc *= */mi, `#!desc=`).replace(/^#!name *= */mi, `#!name=🔗`) 178 | // console.log(content); 179 | if (filePath) { 180 | fm.writeString(filePath, content) 181 | } else { 182 | await DocumentPicker.exportString(content, file); 183 | } 184 | 185 | // } 186 | let nameInfo = `${name}` 187 | let descInfo = `${desc}` 188 | if (originalName && name !== originalName) { 189 | nameInfo = `${originalName} -> ${name}` 190 | } 191 | if (originalDesc && desc !== originalDesc) { 192 | descInfo = `${originalDesc} -> ${desc}` 193 | } 194 | console.log(`\n✅ ${nameInfo}\n${descInfo}\n${file}`); 195 | report.success += 1 196 | await delay(1 * 1000) 197 | if (fromUrlScheme) { 198 | alert = new Alert() 199 | alert.title = `✅ ${nameInfo}` 200 | alert.message = `${descInfo}\n${file}` 201 | alert.addAction("打开 Shadowrocket") 202 | alert.addCancelAction("关闭") 203 | idx = await alert.presentAlert() 204 | if (idx == 0) { 205 | const req = new Request('http://script.hub/reload'); 206 | req.timeoutInterval = 10; 207 | req.method = 'GET'; 208 | let res = await req.loadString(); 209 | } else if (idx == 1) { 210 | Safari.open('shadowrocket://') 211 | } 212 | } 213 | } catch (e) { 214 | if (noUrl) { 215 | report.noUrl += 1 216 | } else { 217 | report.fail.push(originalName||file) 218 | } 219 | 220 | 221 | 222 | if (noUrl) { 223 | console.log(`\n🈚️ ${originalName || ''}\n${file}`); 224 | console.log(e) 225 | } else { 226 | console.log(`\n❌ ${originalName || ''}\n${file}`); 227 | console.error(`${originalName || file}: ${e}`) 228 | } 229 | if (fromUrlScheme) { 230 | alert = new Alert() 231 | alert.title = `❌ ${originalName || ''}\n${file}` 232 | alert.message = `${e.message || e}` 233 | alert.addCancelAction("关闭") 234 | await alert.presentAlert() 235 | } 236 | } 237 | } 238 | } 239 | if (!checkUpdate && !fromUrlScheme) { 240 | alert = new Alert() 241 | alert.title = `📦 模块总数${report.success + report.fail.length + report.noUrl}` 242 | alert.message = `🈚️ 无链接: ${report.noUrl}\n✅ 更新成功: ${report.success}\n❌ 更新失败: ${report.fail.length}${report.fail.length > 0 ? `\n${report.fail.join(', ')}` : ''}` 243 | alert.addAction("打开 Shadowrocket") 244 | alert.addCancelAction("关闭") 245 | idx = await alert.presentAlert() 246 | if (idx == 0) { 247 | Safari.open('shadowrocket://') 248 | } 249 | } 250 | 251 | // @key Think @wuhu. 252 | async function update() { 253 | const fm = FileManager.iCloud() 254 | const dict = fm.documentsDirectory() 255 | // const scriptName = Script.name() 256 | const scriptName = "ShadowrocketModuleTool" 257 | let version 258 | let resp 259 | try { 260 | const url = "https://github.com/chengkongyiban/shadowrocket/raw/main/scriptable/ShadowrocketModuleTool.js?v="+Date.now() 261 | let req = new Request(url) 262 | req.method = "GET" 263 | req.headers = { 264 | 'Cache-Control': 'no-cache', 265 | Pragma: 'no-cache', 266 | } 267 | resp = await req.loadString() 268 | 269 | const regex = /let ToolVersion = "([\d.]+)"/ 270 | const match = resp.match(regex); 271 | version = (match ? match[1] : "") 272 | } catch (e) { 273 | console.error(e); 274 | } 275 | 276 | if (!version) { 277 | let alert = new Alert() 278 | alert.title = "Shadowrocket 模块工具" 279 | alert.message = "无法获取在线版本" 280 | alert.addCancelAction("关闭") 281 | await alert.presentAlert() 282 | return 283 | } else { 284 | let needUpdate = version > ToolVersion 285 | if (!needUpdate) { 286 | let alert = new Alert() 287 | alert.title = "Shadowrocket 模块工具" 288 | alert.message = `当前版本: ${ToolVersion}\n在线版本: ${version}\n无需更新` 289 | alert.addDestructiveAction("强制更新") 290 | alert.addCancelAction("关闭") 291 | idx = await alert.presentAlert() 292 | if (idx === 0) { 293 | needUpdate = true 294 | } 295 | } 296 | if (needUpdate) { 297 | fm.writeString(`${dict}/${scriptName}.js`, resp) 298 | console.log("更新成功: " + version) 299 | let notification = new Notification() 300 | notification.title = "Shadowrocket 模块工具 更新成功: " + version 301 | notification.subtitle = "点击通知跳转" 302 | notification.sound = "default" 303 | notification.openURL = `scriptable:///open/${scriptName}` 304 | notification.addAction("打开脚本", `scriptable:///open/${scriptName}`, false) 305 | await notification.schedule() 306 | } 307 | 308 | } 309 | 310 | } -------------------------------------------------------------------------------- /scripts/qx-resource-preview.js: -------------------------------------------------------------------------------- 1 | /************************* 2 | #!name=预览qx一键导入资源 3 | #!desc=将qx的一键导入链接复制到Safari打开可以预览 4 | 5 | [MITM] 6 | 7 | hostname = %APPEND% quantumult.app 8 | 9 | [rewrite_local] 10 | 11 | ^https:\/\/quantumult\.app\/x\/open-app\/add-resource\?remote-resource= url script-analyze-echo-response https://github.com/chengkongyiban/shadowrocket/raw/main/scripts/qx-resource-preview.js 12 | 13 | *************************/ 14 | const $ = new Env(`预览qx一键导入内容`) 15 | 16 | let qxSchemeUrl = decodeURIComponent($request.url); 17 | //$.log(qxSchemeUrl); 18 | let qxFilterUrl = []; 19 | let qxRewriteUrl = []; 20 | 21 | if (qxSchemeUrl.search(/"filter_remote"/) != -1){ 22 | let qxFilterObj = $.toObj(qxSchemeUrl.split("?remote-resource=")[1]).filter_remote; 23 | for (let i=0; i < qxFilterObj.length; i++) { 24 | const elem = qxFilterObj[i]; 25 | qxFilterUrl.push(qxFilterObj[i].split(",")[0]); 26 | };//循环结束 27 | }; 28 | 29 | if (qxSchemeUrl.search(/"rewrite_remote"/) != -1){ 30 | let qxRewriteObj = $.toObj(qxSchemeUrl.split("?remote-resource=")[1]).rewrite_remote; 31 | for (let i=0; i < qxRewriteObj.length; i++) { 32 | const elem = qxRewriteObj[i]; 33 | qxRewriteUrl.push(qxRewriteObj[i].split(",")[0]); 34 | };//循环结束 35 | }; 36 | 37 | qxFilterUrl = (qxFilterUrl[0] || '') && `分流链接:\n${qxFilterUrl.join("\n\n")}`; 38 | 39 | qxRewriteUrl = (qxRewriteUrl[0] || '') && `重写链接:\n${qxRewriteUrl.join("\n\n")}`; 40 | 41 | if (qxFilterUrl == [] && qxRewriteUrl == []){ 42 | qxRewriteUrl = "预览失败请将" + qxSchemeUrl + "反馈到https://t.me/zhangpeifu" 43 | }; 44 | 45 | body = `${qxFilterUrl} 46 | 47 | ${qxRewriteUrl}`.replace(/^\n*/i,``); 48 | 49 | let ret = {body:body ,headers: {'Content-Type': 'text/plain; charset=utf-8'}}; 50 | 51 | $done($.isQuanX() ? ret : {response: ret }); 52 | 53 | 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,a)=>{s.call(this,t,(t,s,r)=>{t?a(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("",`🔔${this.name}, 开始!`)}getEnv(){return"undefined"!=typeof $environment&&$environment["surge-version"]?"Surge":"undefined"!=typeof $environment&&$environment["stash-version"]?"Stash":"undefined"!=typeof module&&module.exports?"Node.js":"undefined"!=typeof $task?"Quantumult X":"undefined"!=typeof $loon?"Loon":"undefined"!=typeof $rocket?"Shadowrocket":void 0}isNode(){return"Node.js"===this.getEnv()}isQuanX(){return"Quantumult X"===this.getEnv()}isSurge(){return"Surge"===this.getEnv()}isLoon(){return"Loon"===this.getEnv()}isShadowrocket(){return"Shadowrocket"===this.getEnv()}isStash(){return"Stash"===this.getEnv()}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const a=this.getdata(t);if(a)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,a)=>e(a))})}runScript(t,e){return new Promise(s=>{let a=this.getdata("@chavy_boxjs_userCfgs.httpapi");a=a?a.replace(/\n/g,"").trim():a;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[i,o]=a.split("@"),n={url:`http://${o}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":i,Accept:"*/*"},timeout:r};this.post(n,(t,e,a)=>s(a))}).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),a=!s&&this.fs.existsSync(e);if(!s&&!a)return{};{const a=s?t:e;try{return JSON.parse(this.fs.readFileSync(a))}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),a=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):a?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const a=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of a)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,a)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[a+1])>>0==+e[a+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,a]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,a,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,a,r]=/^@(.*?)\.(.*?)$/.exec(e),i=this.getval(a),o=a?"null"===i?null:i||"{}":"{}";try{const e=JSON.parse(o);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),a)}catch(e){const i={};this.lodash_set(i,r,t),s=this.setval(JSON.stringify(i),a)}}else s=this.setval(t,e);return s}getval(t){switch(this.getEnv()){case"Surge":case"Loon":case"Stash":case"Shadowrocket":return $persistentStore.read(t);case"Quantumult X":return $prefs.valueForKey(t);case"Node.js":return this.data=this.loaddata(),this.data[t];default:return this.data&&this.data[t]||null}}setval(t,e){switch(this.getEnv()){case"Surge":case"Loon":case"Stash":case"Shadowrocket":return $persistentStore.write(t,e);case"Quantumult X":return $prefs.setValueForKey(t,e);case"Node.js":return this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0;default:return this.data&&this.data[e]||null}}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){switch(t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"],delete t.headers["content-type"],delete t.headers["content-length"]),t.params&&(t.url+="?"+this.queryStr(t.params)),this.getEnv()){case"Surge":case"Loon":case"Stash":case"Shadowrocket":default:this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,a)=>{!t&&s&&(s.body=a,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,a)});break;case"Quantumult X":this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:a,headers:r,body:i,bodyBytes:o}=t;e(null,{status:s,statusCode:a,headers:r,body:i,bodyBytes:o},i,o)},t=>e(t&&t.error||"UndefinedError"));break;case"Node.js":let s=require("iconv-lite");this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:a,statusCode:r,headers:i,rawBody:o}=t,n=s.decode(o,this.encoding);e(null,{status:a,statusCode:r,headers:i,rawBody:o,body:n},n)},t=>{const{message:a,response:r}=t;e(a,r,r&&s.decode(r.rawBody,this.encoding))})}}post(t,e=(()=>{})){const s=t.method?t.method.toLocaleLowerCase():"post";switch(t.body&&t.headers&&!t.headers["Content-Type"]&&!t.headers["content-type"]&&(t.headers["content-type"]="application/x-www-form-urlencoded"),t.headers&&(delete t.headers["Content-Length"],delete t.headers["content-length"]),this.getEnv()){case"Surge":case"Loon":case"Stash":case"Shadowrocket":default:this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient[s](t,(t,s,a)=>{!t&&s&&(s.body=a,s.statusCode=s.status?s.status:s.statusCode,s.status=s.statusCode),e(t,s,a)});break;case"Quantumult X":t.method=s,this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:a,headers:r,body:i,bodyBytes:o}=t;e(null,{status:s,statusCode:a,headers:r,body:i,bodyBytes:o},i,o)},t=>e(t&&t.error||"UndefinedError"));break;case"Node.js":let a=require("iconv-lite");this.initGotEnv(t);const{url:r,...i}=t;this.got[s](r,i).then(t=>{const{statusCode:s,statusCode:r,headers:i,rawBody:o}=t,n=a.decode(o,this.encoding);e(null,{status:s,statusCode:r,headers:i,rawBody:o,body:n},n)},t=>{const{message:s,response:r}=t;e(s,r,r&&a.decode(r.rawBody,this.encoding))})}}time(t,e=null){const s=e?new Date(e):new Date;let a={"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 a)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?a[e]:("00"+a[e]).substr((""+a[e]).length)));return t}queryStr(t){let e="";for(const s in t){let a=t[s];null!=a&&""!==a&&("object"==typeof a&&(a=JSON.stringify(a)),e+=`${s}=${a}&`)}return e=e.substring(0,e.length-1),e}msg(e=t,s="",a="",r){const i=t=>{switch(typeof t){case void 0:return t;case"string":switch(this.getEnv()){case"Surge":case"Stash":default:return{url:t};case"Loon":case"Shadowrocket":return t;case"Quantumult X":return{"open-url":t};case"Node.js":return}case"object":switch(this.getEnv()){case"Surge":case"Stash":case"Shadowrocket":default:{let e=t.url||t.openUrl||t["open-url"];return{url:e}}case"Loon":{let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}case"Quantumult X":{let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl,a=t["update-pasteboard"]||t.updatePasteboard;return{"open-url":e,"media-url":s,"update-pasteboard":a}}case"Node.js":return}default:return}};if(!this.isMute)switch(this.getEnv()){case"Surge":case"Loon":case"Stash":case"Shadowrocket":default:$notification.post(e,s,a,i(r));break;case"Quantumult X":$notify(e,s,a,i(r));break;case"Node.js":}if(!this.isMuteLog){let t=["","==============📣系统通知📣=============="];t.push(e),s&&t.push(s),a&&t.push(a),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){switch(this.getEnv()){case"Surge":case"Loon":case"Stash":case"Shadowrocket":case"Quantumult X":default:this.log("",`❗️${this.name}, 错误!`,t);break;case"Node.js":this.log("",`❗️${this.name}, 错误!`,t.stack)}}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;switch(this.log("",`🔔${this.name}, 结束! 🕛 ${s} 秒`),this.log(),this.getEnv()){case"Surge":case"Loon":case"Stash":case"Shadowrocket":case"Quantumult X":default:$done(t);break;case"Node.js":process.exit(1)}}}(t,e)} -------------------------------------------------------------------------------- /scripts/bilibili_cc.js: -------------------------------------------------------------------------------- 1 | /*********************************** 2 | 3 | > 应用名称:哔哩哔哩 4 | > 软件版本:7.1.0 5 | > 下载地址:https://apps.apple.com/cn/app/id736536022 6 | > 脚本作者:Cuttlefish 7 | > 微信账号:墨鱼手记 8 | > 更新时间:2022-11-01 9 | > 通知频道:https://t.me/ddgksf2021 10 | > 投稿助手:https://t.me/ddgksf2013_bot 11 | > 问题反馈:📮 ddgksf2013@163.com 📮 12 | > 特别说明:本脚本仅供学习交流使用,禁止转载售卖 13 | 14 | [rewrite_local] 15 | 16 | # ~ 嗶哩嗶哩繁体CC字幕转中文简体(2022-10-12)@ddgksf2013 17 | ^https?:\/\/i.\.hdslb\.com\/bfs\/subtitle\/.+\.json$ url script-response-body https://raw.githubusercontent.com/krisstibex/404Zone/main/Script/Bili%20Translate.js 18 | 19 | [mitm] 20 | 21 | hostname=i0.hdslb.com 22 | 23 | ***********************************/ 24 | 25 | var cuttlefish ={"warning":"本腳本僅供學習交流使用,禁止轉載售賣","tgchannel":"https://t.me/ddgksf2021","feedback":"ddgksf2013@163.com"}; 26 | 27 | var ddgksf2013 = JSON.parse($response.body); 28 | 29 | for (var i=0; i { 31 | let panel_result = { 32 | title: '流媒体解锁检测', 33 | content: '', 34 | icon: 'play.tv.fill', 35 | 'icon-color': '#FF2D55', 36 | } 37 | let [{ region, status }] = await Promise.all([testDisneyPlus()]) 38 | await Promise.all([check_youtube_premium(),check_netflix()]) 39 | .then((result) => { 40 | console.log(result) 41 | let disney_result="" 42 | if (status==STATUS_COMING) { 43 | //console.log(1) 44 | disney_result="Disney+: 即将登陆~"+region.toUpperCase() 45 | } else if (status==STATUS_AVAILABLE){ 46 | //console.log(2) 47 | console.log(region) 48 | disney_result="Disney+: 已解锁 ➟ "+region.toUpperCase() 49 | // console.log(result["Disney"]) 50 | } else if (status==STATUS_NOT_AVAILABLE) { 51 | //console.log(3) 52 | disney_result="Disney+: 未支持 🚫 " 53 | } else if (status==STATUS_TIMEOUT) { 54 | disney_result="Disney+: 检测超时 🚦" 55 | } 56 | result.push(disney_result) 57 | console.log(result) 58 | let content = result.join(' | ') 59 | console.log(content) 60 | 61 | let nodey = {"v":"2","ps":result[0],"add":"127.0.0.1","port":"443","type":"none","id":"76f77d6e-8839-44b9-9440-2a72457adce9","aid":"0","allowInsecure":"1","net":"ws","path":"/","host":"","tls":"tls"}; 62 | let noden = {"v":"2","ps":result[1],"add":"127.0.0.1","port":"443","type":"none","id":"76f77d6e-8839-44b9-9440-2a72457adce9","aid":"0","allowInsecure":"1","net":"ws","path":"/","host":"","tls":"tls"}; 63 | let noded = {"v":"2","ps":result[2],"add":"127.0.0.1","port":"443","type":"none","id":"76f77d6e-8839-44b9-9440-2a72457adce9","aid":"0","allowInsecure":"1","net":"ws","path":"/","host":"","tls":"tls"}; 64 | 65 | let streamTest = Base64.encode(`STATUS=${content}\nvmess://${Base64.encode(JSON.stringify(nodey))}\nvmess://${Base64.encode(JSON.stringify(noden))}\nvmess://${Base64.encode(JSON.stringify(noded))}`); 66 | 67 | 68 | $done({ response: { status: 200 ,body:streamTest ,headers: {'Content-Type': 'text/plain; charset=utf-8'} } }); 69 | 70 | panel_result['content'] = content 71 | }) 72 | .finally(() => { 73 | $done(panel_result) 74 | }) 75 | })() 76 | async function check_youtube_premium() { 77 | let inner_check = () => { 78 | return new Promise((resolve, reject) => { 79 | let option = { 80 | url: 'https://www.youtube.com/premium', 81 | headers: REQUEST_HEADERS, 82 | } 83 | $httpClient.get(option, function (error, response, data) { 84 | if (error != null || response.statusCode !== 200) { 85 | reject('Error') 86 | return 87 | } 88 | 89 | if (data.indexOf('Premium is not available in your country') !== -1) { 90 | resolve('Not Available') 91 | return 92 | } 93 | 94 | let region = '' 95 | let re = new RegExp('"countryCode":"(.*?)"', 'gm') 96 | let result = re.exec(data) 97 | if (result != null && result.length === 2) { 98 | region = result[1] 99 | } else if (data.indexOf('www.google.cn') !== -1) { 100 | region = 'CN' 101 | } else { 102 | region = 'US' 103 | } 104 | resolve(region) 105 | }) 106 | }) 107 | } 108 | 109 | let youtube_check_result = 'YouTube: ' 110 | 111 | await inner_check() 112 | .then((code) => { 113 | if (code === 'Not Available') { 114 | youtube_check_result += '不支持解锁' 115 | } else { 116 | youtube_check_result += '已解锁 ➟ ' + code.toUpperCase() 117 | } 118 | }) 119 | .catch((error) => { 120 | youtube_check_result += '检测失败,请刷新面板' 121 | }) 122 | 123 | return youtube_check_result 124 | } 125 | 126 | async function check_netflix() { 127 | let inner_check = (filmId) => { 128 | return new Promise((resolve, reject) => { 129 | let option = { 130 | url: 'https://www.netflix.com/title/' + filmId, 131 | headers: REQUEST_HEADERS, 132 | } 133 | $httpClient.get(option, function (error, response, data) { 134 | if (error != null) { 135 | reject('Error') 136 | return 137 | } 138 | 139 | if (response.statusCode === 403) { 140 | reject('Not Available') 141 | return 142 | } 143 | 144 | if (response.statusCode === 404) { 145 | resolve('Not Found') 146 | return 147 | } 148 | 149 | if (response.statusCode === 200) { 150 | let url = response.headers['x-originating-url'] 151 | let region = url.split('/')[3] 152 | region = region.split('-')[0] 153 | if (region == 'title') { 154 | region = 'us' 155 | } 156 | resolve(region) 157 | return 158 | } 159 | 160 | reject('Error') 161 | }) 162 | }) 163 | } 164 | 165 | let netflix_check_result = 'Netflix: ' 166 | 167 | await inner_check(80062035) 168 | .then((code) => { 169 | if (code === 'Not Found') { 170 | return inner_check(80018499) 171 | } 172 | netflix_check_result += '已完整解锁 ➟ ' + code.toUpperCase() 173 | return Promise.reject('BreakSignal') 174 | }) 175 | .then((code) => { 176 | if (code === 'Not Found') { 177 | return Promise.reject('Not Available') 178 | } 179 | 180 | netflix_check_result += '仅解锁自制剧 ➟ ' + code.toUpperCase() 181 | return Promise.reject('BreakSignal') 182 | }) 183 | .catch((error) => { 184 | if (error === 'BreakSignal') { 185 | return 186 | } 187 | if (error === 'Not Available') { 188 | netflix_check_result += '该节点不支持解锁' 189 | return 190 | } 191 | netflix_check_result += '检测失败,请刷新面板' 192 | }) 193 | 194 | return netflix_check_result 195 | } 196 | 197 | async function testDisneyPlus() { 198 | try { 199 | let { region, cnbl } = await Promise.race([testHomePage(), timeout(7000)]) 200 | console.log(`homepage: region=${region}, cnbl=${cnbl}`) 201 | // 即将登陆 202 | // if (cnbl == 2) { 203 | // return { region, status: STATUS_COMING } 204 | // } 205 | let { countryCode, inSupportedLocation } = await Promise.race([getLocationInfo(), timeout(7000)]) 206 | console.log(`getLocationInfo: countryCode=${countryCode}, inSupportedLocation=${inSupportedLocation}`) 207 | 208 | region = countryCode ?? region 209 | console.log( "region:"+region) 210 | // 即将登陆 211 | if (inSupportedLocation === false || inSupportedLocation === 'false') { 212 | return { region, status: STATUS_COMING } 213 | } else { 214 | // 支持解锁 215 | return { region, status: STATUS_AVAILABLE } 216 | } 217 | 218 | } catch (error) { 219 | console.log("error:"+error) 220 | 221 | // 不支持解锁 222 | if (error === 'Not Available') { 223 | console.log("不支持") 224 | return { status: STATUS_NOT_AVAILABLE } 225 | } 226 | 227 | // 检测超时 228 | if (error === 'Timeout') { 229 | return { status: STATUS_TIMEOUT } 230 | } 231 | 232 | return { status: STATUS_ERROR } 233 | } 234 | 235 | } 236 | 237 | function getLocationInfo() { 238 | return new Promise((resolve, reject) => { 239 | let opts = { 240 | url: 'https://disney.api.edge.bamgrid.com/graph/v1/device/graphql', 241 | headers: { 242 | 'Accept-Language': 'en', 243 | Authorization: 'ZGlzbmV5JmJyb3dzZXImMS4wLjA.Cu56AgSfBTDag5NiRA81oLHkDZfu5L3CKadnefEAY84', 244 | 'Content-Type': 'application/json', 245 | 'User-Agent': UA, 246 | }, 247 | body: JSON.stringify({ 248 | query: 'mutation registerDevice($input: RegisterDeviceInput!) { registerDevice(registerDevice: $input) { grant { grantType assertion } } }', 249 | variables: { 250 | input: { 251 | applicationRuntime: 'chrome', 252 | attributes: { 253 | browserName: 'chrome', 254 | browserVersion: '94.0.4606', 255 | manufacturer: 'apple', 256 | model: null, 257 | operatingSystem: 'macintosh', 258 | operatingSystemVersion: '10.15.7', 259 | osDeviceIds: [], 260 | }, 261 | deviceFamily: 'browser', 262 | deviceLanguage: 'en', 263 | deviceProfile: 'macosx', 264 | }, 265 | }, 266 | }), 267 | } 268 | 269 | $httpClient.post(opts, function (error, response, data) { 270 | if (error) { 271 | reject('Error') 272 | return 273 | } 274 | 275 | if (response.statusCode !== 200) { 276 | console.log('getLocationInfo: ' + data) 277 | reject('Not Available') 278 | return 279 | } 280 | 281 | data = JSON.parse(data) 282 | if(data?.errors){ 283 | console.log('getLocationInfo: ' + data) 284 | reject('Not Available') 285 | return 286 | } 287 | 288 | let { 289 | token: { accessToken }, 290 | session: { 291 | inSupportedLocation, 292 | location: { countryCode }, 293 | }, 294 | } = data?.extensions?.sdk 295 | resolve({ inSupportedLocation, countryCode, accessToken }) 296 | }) 297 | }) 298 | } 299 | 300 | function testHomePage() { 301 | return new Promise((resolve, reject) => { 302 | let opts = { 303 | url: 'https://www.disneyplus.com/', 304 | headers: { 305 | 'Accept-Language': 'en', 306 | 'User-Agent': UA, 307 | }, 308 | } 309 | 310 | $httpClient.get(opts, function (error, response, data) { 311 | if (error) { 312 | reject('Error') 313 | return 314 | } 315 | if (response.statusCode !== 200 || data.indexOf('Sorry, Disney+ is not available in your region.') !== -1) { 316 | reject('Not Available') 317 | return 318 | } 319 | 320 | let match = data.match(/Region: ([A-Za-z]{2})[\s\S]*?CNBL: ([12])/) 321 | if (!match) { 322 | resolve({ region: '', cnbl: '' }) 323 | return 324 | } 325 | 326 | let region = match[1] 327 | let cnbl = match[2] 328 | resolve({ region, cnbl }) 329 | }) 330 | }) 331 | } 332 | 333 | 334 | function timeout(delay = 5000) { 335 | return new Promise((resolve, reject) => { 336 | setTimeout(() => { 337 | reject('Timeout') 338 | }, delay) 339 | }) 340 | } 341 | 342 | //Base64编码工具 343 | function Base64Code() { 344 | // constants 345 | var b64chars 346 | = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; 347 | var b64tab = function (bin) { 348 | var t = {}; 349 | for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i; 350 | return t; 351 | }(b64chars); 352 | var fromCharCode = String.fromCharCode; 353 | // encoder stuff 354 | var cb_utob = function (c) { 355 | if (c.length < 2) { 356 | var cc = c.charCodeAt(0); 357 | return cc < 0x80 ? c 358 | : cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6)) 359 | + fromCharCode(0x80 | (cc & 0x3f))) 360 | : (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) 361 | + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) 362 | + fromCharCode(0x80 | (cc & 0x3f))); 363 | } else { 364 | var cc = 0x10000 365 | + (c.charCodeAt(0) - 0xD800) * 0x400 366 | + (c.charCodeAt(1) - 0xDC00); 367 | return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07)) 368 | + fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) 369 | + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) 370 | + fromCharCode(0x80 | (cc & 0x3f))); 371 | } 372 | }; 373 | var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g; 374 | var utob = function (u) { 375 | return u.replace(re_utob, cb_utob); 376 | }; 377 | var cb_encode = function (ccc) { 378 | var padlen = [0, 2, 1][ccc.length % 3], 379 | ord = ccc.charCodeAt(0) << 16 380 | | ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8) 381 | | ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)), 382 | chars = [ 383 | b64chars.charAt(ord >>> 18), 384 | b64chars.charAt((ord >>> 12) & 63), 385 | padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63), 386 | padlen >= 1 ? '=' : b64chars.charAt(ord & 63) 387 | ]; 388 | return chars.join(''); 389 | }; 390 | var btoa = function (b) { 391 | return b.replace(/[\s\S]{1,3}/g, cb_encode); 392 | }; 393 | // var _encode = function(u) { 394 | // var isUint8Array = Object.prototype.toString.call(u) === '[object Uint8Array]'; 395 | // return isUint8Array ? u.toString('base64') 396 | // : btoa(utob(String(u))); 397 | // } 398 | this.encode = function (u) { 399 | var isUint8Array = Object.prototype.toString.call(u) === '[object Uint8Array]'; 400 | return isUint8Array ? u.toString('base64') 401 | : btoa(utob(String(u))); 402 | } 403 | var uriencode = function (u, urisafe) { 404 | return !urisafe 405 | ? _encode(u) 406 | : _encode(String(u)).replace(/[+\/]/g, function (m0) { 407 | return m0 == '+' ? '-' : '_'; 408 | }).replace(/=/g, ''); 409 | }; 410 | var encodeURI = function (u) { return uriencode(u, true) }; 411 | // decoder stuff 412 | var re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g; 413 | var cb_btou = function (cccc) { 414 | switch (cccc.length) { 415 | case 4: 416 | var cp = ((0x07 & cccc.charCodeAt(0)) << 18) 417 | | ((0x3f & cccc.charCodeAt(1)) << 12) 418 | | ((0x3f & cccc.charCodeAt(2)) << 6) 419 | | (0x3f & cccc.charCodeAt(3)), 420 | offset = cp - 0x10000; 421 | return (fromCharCode((offset >>> 10) + 0xD800) 422 | + fromCharCode((offset & 0x3FF) + 0xDC00)); 423 | case 3: 424 | return fromCharCode( 425 | ((0x0f & cccc.charCodeAt(0)) << 12) 426 | | ((0x3f & cccc.charCodeAt(1)) << 6) 427 | | (0x3f & cccc.charCodeAt(2)) 428 | ); 429 | default: 430 | return fromCharCode( 431 | ((0x1f & cccc.charCodeAt(0)) << 6) 432 | | (0x3f & cccc.charCodeAt(1)) 433 | ); 434 | } 435 | }; 436 | var btou = function (b) { 437 | return b.replace(re_btou, cb_btou); 438 | }; 439 | var cb_decode = function (cccc) { 440 | var len = cccc.length, 441 | padlen = len % 4, 442 | n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0) 443 | | (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0) 444 | | (len > 2 ? b64tab[cccc.charAt(2)] << 6 : 0) 445 | | (len > 3 ? b64tab[cccc.charAt(3)] : 0), 446 | chars = [ 447 | fromCharCode(n >>> 16), 448 | fromCharCode((n >>> 8) & 0xff), 449 | fromCharCode(n & 0xff) 450 | ]; 451 | chars.length -= [0, 0, 2, 1][padlen]; 452 | return chars.join(''); 453 | }; 454 | var _atob = function (a) { 455 | return a.replace(/\S{1,4}/g, cb_decode); 456 | }; 457 | var atob = function (a) { 458 | return _atob(String(a).replace(/[^A-Za-z0-9\+\/]/g, '')); 459 | }; 460 | // var _decode = buffer ? 461 | // buffer.from && Uint8Array && buffer.from !== Uint8Array.from 462 | // ? function(a) { 463 | // return (a.constructor === buffer.constructor 464 | // ? a : buffer.from(a, 'base64')).toString(); 465 | // } 466 | // : function(a) { 467 | // return (a.constructor === buffer.constructor 468 | // ? a : new buffer(a, 'base64')).toString(); 469 | // } 470 | // : function(a) { return btou(_atob(a)) }; 471 | var _decode = function (u) { 472 | return btou(_atob(u)) 473 | } 474 | this.decode = function (a) { 475 | return _decode( 476 | String(a).replace(/[-_]/g, function (m0) { return m0 == '-' ? '+' : '/' }) 477 | .replace(/[^A-Za-z0-9\+\/]/g, '') 478 | ).replace(/>/g, ">").replace(/</g, "<"); 479 | }; 480 | } -------------------------------------------------------------------------------- /scripts/HifiniSign.js: -------------------------------------------------------------------------------- 1 | /* 2 | hifini签到-lowking-v1.0 3 | 4 | 按下面配置完之后,打开https://www.hifini.com/my.htm获取cookie 5 | 6 | hostname = *.hifini.com 7 | 8 | ************************ 9 | Surge 4.2.0+ 脚本配置: 10 | ************************ 11 | [Script] 12 | # > hifini签到 13 | hifini签到cookie = type=http-request,pattern=https:\/\/www.hifini.com\/my.htm,script-path=https://raw.githubusercontent.com/lowking/Scripts/master/hifini/hifiniSign.js 14 | hifini签到 = type=cron,cronexp="0 10 0 * * ?",wake-system=1,script-path=https://raw.githubusercontent.com/lowking/Scripts/master/hifini/hifiniSign.js 15 | 16 | 17 | ************************ 18 | QuantumultX 本地脚本配置: 19 | ************************ 20 | [rewrite_local] 21 | #hifini签到cookie 22 | https:\/\/www.hifini.com\/my.htm url script-request-header https://raw.githubusercontent.com/lowking/Scripts/master/hifini/hifiniSign.js 23 | 24 | [task_local] 25 | 0 10 0 * * ? https://raw.githubusercontent.com/lowking/Scripts/master/hifini/hifiniSign.js 26 | 27 | 28 | ************************ 29 | LOON 本地脚本配置: 30 | ************************ 31 | 32 | [Script] 33 | http-request https:\/\/www.hifini.com\/my.htm script-path=https://raw.githubusercontent.com/lowking/Scripts/master/hifini/hifiniSign.js, timeout=10, tag=hifini签到cookie 34 | cron "0 10 0 * * ?" script-path=https://raw.githubusercontent.com/lowking/Scripts/master/hifini/hifiniSign.js, tag=hifini签到 35 | 36 | */ 37 | 38 | const lk = new ToolKit(`hifini签到`, `HifiniSignIn`) 39 | const hifiniCookieKey = 'lkHifiniCookieKey' 40 | const hifiniIsTakeTheFirst = 'lkHifiniIsTakeTheFirst' 41 | const hifiniTakeTheFirstCount = 'lkHifiniTakeTheFirstCount' 42 | const hifiniRunType = 'lkHifiniRunType' 43 | const hifiniSec = 'lkHifiniSec' 44 | const hifiniMsec = 'lkHifiniMsec' 45 | const timeIntervalKey = 'lkHifiniTimeInterval' 46 | const hifiniCookie = !lk.getVal(hifiniCookieKey) ? '' : lk.getVal(hifiniCookieKey) 47 | const isTakeTheFirst = !lk.getVal(hifiniIsTakeTheFirst) ? false : JSON.parse(lk.getVal(hifiniIsTakeTheFirst)) 48 | const takeTheFirstCount = !lk.getVal(hifiniTakeTheFirstCount) ? 20 : lk.getVal(hifiniTakeTheFirstCount) 49 | const runType = !lk.getVal(hifiniRunType) ? "1" : lk.getVal(hifiniRunType) 50 | const sec = !lk.getVal(hifiniSec) ? 59 : lk.getVal(hifiniSec) 51 | const msec = !lk.getVal(hifiniMsec) ? 0 : lk.getVal(hifiniMsec) 52 | const timeInterval = !lk.getVal(timeIntervalKey) ? 100 : lk.getVal(timeIntervalKey) 53 | 54 | if (!lk.isExecComm) { 55 | if (lk.isRequest()) { 56 | getCookie() 57 | lk.done() 58 | } else { 59 | // 构建boxjs数据写入订阅 60 | lk.boxJsJsonBuilder({ 61 | "icons": [ 62 | "https://raw.githubusercontent.com/lowking/Scripts/master/doc/icon/hifinisignin-dark.png", 63 | "https://raw.githubusercontent.com/lowking/Scripts/master/doc/icon/hifinisignin.png" 64 | ], 65 | "settings": [ 66 | { 67 | "id": hifiniCookieKey, 68 | "name": "hifini cookie", 69 | "val": "", 70 | "type": "text", 71 | "desc": "hifini cookie" 72 | }, { 73 | "id": hifiniIsTakeTheFirst, 74 | "name": "是否抢签到第一", 75 | "val": false, 76 | "type": "boolean", 77 | "desc": "默认关闭" 78 | }, { 79 | "id": hifiniTakeTheFirstCount, 80 | "name": "抢签到第一并发数", 81 | "val": 20, 82 | "type": "number", 83 | "desc": "默认20" 84 | }, { 85 | "id": hifiniSec, 86 | "name": "抢签到等待至xx秒", 87 | "val": 59, 88 | "type": "number", 89 | "desc": "默认59s" 90 | }, { 91 | "id": hifiniMsec, 92 | "name": "抢签到等待至xxx毫秒", 93 | "val": 0, 94 | "type": "number", 95 | "desc": "默认0ms" 96 | }, { 97 | "id": timeIntervalKey, 98 | "name": "设定固定时间间隔", 99 | "val": 100, 100 | "type": "number", 101 | "desc": "默认100ms" 102 | }, { 103 | "id": hifiniRunType, 104 | "name": "运行脚本方式", 105 | "val": "1", 106 | "type": "radios", 107 | "items": [ 108 | { 109 | "key": "1", 110 | "label": "并发执行" 111 | }, 112 | { 113 | "key": "2", 114 | "label": "顺序执行" 115 | }, 116 | { 117 | "key": "3", 118 | "label": "固定时间间隔顺序执行" 119 | } 120 | ], 121 | "desc": "默认并发执行" 122 | } 123 | ], 124 | "keys": [hifiniCookieKey] 125 | }, { 126 | "script_url": "https://github.com/lowking/Scripts/blob/master/hifini/hifiniSign.js", 127 | "author": "@lowking", 128 | "repo": "https://github.com/lowking/Scripts", 129 | }) 130 | all() 131 | } 132 | } 133 | 134 | function getCookie() { 135 | if (lk.isGetCookie(/\/my.htm/)) { 136 | if ($request.headers.hasOwnProperty('Cookie')) { 137 | lk.setVal(hifiniCookieKey, $request.headers.Cookie) 138 | lk.appendNotifyInfo('🎉成功获取hifini签到cookie,可以关闭相应脚本') 139 | } else { 140 | lk.appendNotifyInfo('❌获取hifini签到cookie失败') 141 | } 142 | lk.msg('') 143 | } 144 | } 145 | 146 | async function all() { 147 | if (hifiniCookie == '') { 148 | lk.execFail() 149 | lk.appendNotifyInfo(`⚠️请先先根据脚本注释获取cookie`) 150 | } else { 151 | let now = new Date() 152 | if (isTakeTheFirst && now.getHours() == 23) { 153 | // 如果时间是23点,就等待0点的时候再继续 154 | if (now.getMinutes() > 57) { 155 | while (1) { 156 | if (now.getHours() != 23 || (now.getSeconds() >= sec && now.getMilliseconds() >= msec)) { 157 | lk.log("跳出等待") 158 | break 159 | } 160 | lk.log("等待中。。。") 161 | await lk.sleep(100) 162 | now = new Date() 163 | } 164 | } 165 | let execArr = [] 166 | // 尝试同时请求20次,抢签到第一 167 | for (let i = 0; i < takeTheFirstCount; i++) { 168 | if (runType == "1") { 169 | // 并发执行 170 | execArr.push(signIn()) 171 | } else if (runType == "2") { 172 | // 顺序执行 173 | let res = await signIn() 174 | if (res.indexOf("suc") > -1) { 175 | lk.execStatus = true 176 | lk.appendNotifyInfo([res.substring(3)], 1) 177 | break 178 | } 179 | } else if (runType == "3") { 180 | // 固定间隔时间执行 181 | let finalTimeInterval = timeInterval * i 182 | execArr.push(new Promise((resolve, reject) => { 183 | setTimeout(async function () { 184 | resolve(await signIn()) 185 | }, finalTimeInterval) 186 | })) 187 | } 188 | } 189 | if (runType == "1" || runType == "3") { 190 | await Promise.all(execArr).then(async (res) => { 191 | console.log(`${res}`) 192 | let sucList = res.filter(str => { 193 | return str !== undefined && str.indexOf("suc") != -1 194 | }) 195 | // 只要有一个成功,就算成功 196 | if (sucList.length >= 1) { 197 | lk.execStatus = true 198 | // 获取返回排名最靠前的 199 | const regExp = new RegExp("排名(\\d+)", '') 200 | let m 201 | let min = 9999999 202 | let minStr = sucList[0].substring(3) 203 | sucList.forEach((info) => { 204 | if ((m = regExp.exec(info + "")) !== null) { 205 | let number = Number(m[1]) 206 | if (number < min) { 207 | min = number 208 | minStr = info.substring(3) 209 | } 210 | } 211 | }) 212 | lk.appendNotifyInfo([minStr], 1) 213 | } else { 214 | lk.execFail() 215 | } 216 | }) 217 | } 218 | } else { 219 | await signIn() 220 | } 221 | } 222 | lk.msg(``) 223 | lk.done() 224 | } 225 | 226 | function signIn() { 227 | return new Promise((resolve, reject) => { 228 | lk.log("开始签到") 229 | const t = '签到' 230 | let url = { 231 | url: 'https://www.hifini.com/sg_sign.htm', 232 | headers: { 233 | cookie: hifiniCookie, 234 | "User-Agent": lk.userAgent 235 | } 236 | } 237 | lk.post(url, (error, response, data) => { 238 | try { 239 | if (error) { 240 | lk.execFail() 241 | lk.appendNotifyInfo(`❌${t}失败,请稍后再试`) 242 | } else { 243 | let msg = data.split(`

`)[1].split(``)[1].split("<")[0] 244 | if (msg) { 245 | lk.appendNotifyInfo(`🎉${msg.trim()}`) 246 | lk.log(msg.trim()) 247 | resolve(`suc🎉${msg.trim()}`) 248 | } else { 249 | lk.execFail() 250 | lk.appendNotifyInfo(data) 251 | } 252 | } 253 | } catch (e) { 254 | lk.logErr(e) 255 | lk.log(`返回数据:${data}`) 256 | lk.execFail() 257 | lk.appendNotifyInfo(`❌${t}错误,请带上日志联系作者,或稍后再试`) 258 | resolve(`fail`) 259 | } finally { 260 | resolve() 261 | } 262 | }) 263 | }) 264 | } 265 | 266 | //ToolKit-start 267 | 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.startTime=(new Date).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()){if(!this.isJsonObject(t)||!this.isJsonObject(s)){this.log("构建BoxJsJson传入参数格式错误,请传入json对象");return}this.log("using node");let i=["settings","keys"];const e="https://raw.githubusercontent.com/Orz-3";let o={};let h="#lk{script_url}";if(s&&s.hasOwnProperty("script_url")){h=this.isEmpty(s["script_url"])?"#lk{script_url}":s["script_url"]}o.id=`${this.prefix}${this.id}`;o.name=this.name;o.desc_html=`⚠️使用说明
详情【点我查看】`;o.icons=[`${e}/mini/master/Alpha/${this.id.toLocaleLowerCase()}.png`,`${e}/mini/master/Color/${this.id.toLocaleLowerCase()}.png`];o.keys=[];o.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="}];o.author="#lk{author}";o.repo="#lk{repo}";o.script=`${h}?raw=true`;if(!this.isEmpty(t)){for(let s in i){let e=i[s];if(!this.isEmpty(t[e])){if(e==="settings"){for(let s=0;s0){let t=a.apps;let i=t.indexOf(t.filter(t=>{return t.id==o.id})[0]);if(i>=0){a.apps[i]=o}else{a.apps.push(o)}let e=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"}e=e.replace(`#lk{${t}}`,i)}}const h=/(?:#lk\{)(.+?)(?=\})/;let r=h.exec(e);if(r!==null){this.log(`生成BoxJs还有未配置的参数,请参考https://github.com/lowking/Scripts/blob/master/util/example/ToolKitDemo.js#L17-L18传入参数:\n`)}let l=new Set;while((r=h.exec(e))!==null){l.add(r[1]);e=e.replace(`#lk{${r[1]}}`,``)}l.forEach(t=>{console.log(`${t} `)});this.fs.writeFileSync(n,e)}}}}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()){if(h)o["url"]=i;$notification.post(this.name,t,s,o)}if(this.isNode())this.log("⭐️"+this.name+t+s);if(this.isJSBox())$push.schedule({title:this.name,body:t?t+"\n"+s:s})}}}}getVal(t){if(this.isSurge()||this.isLoon()){return $persistentStore.read(t)}else if(this.isQuanX()){return $prefs.valueForKey(t)}else if(this.isNode()){this.data=this.loadData();return this.data[t]}else{return this.data&&this.data[t]||null}}setVal(t,s){if(this.isSurge()||this.isLoon()){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())$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()){$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()){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()){$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/g) 266 | 267 | if (url.match(/&kind=asr/)) { 268 | body = body.replace(/<\/?s[^>]*>/g, "") 269 | data = data.replace(/<\/?s[^>]*>/g, "") 270 | timeline = body.match(/

]+>/g) 271 | } 272 | 273 | for (var i in timeline) { 274 | let patt = new RegExp(`${timeline[i]}([^<]+)<\\/p>`) 275 | if (body.match(patt) && data.match(patt)) { 276 | if (setting.line == "s") body = body.replace(patt, `${timeline[i]}$1\n${data.match(patt)[1]}

`) 277 | if (setting.line == "f") body = body.replace(patt, `${timeline[i]}${data.match(patt)[1]}\n$1

`) 278 | } 279 | } 280 | 281 | $done({ body }) 282 | 283 | }) 284 | 285 | } 286 | 287 | let subtitles_urls_data = setting.t_subtitles_url 288 | 289 | if (setting.type == "Official" && url.match(/\.m3u8/)) { 290 | settings[service].t_subtitles_url = "null" 291 | $persistentStore.write(JSON.stringify(settings)) 292 | 293 | let patt = new RegExp(`TYPE=SUBTITLES.+NAME="${setting.tl.replace(/(\[|\]|\(|\))/g, "\\$1")}.+URI="([^"]+)`) 294 | 295 | if (body.match(patt)) { 296 | 297 | let host = "" 298 | if (service == "Disney") host = url.match(/https.+media.(dss|star)ott.com\/ps01\/disney\/[^\/]+\//)[0] 299 | 300 | let subtitles_data_link = `${host}${body.match(patt)[1]}` 301 | 302 | if (service == "PrimeVideo") { 303 | correct_host = subtitles_data_link.match(/https:\/\/(.+(cloudfront|akamaihd|avi-cdn).net)/)[1] 304 | headers.Host = correct_host 305 | } 306 | 307 | let options = { 308 | url: subtitles_data_link, 309 | headers: headers 310 | } 311 | 312 | $httpClient.get(options, function (error, response, data) { 313 | let subtitles_data = "" 314 | if (service == "Disney") subtitles_data = data.match(/.+-MAIN.+\.vtt/g) 315 | if (service == "HBOMax") subtitles_data = data.match(/http.+\.vtt/g) 316 | if (service == "PrimeVideo") subtitles_data = data.match(/.+\.vtt/g) 317 | 318 | if (service == "Disney") host = host + "r/" 319 | if (service == "PrimeVideo") host = subtitles_data_link.match(/https.+\//)[0] 320 | 321 | if (subtitles_data) { 322 | subtitles_data = subtitles_data.join("\n") 323 | if (service == "Disney" || service == "PrimeVideo") subtitles_data = subtitles_data.replace(/(.+)/g, `${host}$1`) 324 | settings[service].t_subtitles_url = subtitles_data 325 | $persistentStore.write(JSON.stringify(settings)) 326 | } 327 | 328 | if (service == "Disney" && subtitles_data_link.match(/.+-MAIN.+/) && data.match(/,\nseg.+\.vtt/g)) { 329 | subtitles_data = data.match(/,\nseg.+\.vtt/g) 330 | let url_path = subtitles_data_link.match(/\/r\/(.+)/)[1].replace(/\w+\.m3u8/, "") 331 | settings[service].t_subtitles_url = subtitles_data.join("\n").replace(/,\n/g, hots + url_path) 332 | $persistentStore.write(JSON.stringify(settings)) 333 | } 334 | 335 | $done({}) 336 | }) 337 | 338 | } 339 | 340 | if (!body.match(patt)) $done({}) 341 | } 342 | 343 | if (url.match(/\.(web)?vtt/) || service == "Netflix" || service == "General") { 344 | if (service != "Netflix" && url == setting.s_subtitles_url && setting.subtitles != "null" && setting.subtitles_type == setting.type && setting.subtitles_sl == setting.sl && setting.subtitles_tl == setting.tl && setting.subtitles_line == setting.line) $done({ body: setting.subtitles }) 345 | 346 | if (setting.type == "Official") { 347 | if (subtitles_urls_data == "null") $done({}) 348 | subtitles_urls_data = subtitles_urls_data.match(/.+\.vtt/g) 349 | if (subtitles_urls_data) official_subtitles(subtitles_urls_data) 350 | } 351 | 352 | if (setting.type == "Google") machine_subtitles("Google") 353 | 354 | if (setting.type == "DeepL") machine_subtitles("DeepL") 355 | 356 | if (setting.type == "External") external_subtitles() 357 | } 358 | 359 | function external_subtitles() { 360 | let patt = new RegExp(`(\\d+\\n)*\\d+:\\d\\d:\\d\\d.\\d\\d\\d --> \\d+:\\d\\d:\\d\\d.\\d.+(\\n|.)+`) 361 | if (!setting.external_subtitles.match(patt)) $done({}) 362 | if (!body.match(patt)) $done({}) 363 | let external = setting.external_subtitles.replace(/(\d+:\d\d:\d\d),(\d\d\d)/g, "$1.$2") 364 | body = body.replace(patt, external.match(patt)[0]) 365 | $done({ body }) 366 | } 367 | 368 | async function machine_subtitles(type) { 369 | 370 | body = body.replace(/\r/g, "") 371 | body = body.replace(/(\d+:\d\d:\d\d.\d\d\d --> \d+:\d\d:\d\d.\d.+\n.+)\n(.+)/g, "$1 $2") 372 | body = body.replace(/(\d+:\d\d:\d\d.\d\d\d --> \d+:\d\d:\d\d.\d.+\n.+)\n(.+)/g, "$1 $2") 373 | 374 | let dialogue = body.match(/\d+:\d\d:\d\d.\d\d\d --> \d+:\d\d:\d\d.\d.+\n.+/g) 375 | 376 | if (!dialogue) $done({}) 377 | 378 | let timeline = body.match(/\d+:\d\d:\d\d.\d\d\d --> \d+:\d\d:\d\d.\d.+/g) 379 | 380 | let s_sentences = [] 381 | for (var i in dialogue) { 382 | s_sentences.push(`${type == "Google" ? "~" + i + "~" : "&text="}${dialogue[i].replace(/<\/*(c\.[^>]+|i|c)>/g, "").replace(/\d+:\d\d:\d\d.\d\d\d --> \d+:\d\d:\d\d.\d.+\n/, "")}`) 383 | } 384 | s_sentences = groupAgain(s_sentences, type == "Google" ? 80 : 50) 385 | 386 | let t_sentences = [] 387 | let trans_result = [] 388 | 389 | if (type == "Google") { 390 | for (var p in s_sentences) { 391 | let options = { 392 | url: `https://translate.google.com/translate_a/single?client=it&dt=qca&dt=t&dt=rmt&dt=bd&dt=rms&dt=sos&dt=md&dt=gt&dt=ld&dt=ss&dt=ex&otf=2&dj=1&hl=en&ie=UTF-8&oe=UTF-8&sl=${setting.sl}&tl=${setting.tl}`, 393 | headers: { 394 | "User-Agent": "GoogleTranslate/6.29.59279 (iPhone; iOS 15.4; en; iPhone14,2)" 395 | }, 396 | body: `q=${encodeURIComponent(s_sentences[p].join("\n"))}` 397 | } 398 | 399 | let trans = await send_request(options, "post") 400 | 401 | if (trans.sentences) { 402 | let sentences = trans.sentences 403 | for (var k in sentences) { 404 | if (sentences[k].trans) trans_result.push(sentences[k].trans.replace(/\n$/g, "").replace(/\n/g, " ").replace(/〜|~/g, "~")) 405 | } 406 | } 407 | } 408 | 409 | if (trans_result.length > 0) { 410 | t_sentences = trans_result.join(" ").match(/~\d+~[^~]+/g) 411 | } 412 | 413 | } 414 | 415 | if (type == "DeepL") { 416 | for (var l in s_sentences) { 417 | let options = { 418 | url: "https://api-free.deepl.com/v2/translate", 419 | body: `auth_key=${setting.dkey}${setting.sl == "auto" ? "" : `&source_lang=${setting.sl}`}&target_lang=${setting.tl}${s_sentences[l].join("")}` 420 | } 421 | 422 | let trans = await send_request(options, "post") 423 | 424 | if (trans.translations) trans_result.push(trans.translations) 425 | } 426 | 427 | if (trans_result.length > 0) { 428 | for (var o in trans_result) { 429 | for (var u in trans_result[o]) { 430 | t_sentences.push(trans_result[o][u].text.replace(/\n/g, " ")) 431 | } 432 | } 433 | } 434 | } 435 | 436 | if (t_sentences.length > 0) { 437 | let g_t_sentences = t_sentences.join("\n").replace(/\s\n/g, "\n") 438 | 439 | for (var j in dialogue) { 440 | let patt = new RegExp(`(${timeline[j]})`) 441 | if (setting.line == "s") patt = new RegExp(`(${dialogue[j].replace(/(\[|\]|\(|\)|\?)/g, "\\$1")})`) 442 | 443 | let patt2 = new RegExp(`~${j}~\\s*(.+)`) 444 | 445 | if (g_t_sentences.match(patt2) && type == "Google") body = body.replace(patt, `$1\n${g_t_sentences.match(patt2)[1]}`) 446 | 447 | if (type == "DeepL") body = body.replace(patt, `$1\n${t_sentences[j]}`) 448 | 449 | } 450 | 451 | if (service != "Netflix") { 452 | settings[service].s_subtitles_url = url 453 | settings[service].subtitles = body 454 | settings[service].subtitles_type = setting.type 455 | settings[service].subtitles_sl = setting.sl 456 | settings[service].subtitles_tl = setting.tl 457 | settings[service].subtitles_line = setting.line 458 | $persistentStore.write(JSON.stringify(settings)) 459 | } 460 | } 461 | 462 | $done({ body }) 463 | 464 | } 465 | 466 | async function official_subtitles(subtitles_urls_data) { 467 | let result = [] 468 | 469 | if (service == "Disney" || service == "HBOMax") { 470 | let subtitles_index = parseInt(url.match(/(\d+)\.vtt/)[1]) 471 | 472 | let start = subtitles_index - 3 < 0 ? 0 : subtitles_index - 3 473 | 474 | subtitles_urls_data = subtitles_urls_data.slice(start, subtitles_index + 4) 475 | } 476 | 477 | for (var k in subtitles_urls_data) { 478 | let options = { 479 | url: subtitles_urls_data[k], 480 | headers: headers 481 | } 482 | result.push(await send_request(options, "get")) 483 | } 484 | 485 | body = body.replace(/\r/g, "") 486 | body = body.replace(/(\d+:\d\d:\d\d.\d\d\d --> \d+:\d\d:\d\d.\d.+\n.+)\n(.+)/g, "$1 $2") 487 | body = body.replace(/(\d+:\d\d:\d\d.\d\d\d --> \d+:\d\d:\d\d.\d.+\n.+)\n(.+)/g, "$1 $2") 488 | 489 | let timeline = body.match(/\d+:\d\d:\d\d.\d\d\d --> \d+:\d\d:\d\d.\d.+/g) 490 | 491 | for (var i in timeline) { 492 | let patt1 = new RegExp(`(${timeline[i]})`) 493 | if (setting.line == "s") patt1 = new RegExp(`(${timeline[i]}(\\n.+)+)`) 494 | 495 | let time = timeline[i].match(/^\d+:\d\d:\d\d/)[0] 496 | 497 | let patt2 = new RegExp(`${time}.\\d\\d\\d --> \\d+:\\d\\d:\\d\\d.\\d.+(\\n.+)+`) 498 | 499 | let dialogue = result.join("\n\n").match(patt2) 500 | 501 | if (dialogue) body = body.replace( 502 | patt1, 503 | `$1\n${dialogue[0] 504 | .replace(/\d+:\d\d:\d\d.\d\d\d --> \d+:\d\d:\d\d.\d.+\n/, "") 505 | .replace(/\n/, " ")}` 506 | ) 507 | } 508 | 509 | settings[service].s_subtitles_url = url 510 | settings[service].subtitles = body 511 | settings[service].subtitles_type = setting.type 512 | settings[service].subtitles_sl = setting.sl 513 | settings[service].subtitles_tl = setting.tl 514 | settings[service].subtitles_line = setting.line 515 | $persistentStore.write(JSON.stringify(settings)) 516 | 517 | $done({ body }) 518 | } 519 | 520 | function send_request(options, method) { 521 | return new Promise((resolve, reject) => { 522 | 523 | if (method == "get") { 524 | $httpClient.get(options, function (error, response, data) { 525 | if (error) return reject('Error') 526 | resolve(data) 527 | }) 528 | } 529 | 530 | if (method == "post") { 531 | $httpClient.post(options, function (error, response, data) { 532 | if (error) return reject('Error') 533 | resolve(JSON.parse(data)) 534 | }) 535 | } 536 | }) 537 | } 538 | 539 | function groupAgain(data, num) { 540 | var result = [] 541 | for (var i = 0; i < data.length; i += num) { 542 | result.push(data.slice(i, i + num)) 543 | } 544 | return result 545 | } 546 | 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("",`🔔${this.name}, 开始!`)}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,n]=i.split("@"),a={url:`http://${n}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(a,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),n=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(n);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:n}=t,a=s.decode(n,this.encoding);e(null,{status:i,statusCode:r,headers:o,rawBody:n,body:a},a)},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:n}=t,a=i.decode(n,this.encoding);e(null,{status:s,statusCode:r,headers:o,rawBody:n,body:a},a)},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}queryStr(t){let e="";for(const s in t){let i=t[s];null!=i&&""!==i&&("object"==typeof i&&(i=JSON.stringify(i)),e+=`${s}=${i}&`)}return e=e.substring(0,e.length-1),e}msg(e=t,s="",i="",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=["","==============📣系统通知📣=============="];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("",`❗️${this.name}, 错误!`,t.stack):this.log("",`❗️${this.name}, 错误!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`🔔${this.name}, 结束! 🕛 ${s} 秒`),this.log(),this.isSurge()||this.isQuanX()||this.isLoon()?$done(t):this.isNode()&&process.exit(1)}}(t,e)} 547 | --------------------------------------------------------------------------------