diff --git a/README.md b/README.md index e93baa99820..68d1ca446b0 100644 --- a/README.md +++ b/README.md @@ -55,24 +55,22 @@ https://github.com/blackmatrix7/ios_rule_script/tree/master/rewrite ### 脚本说明 -| 脚本 | 介绍 | 维护状态 | -| ------------------------------------------------------------ | ------------------------------------ | -------- | -| [知乎助手](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/zhihu) | 使用纯净版知乎是一种怎么样的体验? | 正常 | -| ~~[哔哩哔哩](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/bilibili)~~ | ~~没有广告的哔哩哔哩更值得干杯~~ | 停止 | -| [什么值得买](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/smzdm) | 什么值得买签到和去广告脚本 | 正常 | -| [百度贴吧](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/tieba) | 带重试功能的贴吧签到,提高签到成功率 | 正常 | -| [中国联通](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/10010) | 每日自动签到 | 正常 | -| [开屏去广告](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/startup) | 通过脚本去除缓存到本地的APP开屏广告 | 正常 | -| [家长帮](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/jiazhangbang) | 每日自动签到 | 正常 | -| [慢慢买](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/manmanbuy) | 每日自动签到 | 正常 | -| [叮咚买菜](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/dingdong) | 每日自动签到 | 正常 | -| [万达电影](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/wanda) | 每日自动签到,月末将剩余能量抽奖 | 正常 | -| [饿了么](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/eleme) | 每日自动领取会员任务 | 正常 | -| [Fa米家](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/famijia) | 每日自动签到 | 正常 | -| [Luka](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/luka) | 每日自动签到 | 正常 | -| [美团买菜](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/meituan) | 每日自动签到 | 正常 | -| [Synology](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/synology) | 群晖Download Station资源离线下载 | 正常 | -| [AppleStore](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/applestore) | AppleStore 商品库存监控 | 正常 | +| 脚本 | 介绍 | 框架 | 维护状态 | +| ------------------------------------------------------------ | ------------------------------------ | --------- | -------- | +| [知乎助手](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/zhihu) | 使用纯净版知乎是一种怎么样的体验? | MagicJS 2 | 正常 | +| ~~[哔哩哔哩](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/bilibili)~~ | ~~没有广告的哔哩哔哩更值得干杯~~ | MagicJS 2 | 停止 | +| [什么值得买](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/smzdm) | 什么值得买签到和去广告脚本 | MagicJS 3 | 正常 | +| [百度贴吧](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/tieba) | 带重试功能的贴吧签到,提高签到成功率 | MagicJS 3 | 正常 | +| [开屏去广告](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/startup) | 通过脚本去除缓存到本地的APP开屏广告 | MagicJS 2 | 正常 | +| [家长帮](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/jiazhangbang) | 每日自动签到 | MagicJS 2 | 正常 | +| [慢慢买](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/manmanbuy) | 每日自动签到 | MagicJS 2 | 正常 | +| [叮咚买菜](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/dingdong) | 每日自动签到 | MagicJS 2 | 正常 | +| [饿了么](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/eleme) | 每日自动领取会员任务 | MagicJS 2 | 正常 | +| [Fa米家](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/famijia) | 每日自动签到 | MagicJS 2 | 正常 | +| [Luka](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/luka) | 每日自动签到 | MagicJS 2 | 正常 | +| [美团买菜](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/meituan) | 每日自动签到 | MagicJS 2 | 正常 | +| [Synology](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/synology) | 群晖Download Station资源离线下载 | MagicJS 3 | 正常 | +| [AppleStore](https://github.com/blackmatrix7/ios_rule_script/tree/master/script/applestore) | AppleStore 商品库存监控 | MagicJS 3 | 正常 | #### Quantumult X Gallery diff --git a/script/README.md b/script/README.md index 50237d0b833..0b7841008c3 100644 --- a/script/README.md +++ b/script/README.md @@ -1,9 +1,150 @@ # 脚本 -**常见问题** +当前目录下的脚本都是基于 MagicJS 2 或 MaicJS 3 框架进行开发。 -使用过程中的常见问题,请访问:[https://github.com/blackmatrix7/ios_rule_script/wiki/脚本常见问题](https://github.com/blackmatrix7/ios_rule_script/wiki/脚本常见问题) +其中 MagicJS 2 已停止维护,以下涉及的特性,都以MagicJS 3为主。 -**安全性** +你可以在仓库的README中,查询到哪些项目是基于MagicJS3的。 + +**涉及NodeJS(含青龙面板)的内容,统一在此说明,单个脚本的README中不再赘述。** + +## 数据存储 + +### iOS平台 + +基于 MagicJS 2/3 编写的脚本,运行在iOS平台的APP中时,数据存储在由APP提供的存储池。 + +### NodeJS + +运行在NodeJS环境中时,数据存储在脚本同级目录下的magic.json文件中,而不存储在环境变量。 + +如果有需求,可以将不同的脚本存放在不同的目录下,读取不同的magic.json文件来实现数据隔离。 + +如果将所有的脚本数据存储在同个magic.json文件中,它们也可以和谐相处。 + +例如下面的例子,把什么值得买和饿了么的数据存储在一起。 + +```json +{ + "smzdm_cookie": "xxxxxxxxxxxxxxxxxxxxxxx", + "eleme_app_longitude": "xxxxxxxxxxxxxxxxx", + "eleme_app_latitude": "xxxxxxxxxxxxxxx", + "eleme_task_keywords": "xxxxxxxxxxxxxxxxxxxx", + "magic_bark_url": "xxxxxxxxxxxxxxxxxxxxxx" +} +``` + +### 脚本变量 + +基于MagicJS 3的脚本,会在README中明确说明使用的变量。在iOS平台下,这些变量可以在BoxJS中配置和修改。在NodeJS环境下,这些变量需要手动编辑magic.json文件。 + +### 共用变量 + +基于 MagicJS 3 的脚本,除脚本自身所需的变量外,以下的变量是所有脚本共用的。所有基于 MagicJS 3 的脚本(Magic 2 除外),在iOS平台下都会受到共用变量的影响。而在NodeJS环境下,共用变量会影响所有读取同一个magic.json的脚本。 + +| 变量名 | 类型 | 说明 | +| -------------- | ------ | ------------------------------------------------------------ | +| magic_bark_url | string | Bark推送链接,如 https://api.day.app/xxxxxxxxxxxxxxx/ | +| magic_loglevel | string | 日志等级,默认`INFO`,出现问题选`DEBUG`,更多等级见MagicJS手册 | + +## 青龙面板 + +MagicJS 3 增加“青龙面板模块”,可以将所使用的变量,直接同步到青龙面板的magic.json文件中。以此来实现手机仅获取Cookie,青龙面板进行签到。 + +同步变量需要通过手机访问青龙面板接口,请确保青龙面板可以被手机正常访问。 + +### 同步开关 + +支持数据同步到青龙面板的脚本,在BoxJS中都会有同步开关,请先将其打开。 + +![](https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/images/05.jpg) + +如果没有青龙面板、访问缓慢,甚至无法访问,不建议在平时打开此功能,以免由于网络问题造成客户端加载数据缓慢。 + +### 配置连接 + +使用前,需要在BoxJS中配置青龙面板的链接。 + +![](https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/images/04.jpg) + +配置完成后,如果访问没有问题,每次获取到的Cookies,都会同步到青龙面板。 + +### 存储目录 + +数据存储在青龙面板的脚本管理目录下的magic.json文件中。只有在同级目录下的脚本才会访问magic.json文件中的数据。 + +## 多账户 + +从 `MagicJS 3` 开始,正式对多账户进行支持,**部分脚本已实现多账户签到,如百度贴吧签到。** + +多账户分为以下几种情况: + +1. APP本身可以支持多账户 + + 以百度贴吧为例,APP客户端本身能够切换账号。这类程序实现多账号,仅需要切换账号后,重启APP以重新获取Cookies即可。 + +2. 通过网页登录的多账户 + + 可以通过隐身模式、无痕模式等浏览器功能,来实现多账号同时登录,如什么值得买的签到。 + +3. APP不支持多账户,但退出账户后Cookies不会失效 + + 通过获取Cookie -> 退出账号 -> 登录新账号 -> 获取新账号Cookie的方式来实现多账户。 + +4. APP不支持多账户,退出账户后Cookies失效 + + 此类情况需要在不同设备上登录不同的账户,将Cookies同步到青龙面板,由青龙面板实现多账户签到。 + +### 数据存储 + +多账户的数据以JSON格式存储。 + +以百度贴吧的为例,多账户Cookies存在在JSON中的格式,类似下面: + +```json +{ + "tieba_signin_cookie": { + "magic_session": true, + "百度用户1": "你第一个账户的Cookie", + "百度用户2": "你第二个账户的Cookie", + "百度用户3": "你第三个账户的Cookie" + } +} +``` + +其中 **`"magic_session": true` 不可删除和更改,它用来辅助MagicJS判断存储的是Sessions还是Object。** + +`百度用户1`这样的文字可以随意编写,只要不重复。如果是由脚本自动获取,通常是用户id等唯一标识。 + +不建议手动修改多账户的JSON字符串,错误的JSON字符串可能会导致脚本运行异常。 + +### 脏数据 + +如果因意外情况产生脏数据,导致多账户的签到出现异常,建议将Cookie数据进行删除,重新获取所有账户的Cookie。 + +例如上述的`tieba_signin_cookie`,出现异常时,应将整个`tieba_signin_cookie`删除,全部重新获取。 + +## 安全性 + +JavaScript脚本可以执行非常多的操作,通常来说,在客户端中调用脚本属于高风险行为。您在使用脚本前,务必确认脚本安全可信,如果有条件,应该仔细阅读脚本代码。 + +特别需要注意: + +### 脚本是否含有对外发送请求的操作 + +如带有Cookie、Token、Password等等可以作为身份凭证的请求,这类请求比较敏感,务必确认请求的目标安全可信。理论上恶意脚本可以利用你的Cookie,进行非常多的行为,如发帖、购物等等。 + +### 脚本对响应体进行修改 + +对于修改响应体的脚本,必须确认修改响应体内容可信。通过对Http请求响应体的修改,可以在客户端上显示一些欺诈信息,例如显示一些虚假的中奖信息。 + +应慎重使用可以由远端控制修改响应体的脚本,此类脚本可能在当初检查时执行的结果是正常的,但是在某个时刻,可由远端控制修改响应内容。 + +### 加密的脚本 + +本仓库的脚本源码都完全开放,不加密不混淆,不会将你的信息发送给任何第三方,欢迎进行Code Review。 + +**出于安全性考虑,不建议使用任何被加密、混淆的脚本。** + +如果你在使用青龙面板,由于magic.json内的数据是完全开放不做加密的,并不能防止其他恶意脚本读取magic.json导致信息泄露。所以请务必确保在青龙面板上运行脚本的安全性,本仓库的脚本不会窃取你的数据,但是无法避免第三方恶意脚本,窃取由本仓库的脚本存储/生成的数据。 -关于安全性问题,请访问:[https://github.com/blackmatrix7/ios_rule_script/wiki/脚本的安全性](https://github.com/blackmatrix7/ios_rule_script/wiki/脚本的安全性) \ No newline at end of file diff --git a/script/boxjs.json b/script/boxjs.json index 95662f1891b..3e620a441de 100644 --- a/script/boxjs.json +++ b/script/boxjs.json @@ -6,24 +6,121 @@ "repo": "https://github.com/blackmatrix7/ios_rule_script", "apps": [ { - "id": "blackmatrix7.bark", - "name": "Bark推送", + "id": "blackmatrix7.magicjs", + "name": "MagicJS", + "settings": [ + { + "id": "magic_loglevel", + "name": "日志等级", + "val": "INFO", + "type": "radios", + "items": [ + { + "key": "INFO", + "label": "INFO" + }, + { + "key": "WARNING", + "label": "WARNING" + }, + { + "key": "ERROR", + "label": "ERROR" + }, + { + "key": "DEBUG", + "label": "DEBUG" + }, + { + "key": "SNIFFER", + "label": "SNIFFER" + } + ], + "desc": "出现异常时请选择DEBUG提交日志" + } + ], + "author": "@blackmatrix7", + "repo": "https://github.com/blackmatrix7/ios_rule_script/", + "icons": [ + "https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/magicjs/images/logo_dark.png", + "https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/magicjs/images/logo.png" + ] + }, + { + "id": "blackmatrix7.qinglong", + "name": "青龙面板", "keys": [ - "bark_url" + "magic_qlurl", + "magic_qlclient", + "magic_qlsecrt", + "magic_qlname", + "magic_qlpwd", + "magic_qltoken" ], "settings": [ { - "id": "bark_url", + "id": "magic_qlurl", + "name": "登录地址", + "val": "", + "type": "input", + "placeholder": "http://qinglong.mydomain.com", + "autoGrow": true, + "desc": "填写青龙面板的登录地址,如为https请保证证书有效" + }, + { + "id": "magic_qlclient", + "name": "ClientId", + "val": "", + "type": "input", + "placeholder": "", + "autoGrow": true, + "desc": "填写青龙面板的ClientId" + }, + { + "id": "magic_qlsecrt", + "name": "ClientSecret", + "val": "", + "type": "input", + "placeholder": "", + "autoGrow": true, + "desc": "填写青龙面板的ClientSecret" + }, + { + "id": "magic_qltoken", + "name": "token", + "val": "", + "type": "textarea", + "placeholder": "", + "autoGrow": true, + "desc": "登录token,正常情况下不需要填写,自动获取" + } + ], + "author": "@blackmatrix7", + "repo": "https://github.com/blackmatrix7/ios_rule_script/tree/master/script/bilibili", + "icons": [ + "https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/magicjs/images/qinglong_dark.png", + "https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/magicjs/images/qinglong.png" + ] + }, + { + "id": "blackmatrix7.bark", + "name": "Bark推送", + "keys": [ + "magic_bark_url" + ], + "settings": [ + { + "id": "magic_bark_url", "name": "Bark推送URL", "val": "", "type": "input", "placeholder": "https://api.day.app/xxxxxxxxxxxxxxxxxx/", "autoGrow": true, - "desc": "填写Bark推送的链接,脚本通知将通过Bark推送" + "desc": "填写Bark推送的链接,脚本通知将通过Bark推送。仅基于MagicJS 3的脚本支持。" } ], "author": "@blackmatrix7", - "repo": "https://git.codecolor.cool/matrix/script/bilibili", + "repo": "https://github.com/blackmatrix7/ios_rule_script/tree/master/script/bilibili", "icons": [ "https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/icon/matrix/dark/bark.jpg", "https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/icon/matrix/color/bark.jpg" @@ -34,9 +131,7 @@ "name": "哔哩哔哩去广告", "keys": [ "bilibili_story_aid", - "bilibili_feed_black", - "bilibili_disable_index_story", - "bilibili_enable_mall" + "bilibili_feed_black" ], "settings": [ { @@ -48,20 +143,6 @@ "autoGrow": true, "rows": 5, "desc": "以英文逗号分隔多个号码" - }, - { - "id": "bilibili_disable_index_story", - "name": "停用首页竖屏播放器", - "val": false, - "type": "boolean", - "desc": "首页推荐竖屏视频转为普通播放器" - }, - { - "id": "bilibili_enable_mall", - "name": "启用会员购", - "val": false, - "type": "boolean", - "desc": "我的tab-更多服务-添加会员购入口" } ], "author": "@blackmatrix7", @@ -96,7 +177,7 @@ "eleme_task_keywords" ], "author": "@blackmatrix7", - "repo": "https://git.codecolor.cool/matrix/script/eleme", + "repo": "https://github.com/blackmatrix7/ios_rule_script/tree/master/script/eleme", "icons": [ "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/elem.png", "https://raw.githubusercontent.com/Orz-3/mini/master/Color/elem.png" @@ -251,7 +332,11 @@ "name": "什么值得买", "keys": [ "smzdm_cookie", - "smzdm_session" + "smzdm_session", + "smzdm_signin", + "smzdm_mission", + "smzdm_lottery", + "smzdm_sync_qinglong" ], "author": "@blackmatrix7", "repo": "https://github.com/blackmatrix7/ios_rule_script/tree/master/script/smzdm", @@ -261,12 +346,38 @@ ], "scripts": [ { - "name": "每日自动任务", - "script": "https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/smzdm/smzdm_mission.js" + "name": "执行每日签到与任务", + "script": "https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/smzdm/smzdm_daily.js" + } + ], + "settings": [ + { + "id": "smzdm_sync_qinglong", + "name": "同步Cookie到青龙面板", + "val": false, + "type": "boolean", + "desc": "需先配置好青龙面板登录参数,并确保手机可以访问青龙面板" }, { - "name": "每日自动签到", - "script": "https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/smzdm/smzdm_signin.js" + "id": "smzdm_signin", + "name": "执行每日签到", + "val": true, + "type": "boolean", + "desc": "" + }, + { + "id": "smzdm_mission", + "name": "执行每日任务", + "val": false, + "type": "boolean", + "desc": "" + }, + { + "id": "smzdm_lottery", + "name": "执行每日抽奖", + "val": false, + "type": "boolean", + "desc": "" } ] }, @@ -274,7 +385,8 @@ "id": "blackmatrix7.tieba", "name": "百度贴吧", "keys": [ - "tieba_checkin_cookie" + "tieba_signin_cookie", + "tieba_sync_qinglong" ], "author": "@blackmatrix7", "repo": "https://github.com/blackmatrix7/ios_rule_script/tree/master/script/tieba", @@ -282,7 +394,25 @@ "https://raw.githubusercontent.com/Orz-3/mini/master/Alpha/tieba.png", "https://raw.githubusercontent.com/Orz-3/mini/master/Color/tieba.png" ], - "script": "https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.js" + "script": "https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.js", + "settings": [ + { + "id": "tieba_sync_qinglong", + "name": "同步Cookie到青龙面板", + "val": false, + "type": "boolean", + "desc": "需先配置好青龙面板登录参数,并确保手机可以访问青龙面板" + }, + { + "id": "tieba_signin_cookie", + "name": "百度贴吧Cookies", + "val": "", + "type": "textarea", + "placeholder": "推荐由脚本自动获取Cookies,如有特殊情况可手动填写,必须为Json格式", + "autoGrow": true, + "desc": "多账户Cookies,如出现异常,请删除全部内容,避免直接编辑数据" + } + ] }, { "id": "blackmatrix7.zhihu", @@ -336,7 +466,7 @@ "name": "显示为盐选会员", "val": false, "type": "boolean", - "desc": "非会员用户显示为盐选会员,仅自己可见,无实际效果" + "desc": "非会员用户显示为盐选会员,屏蔽关键词解锁需要开启此功能" }, { "id": "zhihu_settings_preset_words", @@ -345,6 +475,13 @@ "type": "boolean", "desc": "屏蔽搜索页中的预置关键词广告" }, + { + "id": "zhihu_settings_remove_article", + "name": "屏蔽推荐页中的文章", + "val": false, + "type": "boolean", + "desc": "屏蔽推荐页中的文章,默认不启用" + }, { "id": "zhihu_settings_blocked_users", "name": "黑名单屏蔽效果增强✨", @@ -374,11 +511,11 @@ "desc": "在知乎回答中提示付费或营销内容" }, { - "id": "zhihu_settings_remove_yanxuan", - "name": "屏蔽“盐选推荐”❓", - "val": true, + "id": "zhihu_settings_remove_sections", + "name": "移除推荐页顶部项✨", + "val": false, "type": "boolean", - "desc": "屏蔽推荐页中的“盐选推荐”" + "desc": "知乎8.3.0有效,仅保留全部和直播,直播无法去除" }, { "id": "zhihu_settings_app_conf", @@ -477,35 +614,6 @@ "placeholder": "", "autoGrow": true, "desc": "除非无法正常获取Sid,否则保持现在的值,不要修改" - }, - { - "id": "magicjs_loglevel", - "name": "日志等级", - "val": "INFO", - "type": "radios", - "items": [ - { - "key": "INFO", - "label": "INFO" - }, - { - "key": "WARNING", - "label": "WARNING" - }, - { - "key": "ERROR", - "label": "ERROR" - }, - { - "key": "CRITICAL", - "label": "CRITICAL" - }, - { - "key": "DEBUG", - "label": "DEBUG" - } - ], - "desc": "出现异常时请选择DEBUG提交日志" } ], "author": "@blackmatrix7", @@ -534,40 +642,11 @@ "author": "@blackmatrix7", "repo": "https://github.com/blackmatrix7/ios_rule_script/tree/master/script/applestore", "settings": [ - { - "id": "applestore_type", - "name": "商店类型", - "val": "APPLESTORE", - "type": "radios", - "items": [ - { - "key": "AppleStore零售店", - "label": "INFO" - }, - { - "key": "Apple官网", - "label": "WARNING" - }, - { - "key": "ERROR", - "label": "ERROR" - }, - { - "key": "CRITICAL", - "label": "CRITICAL" - }, - { - "key": "DEBUG", - "label": "DEBUG" - } - ], - "desc": "出现异常时请选择DEBUG提交日志" - }, { "id": "goods_model", "name": "商品型号", "val": "", - "type": "input", + "type": "textarea", "placeholder": "Z0YQ#MKMR3CH/A,MJXA3FE/A#AppleWatch 7 石墨色不锈钢;MLDE3CH/A", "autoGrow": true, "desc": "需要监控的商品型号,option用#分隔,自定义名称在option后以#分隔。多款以;分隔,移动端建议只监控一个。" @@ -581,46 +660,12 @@ "autoGrow": true, "desc": "直辖市示例:北京 北京 昌平区" }, - { - "id": "applestore_bark_url", - "name": "Bark推送", - "val": "", - "type": "input", - "placeholder": "https://api.day.app/VXTWvaQ18N29bsQAg7DgkT", - "autoGrow": true, - "desc": "使用Bark推送到其他设备,比如iPad执行监控,推送结果到iPhone" - }, { "id": "applestore_settings_notify_soldout", "name": "查询无货也进行通知", "val": false, "type": "boolean", "desc": "可能会发起大量推送,建议仅在测试时开启" - }, - { - "id": "magicjs_loglevel", - "name": "日志等级", - "val": "INFO", - "type": "radios", - "items": [ - { - "key": "INFO", - "label": "INFO" - }, - { - "key": "WARNING", - "label": "WARNING" - }, - { - "key": "ERROR", - "label": "ERROR" - }, - { - "key": "DEBUG", - "label": "DEBUG" - } - ], - "desc": "出现异常时请选择DEBUG提交日志" } ], "icons": [ diff --git a/script/magicjs/images/logo.png b/script/magicjs/images/logo.png new file mode 100644 index 00000000000..7d83b1e38f1 Binary files /dev/null and b/script/magicjs/images/logo.png differ diff --git a/script/magicjs/images/logo_dark.png b/script/magicjs/images/logo_dark.png new file mode 100644 index 00000000000..5f2f0070245 Binary files /dev/null and b/script/magicjs/images/logo_dark.png differ diff --git a/script/magicjs/images/qinglong.png b/script/magicjs/images/qinglong.png new file mode 100644 index 00000000000..e064a89ec72 Binary files /dev/null and b/script/magicjs/images/qinglong.png differ diff --git a/script/magicjs/images/qinglong_dark.png b/script/magicjs/images/qinglong_dark.png new file mode 100644 index 00000000000..05fddfe7a52 Binary files /dev/null and b/script/magicjs/images/qinglong_dark.png differ diff --git a/script/tieba/README.md b/script/tieba/README.md index 3e371a4ff2d..142b49865e6 100644 --- a/script/tieba/README.md +++ b/script/tieba/README.md @@ -1,18 +1,8 @@ -# 百度贴吧签到 +# 🧸 百度贴吧签到 ## 前言 -参考 https://github.com/NobyDa/Script/tree/master/BDTieBa-DailyBonus 做了彻底的重写。 - -做如下改动: - -1. 精简合并通知 - - 只显示签到贴吧总数、成功数量、失败数量,签到明细只会显示失败的,因为我并不关心哪些贴吧签到成功。 - -2. 增加重试机制 - - 针对签到失败的贴吧,进行10次,每次间隔2秒的重试,可以极大提高签到成功率。 +百度贴吧多账户自动签到,支持青龙面板。 ## 配置 @@ -21,38 +11,55 @@ 使用模块 -Surge在获取Cookie时,需要在MITM中设置h2=false,即关闭 MITM over HTTP/2,否则会提示获取Cookie出现异常。 - -建议在获取Cookie时临时关闭,获取成功后再开启,或者等待客户端修复。 - ```ini -https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.sgmodule +https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.sgmodule ``` ### Quantumult X ```ini [rewrite_remote] -https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.qxrewrite, tag=贴吧_获取Cookie, update-interval=86400, opt-parser=false, enabled=true +https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.qxrewrite, tag=贴吧_获取Cookie, update-interval=86400, opt-parser=false, enabled=true [task_local] -30 9 * * * https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.js, tag=贴吧_每日签到, enabled=true +30 10 * * * https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.js, tag=贴吧_每日签到, enabled=true ``` ### Loon -使用插件 +安装插件 ```ini -[Remote Script] -https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.lnplugin, tag=贴吧_每日签到, enabled=true +https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.lnplugin +``` + +### 青龙面板 + +订阅单文件 + +```ini +https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.js ``` ## 获取Cookie 关闭贴吧后台,重新进入一次贴吧即可。 -![](https://github.com/blackmatrix7/ios_rule_script/blob/master/script/tieba/images/03.jpg?raw=true) +![](https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/images/03.jpg) + +## 多账户 + +全新的百度贴吧签到脚本,原生提供了多账户签到的支持。 + +**获取多账户Cookies的办法**: + +你需要做的仅仅是在百度贴吧客户端中,选择“我的”,点击右上角的设置图标,进入“我的账户”,切换不同的账号。 + +每切换一个账号,需要重启一次贴吧客户端,让脚本自动获取Cookie。 + +随着贴吧客户端更新,上述操作方式可能会有变化,但整体大同小异,跟日常切换多账户一样就可以了。 + +*理论上,你可以执行无限多的账号签到,只要签到脚本执行不会超时。* ## 签到 @@ -60,65 +67,19 @@ https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tie 全部签到成功时: -![](https://github.com/blackmatrix7/ios_rule_script/blob/master/script/tieba/images/01.jpg?raw=true) +![](https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/images/01.jpg) 部分贴吧签到失败时: -![](https://github.com/blackmatrix7/ios_rule_script/blob/master/script/tieba/images/02.jpg?raw=true) +![](https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/images/02.jpg) -## 统一推送 +## 脚本变量 -MagicJS利用Bark,实现了跨设备的统一推送能力,将多个iOS设备的脚本执行结果,统一推送到一个设备上。 +当前脚本使用的变量,你可以根据这些Key,在magic.json中配置数据。 -执行效果图,以饿了么为例: +| 名称 | 类型 | 作用 | +| ------------------- | ---- | ------------------------------- | +| tieba_signin_cookie | json | 存储多账号的Cookies | +| tieba_sync_qinglong | bool | 判断是否将Cookies同步到青龙面板 | -![](https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/eleme/images/bark.jpg) -### 开启统一推送 - -你需要安装Bark这个APP,打开后可以得到类似这样的链接: - -```http -https://api.day.app/VXTWvaQ18N29bsQAg7DgkT -``` - -在Surge、Loon、QuantumultX中执行以下代码,将链接写入(如何执行代码请自己动手解决)。 - -**Surge、Loon** - -```javascript -# 开启所有脚本统一推送 -$persistentStore.write("https://api.day.app/VXTWvaQ18N29bsQAg7DgkT", "magicjs_unified_push_url"); -``` - -**Quantumult X** - -```javascript -# 开启所有脚本统一推送 -$prefs.setValueForKey("https://api.day.app/VXTWvaQ18N29bsQAg7DgkT", "magicjs_unified_push_url"); -``` - -### 关闭统一推送 - -**Surge、Loon** - -```javascript -# 关闭所有脚本统一推送 -$persistentStore.write("", "magicjs_unified_push_url"); -``` - -**Quantumult X** - -```javascript -# 关闭所有脚本统一推送 -$prefs.setValueForKey("", "magicjs_unified_push_url"); -``` - -### 其他 - -1. 统一推送能力仅对支持的脚本有效。 -2. 开启统一推送后,所有支持统一推送的脚本,都会把通知推送到目标设备上。 -3. 限于Bark的功能,统一推送中的多媒体和链接不可用。 -4. 统一推送需要使用Bark的服务器,推送成功与否,与Bark服务器的可用性有关。 -5. 统一推送不会关闭APP的本地推送,即两个iOS设备都会有推送。 -6. 如有隐私考虑,可以参考Bark的服务端文档,自建服务端。 \ No newline at end of file diff --git a/script/tieba/images/01.jpg b/script/tieba/images/01.jpg index 130b6426713..92b0120bf10 100644 Binary files a/script/tieba/images/01.jpg and b/script/tieba/images/01.jpg differ diff --git a/script/tieba/images/02.jpg b/script/tieba/images/02.jpg index 5bcda97e404..c8a2b6db744 100644 Binary files a/script/tieba/images/02.jpg and b/script/tieba/images/02.jpg differ diff --git a/script/tieba/images/03.jpg b/script/tieba/images/03.jpg index d90f5084805..fac7ab7583a 100644 Binary files a/script/tieba/images/03.jpg and b/script/tieba/images/03.jpg differ diff --git a/script/tieba/images/04.jpg b/script/tieba/images/04.jpg new file mode 100644 index 00000000000..f10b896712e Binary files /dev/null and b/script/tieba/images/04.jpg differ diff --git a/script/tieba/images/05.jpg b/script/tieba/images/05.jpg new file mode 100644 index 00000000000..502ddaed549 Binary files /dev/null and b/script/tieba/images/05.jpg differ diff --git a/script/tieba/images/06.jpg b/script/tieba/images/06.jpg new file mode 100644 index 00000000000..e0300b27e15 Binary files /dev/null and b/script/tieba/images/06.jpg differ diff --git a/script/tieba/tieba_checkin.js b/script/tieba/tieba_checkin.js deleted file mode 100644 index bf86a941b9a..00000000000 --- a/script/tieba/tieba_checkin.js +++ /dev/null @@ -1,161 +0,0 @@ -/* -百度贴吧签到,增加重试机制,减少签到失败的情况。 -脚本为串行执行,通过设定batchSize的值,实现每批多少个贴吧并行签到一次。 -*/ -const scirptName = "百度贴吧"; -const batchSize = 20; -const retries = 10; // 签到失败重试次数 -const interval = 5000; // 每次重试间隔 -const tiebaCookieKey = "tieba_checkin_cookie"; -const tiebeGetCookieRegex1 = /https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login/; -const tiebeGetCookieRegex2 = /^https?:\/\/c\.tieba\.baidu\.com\/c\/s\/channelIconConfig/; -const tiebeGetCookieRegex3 = /https?:\/\/tiebac\.baidu\.com\/c\/u\/follow\/getFoldedMessageUserInfo/; -let magicJS = MagicJS(scirptName, "DEBUG"); -magicJS.unifiedPushUrl = magicJS.read("tieba_unified_push_url") || magicJS.read("magicjs_unified_push_url"); - -let getTiebaListOptions = { - url: "https://tieba.baidu.com/mo/q/newmoindex", - headers: { - "Content-Type": "application/octet-stream", - "Referer": "https://tieba.baidu.com/index/tbwise/forum", - "Cookie": "", - "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16A366", - }, - body: "", -}; - -let tiebaCheckInOptions = { - url: "https://tieba.baidu.com/sign/add", - headers: { - "Accept": "application/json, text/javascript, */*; q=0.01", - "Accept-Encoding": "gzip,deflate,br", - "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", - "Connection": "keep-alive", - "Cookie": "", - "Host": "tieba.baidu.com", - "Referer": "https://tieba.baidu.com/", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36 Edg/84.0.522.63", - }, - body: "", -}; - -function GetTieBaList(cookie) { - return new Promise((resolve, reject) => { - getTiebaListOptions.headers.Cookie = cookie; - magicJS.get(getTiebaListOptions, (err, resp, data) => { - if (err) { - magicJS.logError(`获取贴吧列表失败,请求异常:${err}`); - reject(err); - } else { - try { - let obj = JSON.parse(data); - if (obj.error === "success") { - resolve([obj.data.tbs, obj.data.like_forum]); - } else { - magicJS.logWarning(`获取贴吧列表失败,接口响应不合法:${data}`); - reject("获取贴吧列表失败"); - } - } catch (err) { - magicJS.logError(`获取贴吧列表失败,执行异常:${err}`); - reject(err); - } - } - }); - }); -} - -function TiebaCheckIn(cookie, tbs, tieba) { - return new Promise((resolve, reject) => { - let kw = tieba["forum_name"]; - if (tieba["is_sign"] === 1) { - resolve(`[${kw}] 重复签到`); - } else { - tiebaCheckInOptions.headers.Cookie = cookie; - tiebaCheckInOptions.body = `tbs=${tbs}&kw=${kw}&ie=utf-8`; - magicJS.post(tiebaCheckInOptions, (err, resp, data) => { - if (err) { - magicJS.logError(`[${kw}] 签到失败,请求异常:${err}`); - reject(err); - } else { - try { - let obj = JSON.parse(data); - if (obj.data.errmsg === "success" && obj.data.errno === 0 && obj.data.uinfo.is_sign_in === 1) { - let msg = `[${kw}] 签到成功 排名 ${obj.data.uinfo.user_sign_rank} 积分 ${obj.data.uinfo.cont_sign_num}`; - magicJS.logInfo(msg); - resolve(msg); - } else if (obj.no === 2150040) { - magicJS.logDebug(`[${kw}] need vcode,接口响应:${data}`); - reject(`[${kw}] 签到失败,need vcode`); - } else if (obj.no === 1011) { - magicJS.logDebug(`[${kw}] 未加入此吧或等级不够,接口响应:${data}`); - reject(`[${kw}] 未加入此吧或等级不够`); - } else if (obj.no === 1102) { - magicJS.logDebug(`[${kw}] 签到过快,接口响应:${data}`); - reject(`[${kw}] 签到过快`); - } else if (obj.no === 1101) { - magicJS.logDebug(`[${kw}] 重复签到,接口响应:${data}`); - resolve(`[${kw}] 重复签到`); - } else { - magicJS.logWarning(`[${kw}] 签到失败,接口响应不合法:${data}`); - reject(`[${kw}] 签到失败`); - } - } catch (err) { - magicJS.logError(`${kw} 签到失败,执行异常:${err}`); - reject(`[${kw}] 执行异常`); - } - } - }); - } - }); -} - -(async () => { - if (magicJS.isRequest && (tiebeGetCookieRegex1.test(magicJS.request.url) || - tiebeGetCookieRegex2.test(magicJS.request.url) || - tiebeGetCookieRegex3.test(magicJS.request.url))) { - let cookie = magicJS.request.headers.Cookie; - let hisCookie = magicJS.read(tiebaCookieKey); - magicJS.logDebug(`当前贴吧Cookie:\n${cookie}\n历史贴吧Cookie:\n${hisCookie}`); - if (!!cookie && cookie === hisCookie) { - magicJS.logInfo(`贴吧Cookie没有变化,无需更新。`); - } else if (!!cookie && cookie !== hisCookie) { - magicJS.write(tiebaCookieKey, cookie); - magicJS.notify(`🎈获取贴吧Cookie成功!!`); - } else { - magicJS.notify(`❌获取贴吧Cookie出现异常!!`); - } - } else { - let cookie = magicJS.read(tiebaCookieKey); - let content = "🥺很遗憾,以下贴吧签到失败:"; - if (!!cookie === false) { - magicJS.notify("❓请先获取有效的贴吧Cookie!!"); - } else { - let [tbs, tiebaList] = await magicJS.retry(GetTieBaList, retries, interval)(cookie); - let tiebaCount = tiebaList.length; - let cycleNumber = Math.ceil(tiebaList.length / batchSize); - let [success, failed] = [0, 0]; - for (let i = 0; i < cycleNumber; i++) { - let batchTiebaPromise = []; - let batchTiebaList = tiebaList.splice(0, batchSize); - for (let tieba of batchTiebaList) { - batchTiebaPromise.push(magicJS.attempt(magicJS.retry(TiebaCheckIn, retries, interval)(cookie, tbs, tieba))); - } - await Promise.all(batchTiebaPromise).then((result) => { - result.forEach((element) => { - if (element[0] !== null) { - failed += 1; - content += `\n${element[0]}`; - } else { - success += 1; - } - }); - }); - } - magicJS.notify(scirptName, `签到${tiebaCount}个,成功${success}个,失败${failed}个`, !!failed > 0 ? content : "🎉恭喜,所有贴吧签到成功!!"); - } - } - magicJS.done(); -})(); - -// prettier-ignore -function MagicJS(scriptName = "MagicJS", logLevel = "INFO") { return new class { constructor() { if (this.version = "2.2.3.3", this.scriptName = scriptName, this.logLevels = { DEBUG: 5, INFO: 4, NOTIFY: 3, WARNING: 2, ERROR: 1, CRITICAL: 0, NONE: -1 }, this.isLoon = "undefined" != typeof $loon, this.isQuanX = "undefined" != typeof $task, this.isJSBox = "undefined" != typeof $drive, this.isNode = "undefined" != typeof module && !this.isJSBox, this.isSurge = "undefined" != typeof $httpClient && !this.isLoon, this.node = { request: void 0, fs: void 0, data: {} }, this.iOSUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Mobile/15E148 Safari/604.1", this.pcUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36 Edg/84.0.522.59", this.logLevel = logLevel, this._barkUrl = "", this.isNode) { this.node.fs = require("fs"), this.node.request = require("request"); try { this.node.fs.accessSync("./magic.json", this.node.fs.constants.R_OK | this.node.fs.constants.W_OK) } catch (err) { this.node.fs.writeFileSync("./magic.json", "{}", { encoding: "utf8" }) } this.node.data = require("./magic.json") } else this.isJSBox && ($file.exists("drive://MagicJS") || $file.mkdir("drive://MagicJS"), $file.exists("drive://MagicJS/magic.json") || $file.write({ data: $data({ string: "{}" }), path: "drive://MagicJS/magic.json" })) } set barkUrl(url) { this._barkUrl = url.replace(/\/+$/g, "") } set logLevel(level) { this._logLevel = "string" == typeof level ? level.toUpperCase() : "DEBUG" } get logLevel() { return this._logLevel } get isRequest() { return "undefined" != typeof $request && "undefined" == typeof $response } get isResponse() { return "undefined" != typeof $response } get request() { return "undefined" != typeof $request ? $request : void 0 } get response() { return "undefined" != typeof $response ? ($response.hasOwnProperty("status") && ($response.statusCode = $response.status), $response.hasOwnProperty("statusCode") && ($response.status = $response.statusCode), $response) : void 0 } get platform() { return this.isSurge ? "Surge" : this.isQuanX ? "Quantumult X" : this.isLoon ? "Loon" : this.isJSBox ? "JSBox" : this.isNode ? "Node.js" : "Unknown" } read(key, session = "") { let val = ""; this.isSurge || this.isLoon ? val = $persistentStore.read(key) : this.isQuanX ? val = $prefs.valueForKey(key) : this.isNode ? val = this.node.data : this.isJSBox && (val = $file.read("drive://MagicJS/magic.json").string); try { this.isNode && (val = val[key]), this.isJSBox && (val = JSON.parse(val)[key]), session && ("string" == typeof val && (val = JSON.parse(val)), val = val && "object" == typeof val ? val[session] : null) } catch (err) { this.logError(err), val = session ? {} : null, this.del(key) } void 0 === val && (val = null); try { val && "string" == typeof val && (val = JSON.parse(val)) } catch (err) { } return this.logDebug(`READ DATA [${key}]${session ? `[${session}]` : ""}(${typeof val})\n${JSON.stringify(val)}`), val } write(key, val, session = "") { let data = session ? {} : ""; if (session && (this.isSurge || this.isLoon) ? data = $persistentStore.read(key) : session && this.isQuanX ? data = $prefs.valueForKey(key) : this.isNode ? data = this.node.data : this.isJSBox && (data = JSON.parse($file.read("drive://MagicJS/magic.json").string)), session) { try { "string" == typeof data && (data = JSON.parse(data)), data = "object" == typeof data && data ? data : {} } catch (err) { this.logError(err), this.del(key), data = {} } this.isJSBox || this.isNode ? (data[key] && "object" == typeof data[key] || (data[key] = {}), data[key].hasOwnProperty(session) || (data[key][session] = null), void 0 === val ? delete data[key][session] : data[key][session] = val) : void 0 === val ? delete data[session] : data[session] = val } else this.isNode || this.isJSBox ? void 0 === val ? delete data[key] : data[key] = val : data = void 0 === val ? null : val; "object" == typeof data && (data = JSON.stringify(data)), this.isSurge || this.isLoon ? $persistentStore.write(data, key) : this.isQuanX ? $prefs.setValueForKey(data, key) : this.isNode ? this.node.fs.writeFileSync("./magic.json", data) : this.isJSBox && $file.write({ data: $data({ string: data }), path: "drive://MagicJS/magic.json" }), this.logDebug(`WRITE DATA [${key}]${session ? `[${session}]` : ""}(${typeof val})\n${JSON.stringify(val)}`) } del(key, session = "") { this.logDebug(`DELETE KEY [${key}]${session ? `[${session}]` : ""}`), this.write(key, null, session) } notify(title = this.scriptName, subTitle = "", body = "", opts = "") { let convertOptions; if (opts = (_opts => { let newOpts = {}; if ("string" == typeof _opts) this.isLoon ? newOpts = { openUrl: _opts } : this.isQuanX ? newOpts = { "open-url": _opts } : this.isSurge && (newOpts = { url: _opts }); else if ("object" == typeof _opts) if (this.isLoon) newOpts.openUrl = _opts["open-url"] ? _opts["open-url"] : "", newOpts.mediaUrl = _opts["media-url"] ? _opts["media-url"] : ""; else if (this.isQuanX) newOpts = _opts["open-url"] || _opts["media-url"] ? _opts : {}; else if (this.isSurge) { let openUrl = _opts["open-url"] || _opts.openUrl; newOpts = openUrl ? { url: openUrl } : {} } return newOpts })(opts), 1 == arguments.length && (title = this.scriptName, subTitle = "", body = arguments[0]), this.logNotify(`title:${title}\nsubTitle:${subTitle}\nbody:${body}\noptions:${"object" == typeof opts ? JSON.stringify(opts) : opts}`), this.isSurge) $notification.post(title, subTitle, body, opts); else if (this.isLoon) opts ? $notification.post(title, subTitle, body, opts) : $notification.post(title, subTitle, body); else if (this.isQuanX) $notify(title, subTitle, body, opts); else if (this.isNode) { if (this._barkUrl) { let content = encodeURI(`${title}/${subTitle}\n${body}`); this.get(`${this._barkUrl}/${content}`, () => { }) } } else if (this.isJSBox) { let push = { title: title, body: subTitle ? `${subTitle}\n${body}` : body }; $push.schedule(push) } } notifyDebug(title = this.scriptName, subTitle = "", body = "", opts = "") { "DEBUG" === this.logLevel && (1 == arguments.length && (title = this.scriptName, subTitle = "", body = arguments[0]), this.notify(title, subTitle, body, opts)) } log(msg, level = "INFO") { this.logLevels[this._logLevel] < this.logLevels[level.toUpperCase()] || console.log(`[${level}] [${this.scriptName}]\n${msg}\n`) } logDebug(msg) { this.log(msg, "DEBUG") } logInfo(msg) { this.log(msg, "INFO") } logNotify(msg) { this.log(msg, "NOTIFY") } logWarning(msg) { this.log(msg, "WARNING") } logError(msg) { this.log(msg, "ERROR") } logRetry(msg) { this.log(msg, "RETRY") } adapterHttpOptions(options, method) { let _options = "object" == typeof options ? Object.assign({}, options) : { url: options, headers: {} }; _options.hasOwnProperty("header") && !_options.hasOwnProperty("headers") && (_options.headers = _options.header, delete _options.header); const headersMap = { accept: "Accept", "accept-ch": "Accept-CH", "accept-charset": "Accept-Charset", "accept-features": "Accept-Features", "accept-encoding": "Accept-Encoding", "accept-language": "Accept-Language", "accept-ranges": "Accept-Ranges", "access-control-allow-credentials": "Access-Control-Allow-Credentials", "access-control-allow-origin": "Access-Control-Allow-Origin", "access-control-allow-methods": "Access-Control-Allow-Methods", "access-control-allow-headers": "Access-Control-Allow-Headers", "access-control-max-age": "Access-Control-Max-Age", "access-control-expose-headers": "Access-Control-Expose-Headers", "access-control-request-method": "Access-Control-Request-Method", "access-control-request-headers": "Access-Control-Request-Headers", age: "Age", allow: "Allow", alternates: "Alternates", authorization: "Authorization", "cache-control": "Cache-Control", connection: "Connection", "content-encoding": "Content-Encoding", "content-language": "Content-Language", "content-length": "Content-Length", "content-location": "Content-Location", "content-md5": "Content-MD5", "content-range": "Content-Range", "content-security-policy": "Content-Security-Policy", "content-type": "Content-Type", cookie: "Cookie", dnt: "DNT", date: "Date", etag: "ETag", expect: "Expect", expires: "Expires", from: "From", host: "Host", "if-match": "If-Match", "if-modified-since": "If-Modified-Since", "if-none-match": "If-None-Match", "if-range": "If-Range", "if-unmodified-since": "If-Unmodified-Since", "last-event-id": "Last-Event-ID", "last-modified": "Last-Modified", link: "Link", location: "Location", "max-forwards": "Max-Forwards", negotiate: "Negotiate", origin: "Origin", pragma: "Pragma", "proxy-authenticate": "Proxy-Authenticate", "proxy-authorization": "Proxy-Authorization", range: "Range", referer: "Referer", "retry-after": "Retry-After", "sec-websocket-extensions": "Sec-Websocket-Extensions", "sec-websocket-key": "Sec-Websocket-Key", "sec-websocket-origin": "Sec-Websocket-Origin", "sec-websocket-protocol": "Sec-Websocket-Protocol", "sec-websocket-version": "Sec-Websocket-Version", server: "Server", "set-cookie": "Set-Cookie", "set-cookie2": "Set-Cookie2", "strict-transport-security": "Strict-Transport-Security", tcn: "TCN", te: "TE", trailer: "Trailer", "transfer-encoding": "Transfer-Encoding", upgrade: "Upgrade", "user-agent": "User-Agent", "variant-vary": "Variant-Vary", vary: "Vary", via: "Via", warning: "Warning", "www-authenticate": "WWW-Authenticate", "x-content-duration": "X-Content-Duration", "x-content-security-policy": "X-Content-Security-Policy", "x-dnsprefetch-control": "X-DNSPrefetch-Control", "x-frame-options": "X-Frame-Options", "x-requested-with": "X-Requested-With", "x-surge-skip-scripting": "X-Surge-Skip-Scripting" }; if ("object" == typeof _options.headers) for (let key in _options.headers) headersMap[key] && (_options.headers[headersMap[key]] = _options.headers[key], delete _options.headers[key]); _options.headers && "object" == typeof _options.headers && _options.headers["User-Agent"] || (_options.headers && "object" == typeof _options.headers || (_options.headers = {}), this.isNode ? _options.headers["User-Agent"] = this.pcUserAgent : _options.headers["User-Agent"] = this.iOSUserAgent); let skipScripting = !1; if (("object" == typeof _options.opts && (!0 === _options.opts.hints || !0 === _options.opts["Skip-Scripting"]) || "object" == typeof _options.headers && !0 === _options.headers["X-Surge-Skip-Scripting"]) && (skipScripting = !0), skipScripting || (this.isSurge ? _options.headers["X-Surge-Skip-Scripting"] = !1 : this.isLoon ? _options.headers["X-Requested-With"] = "XMLHttpRequest" : this.isQuanX && ("object" != typeof _options.opts && (_options.opts = {}), _options.opts.hints = !1)), this.isSurge && !skipScripting || delete _options.headers["X-Surge-Skip-Scripting"], !this.isQuanX && _options.hasOwnProperty("opts") && delete _options.opts, this.isQuanX && _options.hasOwnProperty("opts") && delete _options.opts["Skip-Scripting"], "GET" === method && !this.isNode && _options.body) { let qs = Object.keys(_options.body).map(key => void 0 === _options.body ? "" : `${encodeURIComponent(key)}=${encodeURIComponent(_options.body[key])}`).join("&"); _options.url.indexOf("?") < 0 && (_options.url += "?"), _options.url.lastIndexOf("&") + 1 != _options.url.length && _options.url.lastIndexOf("?") + 1 != _options.url.length && (_options.url += "&"), _options.url += qs, delete _options.body } return this.isQuanX ? (_options.hasOwnProperty("body") && "string" != typeof _options.body && (_options.body = JSON.stringify(_options.body)), _options.method = method) : this.isNode ? (delete _options.headers["Accept-Encoding"], "object" == typeof _options.body && ("GET" === method ? (_options.qs = _options.body, delete _options.body) : "POST" === method && (_options.json = !0, _options.body = _options.body))) : this.isJSBox && (_options.header = _options.headers, delete _options.headers), _options } adapterHttpResponse(resp) { let _resp = { body: resp.body, headers: resp.headers, json: () => JSON.parse(_resp.body) }; return resp.hasOwnProperty("statusCode") && resp.statusCode && (_resp.status = resp.statusCode), _resp } get(options, callback) { let _options = this.adapterHttpOptions(options, "GET"); this.logDebug(`HTTP GET: ${JSON.stringify(_options)}`), this.isSurge || this.isLoon ? $httpClient.get(_options, callback) : this.isQuanX ? $task.fetch(_options).then(resp => { resp.status = resp.statusCode, callback(null, resp, resp.body) }, reason => callback(reason.error, null, null)) : this.isNode ? this.node.request.get(_options, (err, resp, data) => { resp = this.adapterHttpResponse(resp), callback(err, resp, data) }) : this.isJSBox && (_options.handler = resp => { let err = resp.error ? JSON.stringify(resp.error) : void 0, data = "object" == typeof resp.data ? JSON.stringify(resp.data) : resp.data; callback(err, resp.response, data) }, $http.get(_options)) } getPromise(options) { return new Promise((resolve, reject) => { magicJS.get(options, (err, resp) => { err ? reject(err) : resolve(resp) }) }) } post(options, callback) { let _options = this.adapterHttpOptions(options, "POST"); if (this.logDebug(`HTTP POST: ${JSON.stringify(_options)}`), this.isSurge || this.isLoon) $httpClient.post(_options, callback); else if (this.isQuanX) $task.fetch(_options).then(resp => { resp.status = resp.statusCode, callback(null, resp, resp.body) }, reason => { callback(reason.error, null, null) }); else if (this.isNode) { let resp = this.node.request.post(_options, callback); resp.status = resp.statusCode, delete resp.statusCode } else this.isJSBox && (_options.handler = resp => { let err = resp.error ? JSON.stringify(resp.error) : void 0, data = "object" == typeof resp.data ? JSON.stringify(resp.data) : resp.data; callback(err, resp.response, data) }, $http.post(_options)) } get http() { return { get: this.getPromise, post: this.post } } done(value = {}) { "undefined" != typeof $done && $done(value) } isToday(day) { if (null == day) return !1; { let today = new Date; return "string" == typeof day && (day = new Date(day)), today.getFullYear() == day.getFullYear() && today.getMonth() == day.getMonth() && today.getDay() == day.getDay() } } isNumber(val) { return "NaN" !== parseFloat(val).toString() } attempt(promise, defaultValue = null) { return promise.then(args => [null, args]).catch(ex => (this.logError(ex), [ex, defaultValue])) } retry(fn, retries = 5, interval = 0, callback = null) { return (...args) => new Promise((resolve, reject) => { function _retry(...args) { Promise.resolve().then(() => fn.apply(this, args)).then(result => { "function" == typeof callback ? Promise.resolve().then(() => callback(result)).then(() => { resolve(result) }).catch(ex => { retries >= 1 ? interval > 0 ? setTimeout(() => _retry.apply(this, args), interval) : _retry.apply(this, args) : reject(ex), retries-- }) : resolve(result) }).catch(ex => { this.logRetry(ex), retries >= 1 && interval > 0 ? setTimeout(() => _retry.apply(this, args), interval) : retries >= 1 ? _retry.apply(this, args) : reject(ex), retries-- }) } _retry.apply(this, args) }) } formatTime(time, fmt = "yyyy-MM-dd hh:mm:ss") { var o = { "M+": time.getMonth() + 1, "d+": time.getDate(), "h+": time.getHours(), "m+": time.getMinutes(), "s+": time.getSeconds(), "q+": Math.floor((time.getMonth() + 3) / 3), S: time.getMilliseconds() }; /(y+)/.test(fmt) && (fmt = fmt.replace(RegExp.$1, (time.getFullYear() + "").substr(4 - RegExp.$1.length))); for (let k in o) new RegExp("(" + k + ")").test(fmt) && (fmt = fmt.replace(RegExp.$1, 1 == RegExp.$1.length ? o[k] : ("00" + o[k]).substr(("" + o[k]).length))); return fmt } now() { return this.formatTime(new Date, "yyyy-MM-dd hh:mm:ss") } today() { return this.formatTime(new Date, "yyyy-MM-dd") } sleep(time) { return new Promise(resolve => setTimeout(resolve, time)) } }(scriptName) } diff --git a/script/tieba/tieba_signin.js b/script/tieba/tieba_signin.js new file mode 100644 index 00000000000..c8b93819472 --- /dev/null +++ b/script/tieba/tieba_signin.js @@ -0,0 +1,236 @@ +/* +百度贴吧签到,增加重试机制,减少签到失败的情况。 +脚本为串行执行,通过设定batchSize的值,实现每批多少个贴吧并行签到一次。 +*/ +const scirptName = "百度贴吧"; +const batchSize = 20; +const retries = 10; // 签到失败重试次数 +const interval = 5000; // 每次重试间隔 +const tiebaCookieKey = "tieba_signin_cookie"; +const tiebeGetCookieRegex1 = /https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login/; +const tiebeGetCookieRegex2 = /^https?:\/\/c\.tieba\.baidu\.com\/c\/s\/channelIconConfig/; +const tiebeGetCookieRegex3 = /https?:\/\/tiebac\.baidu\.com\/c\/u\/follow\/getFoldedMessageUserInfo/; + + +const $ = MagicJS(scirptName, "INFO"); +let currentCookie = ""; + +function addCookie(config) { + config.headers["Cookie"] = currentCookie; + return config; +} +$.http.interceptors.request.use(addCookie); + + +function getTieBaList() { + return new Promise((resolve, reject) => { + $.http.get({ + url: "https://tieba.baidu.com/mo/q/newmoindex", + headers: { + "Content-Type": "application/octet-stream", + "Referer": "https://tieba.baidu.com/index/tbwise/forum", + "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16A366", + }, + body: "" + }).then(resp => { + const obj = resp.body; + if (obj.error === "success") { + $.logger.info(`获取贴吧列表成功,共关注${obj.data.like_forum.length}个贴吧`); + resolve([obj.data.tbs, obj.data.like_forum]) + } + + }).catch(err => { + const errMsg = `获取贴吧列表失败,${err}`; + $.logger.error(); + $.notification.post("获取贴吧列表失败,请查阅日志"); + reject(errMsg); + }) + }) +} + +function tiebaSignIn(tbs, tieba) { + const kw = tieba["forum_name"]; + return new Promise((resolve, reject) => { + if (tieba["is_sign"] === 1) { + resolve(`[${kw}] 重复签到`); + } + else { + let msg = ""; + const body = `tbs=${tbs}&kw=${kw}&ie=utf-8`; + $.http.post({ + url: "https://tieba.baidu.com/sign/add", + headers: { + "Accept": "application/json, text/javascript, */*; q=0.01", + "Accept-Encoding": "gzip,deflate,br", + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", + "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", + "Connection": "keep-alive", + "Host": "tieba.baidu.com", + "Referer": "https://tieba.baidu.com/", + "x-requested-with": "XMLHttpRequest", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36 Edg/84.0.522.63", + }, + body: body + }).then(resp => { + const obj = resp.body; + if (obj.data.errmsg === "success" && obj.data.errno === 0 && obj.data.uinfo.is_sign_in === 1) { + msg = `[${kw}] 签到成功 排名 ${obj.data.uinfo.user_sign_rank} 积分 ${obj.data.uinfo.cont_sign_num}`; + $.logger.info(msg); + resolve(msg); + } else { + if (obj.no === 2150040) { + msg = `[${kw}] 签到失败,need vcode`; + } else if (obj.no === 1011) { + msg = `[${kw}] 未加入此吧或等级不够`; + } + else if (obj.no === 1102) { + msg = `[${kw}] 签到过快`; + } + else if (obj.no === 1101) { + msg = `[${kw}] 重复签到`; + } + else if (obj.no === 1010) { + msg = `[${kw}] 目录出错`; + } + else { + msg = `[${kw}] 签到失败`; + } + $.logger.warning(`${msg}\n${JSON.stringify(obj)}`); + reject(msg); + } + }).catch(err => { + msg = `[${kw}] 签到异常`; + $.logger.warning(`${kw} 签到异常\n${err}`); + reject(msg); + }) + } + }) +} + +function getUserInfo() { + return new Promise((resolve, reject) => { + $.http.get({ + url: "https://tieba.baidu.com/mo/q/sync", + headers: { + "Accept": "application/json, text/javascript, */*; q=0.01", + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", + "Connection": "keep-alive", + "Host": "tieba.baidu.com", + "Referer": "https://tieba.baidu.com/home/main" + } + }).then(resp => { + if (resp.body.no === 0 && resp.body.error === "success") { + resolve(resp.body.data.user_id); + } + }).catch(err => { + $.logger.error(`获取用户信息出现出现异常,${err}`); + reject(err); + }) + }); +} + +async function multiUsersSignIn() { + const allSessionskey = $.data.allSessions(tiebaCookieKey); + if (allSessionskey.length === 0) { + $.logger.error(`没有需要签到的Cookie,请先登录百度贴吧`); + $.notification.post(`没有需要签到的Cookie,请先登录百度贴吧`); + $.done(); + } + $.logger.info(`本次一共需要签到 ${allSessionskey.length} 个Cookies`); + for (let [index, sessionKey] of allSessionskey.entries()) { + currentCookie = $.data.read(tiebaCookieKey, null, sessionKey); + if (!currentCookie) { + continue; + } + else { + $.logger.info(`当前正在进行第 ${index + 1} 个Cookie签到`); + let content = "🥺很遗憾,以下贴吧签到失败:"; + let success = 0; + let failure = 0; + const [tbs, tiebaList] = await $.utils.retry(getTieBaList, retries, interval)(); + const tiebaCount = tiebaList.length; + const cycleNumber = Math.ceil(tiebaList.length / batchSize); + for (let i = 0; i < cycleNumber; i++) { + let batchTiebaPromise = []; + const batchTiebaList = tiebaList.splice(0, batchSize); + for (let tieba of batchTiebaList) { + batchTiebaPromise.push($.utils.retry(tiebaSignIn, retries, interval)(tbs, tieba)); + } + await Promise.all(batchTiebaPromise).then((result) => { + result.forEach((element) => { + if (element.indexOf("签到成功") < 0 && element.indexOf("重复签到") < 0) { + failure += 1; + content += `\n${element}`; + } else { + success += 1; + } + }); + }); + } + $.notification.post(scirptName, `签到${tiebaCount}个,成功${success}个,失败${failure}个!`, !!failure > 0 ? content : "🎉恭喜,所有贴吧签到成功!!"); + $.logger.info(`第 ${index + 1} 个Cookie签到完毕`); + } + } +} + +(async () => { + // 获取百度贴吧Cookie + if ($.isRequest && ( + tiebeGetCookieRegex1.test($.request.url) || + tiebeGetCookieRegex2.test($.request.url) || + tiebeGetCookieRegex3.test($.request.url)) + ) { + const cookie = $.request.headers.Cookie; + currentCookie = cookie; + $.logger.info(`获取百度贴吧Cookies(请勿泄露):\n${cookie}`); + if (!!cookie) { + const userId = await getUserInfo(); + if (!userId) { + userId = "default"; + } + $.logger.info(`获取用户Id:${userId}`); + const result = $.data.update(tiebaCookieKey, cookie, userId); + if (result) { + const msg = "🎈获取百度贴吧Cookie成功"; + $.notification.post(msg); + $.logger.info(msg); + } + else { + $.logger.info("Cookie没有变化,无需更新") + } + const syncQinglong = $.data.read("tieba_sync_qinglong", false); + $.logger.info(`${syncQinglong === true ? "" : "不"}同步Cookie到青龙面板`); + if (syncQinglong === true) { + const msg = "🎈百度贴吧Cookie同步到青龙面板成功"; + const syncQinglong = await $.qinglong.update(tiebaCookieKey, cookie, userId); + if (syncQinglong) { + $.notification.post(msg); + $.logger.info(msg); + } + } + } + } + // 签到 + else { + await multiUsersSignIn(); + } + $.done(); +})(); + +/** + * + * $$\ $$\ $$\ $$$$$\ $$$$$$\ $$$$$$\ + * $$$\ $$$ | \__| \__$$ |$$ __$$\ $$ ___$$\ + * $$$$\ $$$$ | $$$$$$\ $$$$$$\ $$\ $$$$$$$\ $$ |$$ / \__| \_/ $$ | + * $$\$$\$$ $$ | \____$$\ $$ __$$\ $$ |$$ _____| $$ |\$$$$$$\ $$$$$ / + * $$ \$$$ $$ | $$$$$$$ |$$ / $$ |$$ |$$ / $$\ $$ | \____$$\ \___$$\ + * $$ |\$ /$$ |$$ __$$ |$$ | $$ |$$ |$$ | $$ | $$ |$$\ $$ | $$\ $$ | + * $$ | \_/ $$ |\$$$$$$$ |\$$$$$$$ |$$ |\$$$$$$$\\$$$$$$ |\$$$$$$ | \$$$$$$ | + * \__| \__| \_______| \____$$ |\__| \_______|\______/ \______/ \______/ + * $$\ $$ | + * \$$$$$$ | + * \______/ + * +*/ +function MagicJS(e = "MagicJS", t = "INFO") { const r = () => { const e = typeof $loon !== "undefined"; const t = typeof $task !== "undefined"; const n = typeof module !== "undefined"; const r = typeof $httpClient !== "undefined" && !e; const i = typeof $storm !== "undefined"; const o = typeof $environment !== "undefined" && typeof $environment["stash-build"] !== "undefined"; const s = r || e || i || o; const a = typeof importModule !== "undefined"; return { isLoon: e, isQuanX: t, isNode: n, isSurge: r, isStorm: i, isStash: o, isSurgeLike: s, isScriptable: a, get name() { if (e) { return "Loon" } else if (t) { return "QuantumultX" } else if (n) { return "NodeJS" } else if (r) { return "Surge" } else if (a) { return "Scriptable" } else { return "unknown" } }, get build() { if (r) { return $environment["surge-build"] } else if (o) { return $environment["stash-build"] } else if (i) { return $storm.buildVersion } }, get language() { if (r || o) { return $environment["language"] } }, get version() { if (r) { return $environment["surge-version"] } else if (o) { return $environment["stash-version"] } else if (i) { return $storm.appVersion } else if (n) { return process.version } }, get system() { if (r) { return $environment["system"] } else if (n) { return process.platform } }, get systemVersion() { if (i) { return $storm.systemVersion } }, get deviceName() { if (i) { return $storm.deviceName } } } }; const i = (n, e = "INFO") => { let r = e; const i = { SNIFFER: 6, DEBUG: 5, INFO: 4, NOTIFY: 3, WARNING: 2, ERROR: 1, CRITICAL: 0, NONE: -1 }; const o = { SNIFFER: "", DEBUG: "", INFO: "", NOTIFY: "", WARNING: "❗ ", ERROR: "❌ ", CRITICAL: "❌ ", NONE: "" }; const t = (e, t = "INFO") => { if (!(i[r] < i[t.toUpperCase()])) console.log(`[${t}] [${n}]\n${o[t.toUpperCase()]}${e}\n`) }; const s = e => { r = e }; return { setLevel: s, sniffer: e => { t(e, "SNIFFER") }, debug: e => { t(e, "DEBUG") }, info: e => { t(e, "INFO") }, notify: e => { t(e, "NOTIFY") }, warning: e => { t(e, "WARNING") }, error: e => { t(e, "ERROR") }, retry: e => { t(e, "RETRY") } } }; return new class { constructor(e, t) { this._startTime = Date.now(); this.version = "3.0.0"; this.scriptName = e; this.env = r(); this.logger = i(e, t); this.http = typeof MagicHttp === "function" ? MagicHttp(this.env, this.logger) : undefined; this.data = typeof MagicData === "function" ? MagicData(this.env, this.logger) : undefined; this.notification = typeof MagicNotification === "function" ? MagicNotification(this.scriptName, this.env, this.logger, this.http) : undefined; this.utils = typeof MagicUtils === "function" ? MagicUtils(this.env, this.logger) : undefined; this.qinglong = typeof MagicQingLong === "function" ? MagicQingLong(this.env, this.data, this.logger) : undefined; if (typeof this.data !== "undefined") { let e = this.data.read("magic_loglevel"); const n = this.data.read("magic_bark_url"); if (e) { this.logger.setLevel(e.toUpperCase()) } if (n) { this.notification.setBark(n) } } } get isRequest() { return typeof $request !== "undefined" && typeof $response === "undefined" } get isResponse() { return typeof $response !== "undefined" } get isDebug() { return this.logger.level === "DEBUG" } get request() { return typeof $request !== "undefined" ? $request : undefined } get response() { if (typeof $response !== "undefined") { if ($response.hasOwnProperty("status")) $response["statusCode"] = $response["status"]; if ($response.hasOwnProperty("statusCode")) $response["status"] = $response["statusCode"]; return $response } else { return undefined } } done = (e = {}) => { this._endTime = Date.now(); let t = (this._endTime - this._startTime) / 1e3; this.logger.info(`SCRIPT COMPLETED: ${t} S.`); if (typeof $done !== "undefined") { $done(e) } } }(e, t) } function MagicHttp(u, c) { const t = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Mobile/15E148 Safari/604.1"; const n = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36 Edg/84.0.522.59"; let f; if (u.isNode) { const a = require("axios"); f = a.create() } class e { constructor(e = true) { this.handlers = []; this.isRequest = e } use(e, t, n) { this.handlers.push({ fulfilled: e, rejected: t, synchronous: n ? n.synchronous : false, runWhen: n ? n.runWhen : null }); return this.handlers.length - 1 } eject(e) { if (this.handlers[e]) { this.handlers[e] = null } } forEach(t) { this.handlers.forEach(e => { if (e !== null) { t(e) } }) } } function r(e) { let n = { ...e }; if (!!n.params) { if (!u.isNode) { let e = Object.keys(n.params).map(e => { const t = encodeURIComponent(e); n.url = n.url.replace(new RegExp(`${e}=[^&]*`, "ig"), ""); n.url = n.url.replace(new RegExp(`${t}=[^&]*`, "ig"), ""); return `${t}=${encodeURIComponent(n.params[e])}` }).join("&"); if (n.url.indexOf("?") < 0) n.url += "?"; if (!/(&|\?)$/g.test(n.url)) { n.url += "&" } n.url += e; delete n.params; c.debug(`Params to QueryString: ${n.url}`) } } return n } const d = (e, t) => { let n = typeof t === "object" ? { headers: {}, ...t } : { url: t, headers: {} }; if (!n.method) { n["method"] = e } n = r(n); if (n["rewrite"] === true) { if (u.isSurge) { n.headers["X-Surge-Skip-Scripting"] = false; delete n["rewrite"] } else if (u.isQuanX) { n["hints"] = false; delete n["rewrite"] } } if (u.isSurge) { if (n["method"] !== "GET" && n.headers["Content-Type"].indexOf("application/json") >= 0 && n.body instanceof Array) { n.body = JSON.stringify(n.body); c.debug(`Convert Array object to String: ${n.body}`) } } else if (u.isQuanX) { if (n.hasOwnProperty("body") && typeof n["body"] !== "string") n["body"] = JSON.stringify(n["body"]); n["method"] = e } else if (u.isNode) { if (e === "POST" || e === "PUT" || e === "PATCH" || e === "DELETE") { n.data = n.data || n.body } else if (e === "GET") { n.params = n.params || n.body } delete n.body } return n }; const p = (t, n = null) => { if (t) { let e = { ...t, config: t.config || n, status: t.statusCode || t.status, body: t.body || t.data, headers: t.headers || t.header }; if (typeof e.body === "string") { try { e.body = JSON.parse(e.body) } catch { } } delete t.data; return e } else { return t } }; const i = r => { if (!!r) { delete r["Content-Length"]; let e = new Set(["Accept", "Accept-CH", "Accept-Charset", "Accept-Features", "Accept-Encoding", "Accept-Language", "Accept-Ranges", "Access-Control-Allow-Credentials", "Access-Control-Allow-Origin", "Access-Control-Allow-Methods", "Access-Control-Allow-Headers", "Access-Control-Max-Age", "Access-Control-Expose-Headers", "Access-Control-Request-Method", "Access-Control-Request-Headers", "Age", "Allow", "Alternates", "Authorization", "Cache-Control", "Connection", "Content-Encoding", "Content-Language", "ontent-Length", "Content-Location", "Content-Range", "Content-Security-Policy", "Content-Type", "Cookie", "DNT", "Date", "ETag", "Expect", "Expires", "From", "Host", "If-Match", "If-Modified-Since", "If-None-Match", "If-Range", "If-Unmodified-Since", "Last-Event-ID", "Last-Modified", "Link", "Location", "Max-Forwards", "Negotiate", "Origin", "Pragma", "Proxy-Authenticate", "Proxy-Authorization", "Range", "Referer", "Retry-After", "Sec-Websocket-Extensions", "Sec-Websocket-Key", "Sec-Websocket-Origin", "Sec-Websocket-Protocol", "Sec-Websocket-Version", "Server", "Set-Cookie", "Set-Cookie2", "Strict-Transport-Security", "TCN", "TE", "Trailer", "Transfer-Encoding", "Upgrade", "User-Agent", "Variant-Vary", "Vary", "Via", "Warning", "WWW-Authenticate", "X-Content-Duration", "X-Content-Security-Policy", "X-DNSPrefetch-Control", "X-Frame-Options", "X-Requested-With"]); for (let n of Object.keys(r)) { if (!e.has(n)) { for (let t of e) { let e = n.replace(new RegExp(t, "ig"), t); if (n !== e) { r[e] = r[n]; delete r[n]; break } } } } if (!r["User-Agent"]) { if (u.isNode) { r["User-Agent"] = n } else { r["User-Agent"] = t } } return r } return r }; const g = (t, n = null) => { if (!!t && t.status >= 400) { c.debug(`Raise exception when status code is ${t.status}`); let e = { name: "RequestException", message: `Request failed with status code ${t.status}`, config: n || t.config, response: t }; return e } }; const o = { request: new e, response: new e(false) }; let y = []; let h = []; let m = true; function $(e) { if (typeof e === "object" && e["modify"] !== false) { e["headers"] = i(e["headers"]) } e = r(e); return e } function b(e) { try { e = !!e ? p(e) : e; c.sniffer(`HTTP ${e.config["method"].toUpperCase()}:\n${JSON.stringify(e.config)}\nSTATUS CODE:\n${e.status}\nRESPONSE:\n${typeof e.body === "object" ? JSON.stringify(e.body) : e.body}`); const t = g(e); if (!!t) { return Promise.reject(t) } return e } catch (t) { c.error(t); return e } } const S = t => { try { y = []; h = []; o.request.forEach(e => { if (typeof e.runWhen === "function" && e.runWhen(t) === false) { return } m = m && e.synchronous; y.unshift(e.fulfilled, e.rejected) }); o.response.forEach(e => { h.push(e.fulfilled, e.rejected) }) } catch (e) { c.error(`failed to register interceptors: ${e}`) } }; const s = (e, r) => { let i; const t = e.toUpperCase(); r = d(t, r); if (u.isNode) { i = f } else { if (u.isSurgeLike) { i = o => { return new Promise((r, i) => { $httpClient[e.toLowerCase()](o, (t, n, e) => { if (t) { let e = { name: t.name || t, message: t.message || t, stack: t.stack || t, config: o, response: p(n) }; i(e) } else { n.config = o; n.body = e; r(n) } }) }) } } else { i = i => { return new Promise((n, r) => { $task.fetch(i).then(e => { e = p(e, i); const t = g(e, i); if (t) { return Promise.reject(t) } n(e) }).catch(e => { let t = { name: e.message || e.error, message: e.message || e.error, stack: e.error, config: i, response: !!e.response ? p(e.response) : null }; r(t) }) }) } } } let o; S(r); const s = [$, undefined]; const a = [b, undefined]; if (!m) { c.debug("Interceptors are executed in asynchronous mode"); let n = [i, undefined]; Array.prototype.unshift.apply(n, s); Array.prototype.unshift.apply(n, y); Array.prototype.unshift.apply(n, s); n = n.concat(a); n = n.concat(h); o = Promise.resolve(r); while (n.length) { try { let e = n.shift(); let t = n.shift(); if (!u.isNode && r["timeout"] && e === i) { o = l(r) } else { o = o.then(e, t) } } catch (e) { c.error(`request exception: ${e}`) } } return o } else { c.debug("Interceptors are executed in synchronous mode"); Array.prototype.unshift.apply(y, s); y = y.concat([$, undefined]); while (y.length) { let e = y.shift(); let t = y.shift(); try { r = e(r) } catch (e) { t(e); break } } try { if (!u.isNode && r["timeout"]) { o = l(r) } else { o = i(r) } } catch (e) { return Promise.reject(e) } Array.prototype.unshift.apply(h, a); while (h.length) { o = o.then(h.shift(), h.shift()) } return o } function l(n) { try { const e = new Promise((e, t) => { setTimeout(() => { let e = { message: `timeout of ${n["timeout"]}ms exceeded`, config: n }; t(e) }, n["timeout"]) }); return Promise.race([i(n), e]) } catch (e) { c.error(`Request Timeout exception: ${e}`) } } }; return { request: s, interceptors: o, modifyHeaders: i, modifyResponse: p, get: e => { return s("GET", e) }, post: e => { return s("POST", e) }, put: e => { return s("PUT", e) }, patch: e => { return s("PATCH", e) }, delete: e => { return s("DELETE", e) }, head: e => { return s("HEAD", e) }, options: e => { return s("OPTIONS", e) } } } function MagicNotification(o, s, a, l) { let u = null; let c = null; const e = t => { try { let e = t.replace(/\/+$/g, ""); u = `${/^https?:\/\/([^/]*)/.exec(e)[0]}/push`; c = /\/([^\/]+)\/?$/.exec(e)[1] } catch (e) { a.error(`Bark url error: ${e}.`) } }; function t(e = o, t = "", n = "", r = "") { const i = n => { try { let t = {}; if (typeof n === "string") { if (s.isLoon) t = { openUrl: n }; else if (s.isQuanX) t = { "open-url": n }; else if (s.isSurge) t = { url: n } } else if (typeof n === "object") { if (s.isLoon) { t["openUrl"] = !!n["open-url"] ? n["open-url"] : ""; t["mediaUrl"] = !!n["media-url"] ? n["media-url"] : "" } else if (s.isQuanX) { t = !!n["open-url"] || !!n["media-url"] ? n : {} } else if (s.isSurge) { let e = n["open-url"] || n["openUrl"]; t = e ? { url: e } : {} } } return t } catch (e) { a.error(`Failed to convert notification option, ${e}`) } return n }; r = i(r); if (arguments.length == 1) { e = o; t = "", n = arguments[0] } a.notify(`title:${e}\nsubTitle:${t}\nbody:${n}\noptions:${typeof r === "object" ? JSON.stringify(r) : r}`); if (s.isSurge) { $notification.post(e, t, n, r) } else if (s.isLoon) { if (!!r) $notification.post(e, t, n, r); else $notification.post(e, t, n) } else if (s.isQuanX) { $notify(e, t, n, r) } if (u && c) { f(e, t, n) } } function n(e = o, t = "", n = "", r = "") { if (a.level === "DEBUG") { if (arguments.length == 1) { e = o; t = "", n = arguments[0] } this.notify(e, t, n, r) } } function f(e = o, t = "", n = "", r = "") { if (typeof l === "undefined" || typeof l.post === "undefined") { throw "Bark notification needs to import MagicHttp module." } let i = { url: u, headers: { "Content-Type": "application/json; charset=utf-8" }, body: { title: e, body: t ? `${t}\n${n}` : n, device_key: c } }; l.post(i).catch(e => { a.error(`Bark notify error: ${e}`) }) } return { post: t, debug: n, bark: f, setBark: e } } function MagicData(s, a) { let l = { fs: undefined, data: {} }; if (s.isNode) { l.fs = require("fs"); try { l.fs.accessSync("./magic.json", l.fs.constants.R_OK | l.fs.constants.W_OK) } catch (e) { l.fs.writeFileSync("./magic.json", "{}", { encoding: "utf8" }) } l.data = require("./magic.json") } const u = (e, t) => { if (typeof t === "object") { return false } else { return e === t } }; const c = e => { if (e === "true") { return true } else if (e === "false") { return false } else if (typeof e === "undefined") { return null } else { return e } }; const f = (e, t, n, r) => { if (n) { try { if (typeof e === "string") e = JSON.parse(e); if (e["magic_session"] === true) { e = e[n] } else { e = null } } catch { e = null } } if (typeof e === "string" && e !== "null") { try { e = JSON.parse(e) } catch { } } if (r === false && !!e && e["magic_session"] === true) { e = null } if ((e === null || typeof e === "undefined") && t !== null && typeof t !== "undefined") { e = t } e = c(e); return e }; const o = t => { if (typeof t === "string") { let e = {}; try { e = JSON.parse(t); const n = typeof e; if (n !== "object" || e instanceof Array || n === "bool" || e === null) { e = {} } } catch { } return e } else if (t instanceof Array || t === null || typeof t === "undefined" || t !== t || typeof t === "boolean") { return {} } else { return t } }; const d = (e, t = null, n = "", r = false, i = null) => { let o = i || l.data; if (!!o && typeof o[e] !== "undefined" && o[e] !== null) { val = o[e] } else { val = !!n ? {} : null } val = f(val, t, n, r); return val }; const p = (e, t = null, n = "", r = false, i = null) => { let o = ""; if (i || s.isNode) { o = d(e, t, n, r, i) } else { if (s.isSurgeLike) { o = $persistentStore.read(e) } else if (s.isQuanX) { o = $prefs.valueForKey(e) } o = f(o, t, n, r) } a.debug(`READ DATA [${e}]${!!n ? `[${n}]` : ""} <${typeof o}>\n${JSON.stringify(o)}`); return o }; const g = (t, n, r = "", e = null) => { let i = e || l.data; i = o(i); if (!!r) { let e = o(i[t]); e["magic_session"] = true; e[r] = n; i[t] = e } else { i[t] = n } if (e !== null) { e = i } return i }; const y = (e, t, n = "", r = null) => { if (typeof t === "undefined" || t !== t) { return false } if (!s.isNode && (typeof t === "boolean" || typeof t === "number")) { t = String(t) } let i = ""; if (r || s.isNode) { i = g(e, t, n, r) } else { if (!n) { i = t } else { if (s.isSurgeLike) { i = !!$persistentStore.read(e) ? $persistentStore.read(e) : i } else if (s.isQuanX) { i = !!$prefs.valueForKey(e) ? $prefs.valueForKey(e) : i } i = o(i); i["magic_session"] = true; i[n] = t } } if (!!i && typeof i === "object") { i = JSON.stringify(i, "", "\t") } a.debug(`WRITE DATA [${e}]${n ? `[${n}]` : ""} <${typeof t}>\n${JSON.stringify(t)}`); if (!r) { if (s.isSurgeLike) { return $persistentStore.write(i, e) } else if (s.isQuanX) { return $prefs.setValueForKey(i, e) } else if (s.isNode) { try { l.fs.writeFileSync("./magic.json", i); return true } catch (e) { a.error(e); return false } } } return true }; const e = (t, n, r, i = u, o = null) => { n = c(n); const e = p(t, null, r, false, o); if (i(e, n) === true) { return false } else { const s = y(t, n, r, o); let e = p(t, null, r, false, o); if (i === u && typeof e === "object") { return s } return i(n, e) } }; const h = (e, t, n) => { let r = n || l.data; r = o(r); if (!!t) { obj = o(r[e]); delete obj[t]; r[e] = obj } else { delete r[e] } if (!!n) { n = r } return r }; const t = (e, t = "", n = null) => { let r = {}; if (n || s.isNode) { r = h(e, t, n); if (!n) { l.fs.writeFileSync("./magic.json", JSON.stringify(r)) } else { n = r } } else { if (!t) { if (s.isStorm) { return $persistentStore.remove(e) } else if (s.isSurgeLike) { return $persistentStore.write(null, e) } else if (s.isQuanX) { return $prefs.removeValueForKey(e) } } else { if (s.isSurgeLike) { r = $persistentStore.read(e) } else if (s.isQuanX) { r = $prefs.valueForKey(e) } r = o(r); delete r[t]; const i = JSON.stringify(r); y(e, i) } } a.debug(`DELETE KEY [${e}]${!!t ? `[${t}]` : ""}`) }; const n = (e, t = null) => { let n = []; let r = p(e, null, null, true, t); r = o(r); if (r["magic_session"] !== true) { n = [] } else { n = Object.keys(r).filter(e => e !== "magic_session") } a.debug(`READ ALL SESSIONS [${e}] <${typeof n}>\n${JSON.stringify(n)}`); return n }; return { read: p, write: y, del: t, update: e, allSessions: n, defaultValueComparator: u, convertToObject: o } } function MagicUtils(r, u) { const e = (o, s = 5, a = 0, l = null) => { return (...e) => { return new Promise((n, r) => { function i(...t) { Promise.resolve().then(() => o.apply(this, t)).then(e => { if (typeof l === "function") { Promise.resolve().then(() => l(e)).then(() => { n(e) }).catch(e => { if (s >= 1) { if (a > 0) setTimeout(() => i.apply(this, t), a); else i.apply(this, t) } else { r(e) } s-- }) } else { n(e) } }).catch(e => { u.error(e); if (s >= 1 && a > 0) { setTimeout(() => i.apply(this, t), a) } else if (s >= 1) { i.apply(this, t) } else { r(e) } s-- }) } i.apply(this, e) }) } }; const t = (e, t = "yyyy-MM-dd hh:mm:ss") => { let n = { "M+": e.getMonth() + 1, "d+": e.getDate(), "h+": e.getHours(), "m+": e.getMinutes(), "s+": e.getSeconds(), "q+": Math.floor((e.getMonth() + 3) / 3), S: e.getMilliseconds() }; if (/(y+)/.test(t)) t = t.replace(RegExp.$1, (e.getFullYear() + "").substr(4 - RegExp.$1.length)); for (let e in n) if (new RegExp("(" + e + ")").test(t)) t = t.replace(RegExp.$1, RegExp.$1.length == 1 ? n[e] : ("00" + n[e]).substr(("" + n[e]).length)); return t }; const n = () => { return t(new Date, "yyyy-MM-dd hh:mm:ss") }; const i = () => { return t(new Date, "yyyy-MM-dd") }; const o = t => { return new Promise(e => setTimeout(e, t)) }; const s = (e, t = null) => { if (r.isNode) { const n = require("assert"); if (t) n(e, t); else n(e) } else { if (e !== true) { let e = `AssertionError: ${t || "The expression evaluated to a falsy value"}`; u.error(e) } } }; return { retry: e, formatTime: t, now: n, today: i, sleep: o, assert: s } } function MagicQingLong(e, l, i) { let o = ""; let s = ""; let a = ""; let u = ""; let c = ""; let t = ""; const f = "magic.json"; const n = 3e3; const d = MagicHttp(e, i); const r = (e, t, n, r, i) => { o = e; a = t; u = n; s = r; c = i }; function p(e) { o = o || l.read("magic_qlurl"); t = t || l.read("magic_qltoken"); return e } function g(e) { if (!o) { o = l.read("magic_qlurl") } if (e.url.indexOf(o) < 0) { e.url = `${o}${e.url}` } return { ...e, timeout: n } } function y(e) { e.params = { ...e.params, t: Date.now() }; return e } function h(e) { t = t || l.read("magic_qltoken"); if (t) { e.headers["Authorization"] = `Bearer ${t}` } return e } function m(e) { a = a || l.read("magic_qlclient"); if (!!a) { e.url = e.url.replace("/api/", "/open/") } return e } async function $(e) { try { const t = e.message || e.error || JSON.stringify(e); if ((t.indexOf("NSURLErrorDomain") >= 0 && t.indexOf("-1012") >= 0 || !!e.response && e.response.status === 401) && (!!e.config && e.config.refreshToken !== true)) { i.warning(`Qinglong panel token has expired`); await b(); e.config["refreshToken"] = true; return await d.request(e.config.method, e.config) } else { return Promise.reject(e) } } catch (e) { return Promise.reject(e) } } d.interceptors.request.use(p, undefined); d.interceptors.request.use(g, undefined); d.interceptors.request.use(m, undefined, { runWhen: e => { return e.url.indexOf("api/user/login") < 0 && e.url.indexOf("open/auth/token") < 0 } }); d.interceptors.request.use(h, undefined, { runWhen: e => { return e.url.indexOf("api/user/login") < 0 && e.url.indexOf("open/auth/token") < 0 } }); d.interceptors.request.use(y, undefined, { runWhen: e => { return e.url.indexOf("open/auth/token") < 0 && e.url.indexOf("t=") < 0 } }); d.interceptors.response.use(undefined, $); async function b() { a = a || l.read("magic_qlclient"); u = u || l.read("magic_qlsecrt"); s = s || l.read("magic_qlname"); c = c || l.read("magic_qlpwd"); if (o && a && u) { await d.get({ url: `/open/auth/token`, headers: { "Content-Type": "application/json" }, params: { client_id: a, client_secret: u } }).then(e => { i.info("Log in to Qinglong panel successfully"); t = e.body.data.token; l.update("magic_qltoken", t); return t }).catch(e => { i.error(`Failed to log in to Qinglong panel.\n${e.message}`) }) } else if (o && s && c) { await d.post({ url: `/api/user/login`, headers: { "Content-Type": "application/json" }, body: { username: s, password: c } }).then(e => { i.info("Log in to Qinglong panel successfully"); t = e.body.data.token; l.update("magic_qltoken", t); return t }).catch(e => { i.error(`Failed to log in to Qinglong panel.\n${e.message}`) }) } } async function S(t, n, r = null) { o = o || l.read("magic_qlurl"); if (r === null) { let e = await N([{ name: t, value: n }]); if (!!e && e.length === 1) { return e[0] } } else { d.put({ url: `/api/envs`, headers: { "Content-Type": "application/json" }, body: { name: t, value: n, id: r } }).then(e => { if (e.body.code === 200) { i.debug(`QINGLONG UPDATE ENV ${t} <${typeof n}> (${r})\n${JSON.stringify(n)}`); return true } else { i.error(`Failed to update Qinglong panel environment variable.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to update Qinglong panel environment variable.\n${e.message}`); return false }) } } async function N(e) { let t = []; await d.post({ url: `/api/envs`, headers: { "Content-Type": "application/json" }, body: e }).then(e => { if (e.body.code === 200) { e.body.data.forEach(e => { i.debug(`QINGLONG ADD ENV ${e.name} <${typeof e.value}> (${e.id})\n${JSON.stringify(e)}`); t.push(e.id) }) } else { i.error(`Failed to add Qinglong panel environment variable.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to add Qinglong panel environment variable.\n${e.message}`) }); return t } async function v(t) { return await d.delete({ url: `/api/envs`, headers: { Accept: "application/json", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", Connection: "keep-alive", "Content-Type": "application/json;charset=UTF-8", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30" }, body: t }).then(e => { if (e.body.code === 200) { i.debug(`QINGLONG DELETE ENV IDS: ${t}`); return true } else { i.error(`Failed to delete QingLong envs.\n${JSON.stringify(e)}`); return false } }).catch(e => { i.error(`Failed to delete QingLong envs.\n${e.message}`) }) } async function O(n = null, e = "") { let r = []; await d.get({ url: `/api/envs`, headers: { "Content-Type": "application/json" }, params: { searchValue: e } }).then(e => { if (e.body.code === 200) { const t = e.body.data; if (!!n) { let e = []; for (const e of t) { if (e.name === n) { r.push(e) } } r = e } r = t } else { i.error(`Failed to get environment variables from Qinglong panel.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to get environment variables from Qinglong panel.\n${JSON.stringify(e)}`) }); return r } async function E(e) { let t = null; const n = await O(); for (const r of n) { if (r.id === e) { t = r; break } } return t } async function T(t) { let n = false; await d.put({ url: `/api/envs/disable`, headers: { Accept: "application/json", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", Connection: "keep-alive", "Content-Type": "application/json;charset=UTF-8", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30" }, body: t }).then(e => { if (e.body.code === 200) { i.debug(`QINGLONG DISABLED ENV IDS: ${t}`); n = true } else { i.error(`Failed to disable QingLong envs.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to disable QingLong envs.\n${e.message}`) }); return n } async function w(t) { let n = false; await d.put({ url: `/api/envs/enable`, headers: { Accept: "application/json", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", Connection: "keep-alive", "Content-Type": "application/json;charset=UTF-8", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30" }, body: t }).then(e => { if (e.body.code === 200) { i.debug(`QINGLONG ENABLED ENV IDS: ${t}`); n = true } else { i.error(`Failed to enable QingLong envs.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to enable QingLong envs.\n${e.message}`) }); return n } async function C(e, t = "", n = "") { let r = false; await d.post({ url: `/api/scripts`, headers: { "Content-Type": "application/json" }, body: { filename: e, path: t, content: n } }).then(e => { if (e.body.code === 200) { r = true } else { i.error(`Failed to add script content from Qinglong panel.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to add script content from Qinglong panel.\n${e.message}`) }); return r } async function A(e, t = "") { let n = ""; await d.get({ url: `/api/scripts/${e}`, params: { path: t } }).then(e => { if (e.body.code === 200) { n = e.body.data } else { i.error(`Failed to read script content from Qinglong panel.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to read script content from Qinglong panel.\n${e.message}`) }); return n } async function k(e, t = "", n = "") { let r = false; await d.put({ url: `/api/scripts`, headers: { "Content-Type": "application/json" }, body: { filename: e, path: t, content: n } }).then(e => { if (e.body.code === 200) { r = true } else { i.error(`Failed to read script content from Qinglong panel.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to read script content from Qinglong panel.\n${e.message}`) }); return r } async function L(e, t = "") { let n = false; await d.delete({ url: `/api/scripts`, headers: { "Content-Type": "application/json" }, body: { filename: e, path: t } }).then(e => { if (e.body.code === 200) { n = true } else { i.error(`Failed to read script content from Qinglong panel.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to read script content from Qinglong panel.\n${e.message}`) }); return n } async function F(e, t, n = "") { let r = await A(f, ""); let i = l.convertToObject(r); let o = l.write(e, t, n, i); r = JSON.stringify(i, "", "\t"); let s = await k(f, "", r); return s && o } async function j(e, t, n, r = l.defaultValueComparator) { let i = await A(f, ""); let o = l.convertToObject(i); const s = l.update(e, t, n, r, o); let a = false; if (s === true) { i = JSON.stringify(o, "", "\t"); a = await k(f, "", i) } return s && a } async function M(e, t, n = "") { let r = await A(f, ""); let i = l.convertToObject(r); const o = l.read(e, t, n, false, i); return o } async function R(e, t = "") { let n = await A(f, ""); let r = l.convertToObject(n); const i = l.del(e, t, r); n = JSON.stringify(r, "", "\t"); const o = await k(f, "", n); return i && o } async function q(e) { let t = await A(f, ""); let n = l.convertToObject(t); const r = l.allSessions(e, n); return r } return { init: r, getToken: b, setEnv: S, setEnvs: N, getEnv: E, getEnvs: O, delEnvs: v, disableEnvs: T, enbleEnvs: w, addScript: C, getScript: A, editScript: k, delScript: L, write: F, read: M, del: R, update: j, allSessions: q } } \ No newline at end of file diff --git a/script/tieba/tieba_checkin.lnplugin b/script/tieba/tieba_signin.lnplugin similarity index 65% rename from script/tieba/tieba_checkin.lnplugin rename to script/tieba/tieba_signin.lnplugin index dd1faecfba7..a693fbaedf9 100644 --- a/script/tieba/tieba_checkin.lnplugin +++ b/script/tieba/tieba_signin.lnplugin @@ -6,10 +6,10 @@ #!icon= https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba.png [Script] -http-request ^https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.js,tag=贴吧_获取Cookie1 -http-request ^https?:\/\/c\.tieba\.baidu\.com\/c\/s\/channelIconConfig script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.js,tag=贴吧_新版Cookie2 -http-request ^https?:\/\/tiebac\.baidu\.com\/c\/u\/follow\/getFoldedMessageUserInfo script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.js,tag=贴吧_新版Cookie3 -cron "30 9 * * *" script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.js,timeout=60,tag=贴吧_每日签到 +http-request ^https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.js,tag=贴吧_获取Cookie1 +http-request ^https?:\/\/c\.tieba\.baidu\.com\/c\/s\/channelIconConfig script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.js,tag=贴吧_新版Cookie2 +http-request ^https?:\/\/tiebac\.baidu\.com\/c\/u\/follow\/getFoldedMessageUserInfo script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.js,tag=贴吧_新版Cookie3 +cron "30 9 * * *" script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.js,timeout=60,tag=贴吧_每日签到 [MITM] hostname = c.tieba.baidu.com, tiebac.baidu.com \ No newline at end of file diff --git a/script/tieba/tieba_checkin.qxrewrite b/script/tieba/tieba_signin.qxrewrite similarity index 64% rename from script/tieba/tieba_checkin.qxrewrite rename to script/tieba/tieba_signin.qxrewrite index 3f754b24aa8..498a2492992 100644 --- a/script/tieba/tieba_checkin.qxrewrite +++ b/script/tieba/tieba_signin.qxrewrite @@ -1,7 +1,7 @@ # 百度贴吧每日自动签到 -^https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login url script-request-header https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.js -^https?:\/\/c\.tieba\.baidu\.com\/c\/s\/channelIconConfig url script-request-header https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.js -^https?:\/\/tiebac\.baidu\.com\/c\/u\/follow\/getFoldedMessageUserInfo url script-request-header https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.js +^https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login url script-request-header https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.js +^https?:\/\/c\.tieba\.baidu\.com\/c\/s\/channelIconConfig url script-request-header https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.js +^https?:\/\/tiebac\.baidu\.com\/c\/u\/follow\/getFoldedMessageUserInfo url script-request-header https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.js -hostname = c.tieba.baidu.com, tiebac.baidu.com \ No newline at end of file +hostname = c.tieba.baidu.com \ No newline at end of file diff --git a/script/tieba/tieba_checkin.sgmodule b/script/tieba/tieba_signin.sgmodule similarity index 79% rename from script/tieba/tieba_checkin.sgmodule rename to script/tieba/tieba_signin.sgmodule index 348de2d0996..4f4002c1d07 100644 --- a/script/tieba/tieba_checkin.sgmodule +++ b/script/tieba/tieba_signin.sgmodule @@ -3,10 +3,10 @@ #!system=ios [Script] -贴吧_每日签到 = type=cron,cronexp=30 9 * * *,timeout=60,script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.js -贴吧_获取cookie1 = type=http-request,pattern=^https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login,script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.js -贴吧_获取cookie2 = type=http-request,pattern=^https?:\/\/c\.tieba\.baidu\.com\/c\/s\/channelIconConfig,script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.js -贴吧_获取cookie3 = type=http-request,pattern=^https?:\/\/tiebac\.baidu\.com\/c\/u\/follow\/getFoldedMessageUserInfo,script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_checkin.js +贴吧_每日签到 = type=cron,cronexp=30 9 * * *,timeout=60,script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.js +贴吧_获取cookie1 = type=http-request,pattern=^https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login,script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.js +贴吧_获取cookie2 = type=http-request,pattern=^https?:\/\/c\.tieba\.baidu\.com\/c\/s\/channelIconConfig,script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.js +贴吧_获取cookie3 = type=http-request,pattern=^https?:\/\/tiebac\.baidu\.com\/c\/u\/follow\/getFoldedMessageUserInfo,script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.js [MITM] hostname = %APPEND% c.tieba.baidu.com, tiebac.baidu.com \ No newline at end of file