├── .eslintrc.json ├── .github ├── FUNDING.yml ├── server.png └── workflows │ └── node.js.yml ├── .gitignore ├── LICENSE ├── README.md ├── bot.js ├── env.js ├── library_task.js ├── package.json ├── sendNotify.js ├── smzdm_checkin.js ├── smzdm_lottery.js ├── smzdm_task.js └── smzdm_testing.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "commonjs": true, 4 | "es2021": true, 5 | "node": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "parserOptions": { 9 | "ecmaVersion": "latest" 10 | }, 11 | "globals": { 12 | "$persistentStore": true, 13 | "$prefs": true, 14 | "$httpClient": true, 15 | "$task": true, 16 | "$notification": true, 17 | "$done": true, 18 | "$notify": true 19 | }, 20 | "rules": { 21 | "indent": ["warn", 2, {"SwitchCase": 1}], 22 | "brace-style": [1, "stroustrup", {"allowSingleLine": true}], 23 | "comma-style": [1, "last"], 24 | "default-case": 2, 25 | "no-floating-decimal": 2, 26 | "space-before-function-paren": [1, {"anonymous": "never", "named": "never", "asyncArrow": "always"}], 27 | "keyword-spacing": [2, {"after": true}], 28 | "space-before-blocks": 1, 29 | "wrap-iife": [2, "any"], 30 | "no-alert": 2, 31 | "curly": [2, "all"], 32 | "no-empty": [2, {"allowEmptyCatch": true}], 33 | "no-obj-calls": 2, 34 | "no-unused-vars": [1, {"vars": "local", "args": "after-used"}], 35 | "no-invalid-regexp": 2, 36 | "comma-dangle": [1, "never"], 37 | "no-undef": 2, 38 | "no-new": 2, 39 | "no-extra-semi": 0, 40 | "no-debugger": 2, 41 | "no-caller": 1, 42 | "no-unreachable": 2, 43 | "no-multi-str": 1, 44 | "no-mixed-spaces-and-tabs": 1, 45 | "no-trailing-spaces": 1, 46 | "space-infix-ops": 1, 47 | "no-with": 2, 48 | "dot-notation": 1, 49 | "semi-spacing": 1, 50 | "key-spacing": [1, {"beforeColon": false, "afterColon": true, "mode": "minimum"}], 51 | "space-in-parens": [1, "never"], 52 | "prefer-const": 2, 53 | "no-control-regex": 0, 54 | "no-var": 1 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 15 | -------------------------------------------------------------------------------- /.github/server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hex-ci/smzdm_script/8a20f51a5d2fcb69afc4c1ec03e404864be40f06/.github/server.png -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [14.x, 16.x, 18.x] 20 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | - run: npm i 25 | - name: Use Node.js ${{ matrix.node-version }} 26 | uses: actions/setup-node@v4 27 | with: 28 | node-version: ${{ matrix.node-version }} 29 | cache: 'npm' 30 | - run: npm run lint 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .idea 59 | .env 60 | 61 | dist 62 | output 63 | 64 | build/.cache 65 | build/*.json 66 | 67 | .fuse_hidden* 68 | 69 | .stfolder 70 | .stignore 71 | 72 | package-lock.json 73 | 74 | .vscode/ 75 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Hex 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 自用脚本 for 青龙面板 2 | 3 | [![Node.js CI](https://github.com/hex-ci/smzdm_script/actions/workflows/node.js.yml/badge.svg)](https://github.com/hex-ci/smzdm_script/actions/workflows/node.js.yml) 4 | 5 | ## 脚本内容 6 | 7 | * 每日签到 8 | * 每日抽奖 9 | * 生活频道转盘抽奖 10 | * 值会员转盘抽奖 11 | * 每日任务(指的是签到页面中的任务) 12 | * 浏览文章 13 | * 收藏文章 14 | * 点赞文章 15 | * 评论文章 16 | * 分享 17 | * 抽奖 18 | * 免费抽奖 19 | * 5 碎银子抽奖 20 | * 关注用户 21 | * 关注栏目 22 | * 关注品牌 23 | * 限时累计活动 24 | * 全民众测能量值任务 25 | 26 | ## 使用方法 27 | 28 | ### 青龙拉库 29 | 30 | ```bash 31 | ql repo https://github.com/hex-ci/smzdm_script.git "smzdm_" "" "env.js|bot.js|sendNotify.js|library_" "main" 32 | ``` 33 | 34 | 建议自行更改青龙面板的脚本执行时间 35 | 36 | ### NodeJS 依赖 37 | 38 | * crypto-js 39 | 40 | ### 抓包 41 | 42 | 建议使用 Android 手机抓包(iOS 也可以)域名为 `user-api.smzdm.com` 的任意链接,把**所有** Cookie 取出来放到青龙面板的 `SMZDM_COOKIE` 环境变量中,多用户请添加多个同名环境变量或者用 `&` 符号分隔。 43 | 44 | 如果手机实在抓不到,也可以用浏览器的 Cookie,但是强烈建议使用手机端的 Cookie。 45 | 46 | #### 抓包教程 47 | 48 | 以下教程请大家自行尝试,本人没有亲自尝试,如有问题可以进群交流。 49 | 50 | * https://www.jianshu.com/p/5e5524868442 51 | * https://www.zqh.plus/2022/03/19/Android-Capture/ 52 | * https://jishuin.proginn.com/p/763bfbd5f92e 53 | * https://juejin.cn/post/7091524392005566471 54 | * https://www.caq98i.top/article/?page=38 55 | 56 | ### 青龙环境变量 57 | 58 | 环境变量请使用环境变量列表直接添加,不要使用 `export xxx=""` 这种方式添加环境变量。 59 | 60 | * `SMZDM_COOKIE`: 抓包抓到的 Cookie 内容,需要所有 Cookie 内容,多用户可以用 `&` 分隔,或者使用多个同名环境变量。 61 | * `SMZDM_SK`: 这个值是可选值,会自动计算,如果你一定想用自己的,可以抓取,是从安卓 App 的 `https://user-api.smzdm.com/checkin` 请求参数中抓包抓到的,多用户可以用 `&` 分隔,或者使用多个同名环境变量,顺序要保持与 `SMZDM_COOKIE` 多用户顺序一致。 62 | * `SMZDM_USER_AGENT_APP`: 这个值是可选值,是指 APP 的 User-Agent,从 APP 的 API 请求头中抓包得到,建议抓取 Android 的 User-Agent,不填使用脚本默认值。 63 | * `SMZDM_USER_AGENT_WEB`: 这个值是可选值,是指 APP 中访问网页的 User-Agent,一般在 APP 内的转盘网页中抓包得到,建议抓取 Android 的 User-Agent,不填使用脚本默认值。 64 | * `SMZDM_COMMENT`: 如果要完成评论文章的任务请设置这个环境变量,环境变量的内容是评论的文案,文案要大于 10 个汉字,建议用比较个性化的文案,脚本发布评论后会删除这条评论,但是为防止删除失败的情况,请尽量用好一点的文案,防止被判定为恶意灌水。 65 | * `SMZDM_CROWD_SILVER_5`: 每日抽奖任务默认只进行免费抽奖,如要进行 5 碎银子的抽奖,请设置这个环境变量的值为 `yes`,请注意,只有在没有免费抽奖的时候,才会执行非免费抽奖,而且,这个抽奖不是转盘抽奖。 66 | * `SMZDM_CROWD_KEYWORD`: 抽奖关键词,执行非免费抽奖时,会优先选择包含此关键词的抽奖,如果未找到包含此关键词的抽奖,则会随机选择一个。 67 | * `SMZDM_TASK_TESTING`: 是否运行全民众测能量值任务,如要运行此任务,请设置这个环境变量的值为 `yes`,否则不运行。 68 | 69 | ## 交流群 70 | 71 | https://t.me/smzdm_script 72 | 73 | ## 推荐🐔场 74 | 75 | 自用🐔场,稳定,线路多,速度快,[点这里注册](https://xs-us.xyz/register?code=GMsubu2k) 76 | 77 | ## 其它说明 78 | 79 | 使用本脚本可能会造成你的账号临时或永久封禁,请自行评估是否使用本脚本。 80 | 81 | ## 注意事项 82 | 83 | 本仓库发布的脚本及其中涉及的任何解密分析脚本,仅用于测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。本项目内所有资源文件,禁止任何公众号、自媒体进行任何形式的转载、发布。您必须在下载后的 24 小时内从计算机或手机中完全删除以上内容。 84 | -------------------------------------------------------------------------------- /bot.js: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto'); 2 | const got = require('got'); 3 | 4 | // ------------------------------------ 5 | 6 | const APP_VERSION = '10.4.26'; 7 | const APP_VERSION_REV = '866'; 8 | 9 | const DEFAULT_USER_AGENT_APP = `smzdm_android_V${APP_VERSION} rv:${APP_VERSION_REV} (Redmi Note 3;Android10.0;zh)smzdmapp`; 10 | const DEFAULT_USER_AGENT_WEB = `Mozilla/5.0 (Linux; Android 10.0; Redmi Build/Redmi Note 3; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/95.0.4638.74 Mobile Safari/537.36 smzdm_android_V${APP_VERSION} rv:${APP_VERSION_REV} (Redmi;Android10.0;zh) jsbv_1.0.0 webv_2.0 smzdmapp`; 11 | 12 | const SIGN_KEY = 'apr1$AwP!wRRT$gJ/q.X24poeBInlUJC'; 13 | 14 | // ------------------------------------ 15 | 16 | const reVersion = /(smzdm_android_V|smzdm\s|iphone_smzdmapp\/)([\d.]+)/i; 17 | const reRev = /rv:([\d.]+)/i; 18 | 19 | const randomStr = (len = 18) => { 20 | const char = '0123456789'; 21 | let str = ''; 22 | 23 | for (let i = 0; i < len; i++) { 24 | str += char.charAt(Math.floor(Math.random() * char.length)); 25 | } 26 | 27 | return str; 28 | }; 29 | 30 | const parseJSON = (str) => { 31 | try { 32 | return JSON.parse(str); 33 | } 34 | catch (e) { 35 | return {}; 36 | } 37 | }; 38 | 39 | const removeTags = (str) => str.replace(/<[^<]+?>/g, ''); 40 | 41 | // 添加公共参数并签名数据 42 | const signFormData = (data) => { 43 | const newData = { 44 | weixin: 1, 45 | basic_v: 0, 46 | f: 'android', 47 | v: APP_VERSION, 48 | time: `${Math.round(new Date().getTime() / 1000)}000`, 49 | ...data 50 | }; 51 | 52 | const keys = Object.keys(newData).filter(key => newData[key] !== '').sort(); 53 | const signData = keys.map(key => `${key}=${String(newData[key]).replace(/\s+/, '')}`).join('&'); 54 | const sign = crypto.createHash('md5').update(`${signData}&key=${SIGN_KEY}`).digest('hex').toUpperCase(); 55 | 56 | return { 57 | ...newData, 58 | sign 59 | }; 60 | }; 61 | 62 | // 公共请求函数 63 | const requestApi = async (url, inputOptions = {}) => { 64 | const options = { ...inputOptions }; 65 | 66 | if (!options.method) { 67 | options.method = 'get'; 68 | } 69 | 70 | if (!options.data) { 71 | options.data = {}; 72 | } 73 | 74 | Object.keys(options.data).forEach(key => options.data[key] === undefined && delete options.data[key]); 75 | 76 | if (options.sign !== false) { 77 | options.data = signFormData(options.data); 78 | } 79 | 80 | const gotOptions = { 81 | method: options.method.toUpperCase(), 82 | headers: options.headers, 83 | retry: { 84 | limit: 2, 85 | methods: [ 86 | 'GET', 87 | 'POST' 88 | ], 89 | statusCodes: [ 90 | ], 91 | errorCodes: [ 92 | 'ECONNRESET', 93 | 'EAI_AGAIN' 94 | ] 95 | } 96 | }; 97 | 98 | if (options.method === 'get') { 99 | gotOptions.searchParams = options.data; 100 | } 101 | else { 102 | gotOptions.form = options.data; 103 | } 104 | 105 | return got(url, gotOptions).then((response) => { 106 | const data = options.parseJSON === false ? response.body : parseJSON(response.body); 107 | 108 | if (options.debug) { 109 | console.log('------------------------'); 110 | console.log(url); 111 | console.log('------------------------'); 112 | console.log(JSON.stringify(gotOptions, null, 2)); 113 | console.log('------------------------'); 114 | console.log(options.parseJSON === false ? response.body : JSON.stringify(data, null, 2)); 115 | console.log('------------------------'); 116 | } 117 | 118 | return { 119 | isSuccess: options.parseJSON === false ? true : (data.error_code == '0'), 120 | response: options.parseJSON === false ? response.body : JSON.stringify(data, null, 2), 121 | data 122 | }; 123 | }).catch((error) => { 124 | if (options.debug) { 125 | console.log('------------------------'); 126 | console.log(url); 127 | console.log('------------------------'); 128 | console.log(JSON.stringify(gotOptions, null, 2)); 129 | console.log('------------------------'); 130 | console.log(error); 131 | console.log('------------------------'); 132 | } 133 | 134 | return { 135 | isSuccess: false, 136 | response: error, 137 | data: error 138 | }; 139 | }) 140 | }; 141 | 142 | const updateCookie = (cookie, name, value) => { 143 | const re = new RegExp(`(^|;)${name}=[^;]+;`, 'ig'); 144 | 145 | return cookie.replace(re, `$1${name}=${encodeURIComponent(value)};`); 146 | }; 147 | 148 | const getEnvCookies = () => { 149 | let cookies = []; 150 | 151 | // 判断环境变量里面是否有 cookie 152 | if (process.env.SMZDM_COOKIE) { 153 | if (process.env.SMZDM_COOKIE.indexOf('&') > -1) { 154 | cookies = process.env.SMZDM_COOKIE.split('&'); 155 | } 156 | else if (process.env.SMZDM_COOKIE.indexOf('\n') > -1) { 157 | cookies = process.env.SMZDM_COOKIE.split('\n'); 158 | } 159 | else { 160 | cookies = [process.env.SMZDM_COOKIE]; 161 | } 162 | } 163 | 164 | return cookies[0] ? cookies : false; 165 | }; 166 | 167 | const randomDecimal = (min, max, decimal) => { 168 | const rand = Math.random() * (max - min + 1) + min; 169 | 170 | return Math.floor(rand * decimal) / decimal; 171 | }; 172 | 173 | const wait = (minSecond, maxSecond) => { 174 | // 生成随机小数秒数 175 | const randomSecond = randomDecimal(minSecond, maxSecond, 1000); 176 | 177 | console.log(`等候 ${minSecond}-${maxSecond}(${randomSecond}) 秒`); 178 | 179 | return new Promise(resolve => setTimeout(resolve, randomSecond * 1000)); 180 | }; 181 | 182 | // ------------------------------------ 183 | 184 | class SmzdmBot { 185 | constructor(cookie) { 186 | this.cookie = cookie.trim(); 187 | 188 | const match = this.cookie.match(/sess=(.*?);/); 189 | this.token = match ? match[1] : ''; 190 | 191 | // 处理 cookie 192 | this.androidCookie = this.cookie.replace('iphone', 'android').replace('iPhone', 'Android'); 193 | this.androidCookie = updateCookie(this.androidCookie, 'smzdm_version', APP_VERSION); 194 | this.androidCookie = updateCookie(this.androidCookie, 'device_smzdm_version', APP_VERSION); 195 | this.androidCookie = updateCookie(this.androidCookie, 'v', APP_VERSION); 196 | this.androidCookie = updateCookie(this.androidCookie, 'device_smzdm_version_code', APP_VERSION_REV); 197 | this.androidCookie = updateCookie(this.androidCookie, 'device_system_version', '10.0'); 198 | this.androidCookie = updateCookie(this.androidCookie, 'apk_partner_name', 'smzdm_download'); 199 | this.androidCookie = updateCookie(this.androidCookie, 'partner_name', 'smzdm_download'); 200 | this.androidCookie = updateCookie(this.androidCookie, 'device_type', 'Android'); 201 | this.androidCookie = updateCookie(this.androidCookie, 'device_smzdm', 'android'); 202 | this.androidCookie = updateCookie(this.androidCookie, 'device_name', 'Android'); 203 | } 204 | 205 | getHeaders() { 206 | let userAgent = DEFAULT_USER_AGENT_APP; 207 | 208 | if (process.env.SMZDM_USER_AGENT_APP) { 209 | userAgent = process.env.SMZDM_USER_AGENT_APP 210 | .replace(reVersion, `$1${APP_VERSION}`) 211 | .replace(reRev, `rv:${APP_VERSION_REV}`); 212 | } 213 | 214 | return { 215 | Accept: '*/*', 216 | 'Accept-Language': 'zh-Hans-CN;q=1', 217 | 'Accept-Encoding': 'gzip', 218 | 'request_key': randomStr(18), 219 | 'User-Agent': userAgent, 220 | Cookie: this.androidCookie 221 | }; 222 | } 223 | 224 | getHeadersForWeb() { 225 | let userAgent = DEFAULT_USER_AGENT_WEB; 226 | 227 | if (process.env.SMZDM_USER_AGENT_WEB) { 228 | userAgent = process.env.SMZDM_USER_AGENT_WEB 229 | .replace(reVersion, `$1${APP_VERSION}`) 230 | .replace(reRev, `rv:${APP_VERSION_REV}`); 231 | } 232 | 233 | return { 234 | Accept: '*/*', 235 | 'Accept-Language': 'zh-CN,zh-Hans;q=0.9', 236 | 'Accept-Encoding': 'gzip', 237 | 'User-Agent': userAgent, 238 | Cookie: this.androidCookie 239 | }; 240 | } 241 | 242 | getOneByRandom(listing) { 243 | return listing[Math.floor(Math.random() * listing.length)]; 244 | } 245 | } 246 | 247 | module.exports = { 248 | SmzdmBot, 249 | requestApi, 250 | removeTags, 251 | parseJSON, 252 | getEnvCookies, 253 | wait 254 | }; 255 | -------------------------------------------------------------------------------- /env.js: -------------------------------------------------------------------------------- 1 | function Env(t, e) { 2 | "undefined" != typeof process && JSON.stringify(process.env).indexOf("GITHUB") > -1 && process.exit(0); 3 | 4 | class s { 5 | constructor(t) { 6 | this.env = t 7 | } 8 | send(t, e = "GET") { 9 | t = "string" == typeof t ? { 10 | url: t 11 | } : 12 | t; 13 | let s = this.get; 14 | return "POST" === e && (s = this.post), 15 | new Promise((e, i) => { 16 | s.call(this, t, (t, s) => { 17 | t ? i(t) : e(s) 18 | }) 19 | }) 20 | } 21 | get(t) { 22 | return this.send.call(this.env, t) 23 | } 24 | post(t) { 25 | return this.send.call(this.env, t, "POST") 26 | } 27 | } 28 | 29 | return new class { 30 | constructor(t, e) { 31 | this.name = t, 32 | this.http = new s(this), 33 | this.data = null, 34 | this.dataFile = "box.dat", 35 | this.logs = [], 36 | this.isMute = !1, 37 | this.isNeedRewrite = !1, 38 | this.logSeparator = "\n", 39 | this.startTime = (new Date).getTime(), 40 | Object.assign(this, e), 41 | this.log("", `🔔${this.name}, 开始!`) 42 | } 43 | isNode() { 44 | return "undefined" != typeof module && !!module.exports 45 | } 46 | isQuanX() { 47 | return "undefined" != typeof $task 48 | } 49 | isSurge() { 50 | return "undefined" != typeof $httpClient && "undefined" == typeof $loon 51 | } 52 | isLoon() { 53 | return "undefined" != typeof $loon 54 | } 55 | toObj(t, e = null) { 56 | try { 57 | return JSON.parse(t) 58 | } 59 | catch { 60 | return e 61 | } 62 | } 63 | toStr(t, e = null) { 64 | try { 65 | return JSON.stringify(t) 66 | } 67 | catch { 68 | return e 69 | } 70 | } 71 | getjson(t, e) { 72 | let s = e; 73 | const i = this.getdata(t); 74 | if (i) { 75 | try { 76 | s = JSON.parse(this.getdata(t)) 77 | } 78 | catch {} 79 | } 80 | return s 81 | } 82 | setjson(t, e) { 83 | try { 84 | return this.setdata(JSON.stringify(t), e) 85 | } 86 | catch { 87 | return !1 88 | } 89 | } 90 | getScript(t) { 91 | return new Promise(e => { 92 | this.get({ 93 | url: t 94 | }, (t, s, i) => e(i)) 95 | }) 96 | } 97 | runScript(t, e) { 98 | return new Promise(s => { 99 | let i = this.getdata("@chavy_boxjs_userCfgs.httpapi"); 100 | i = i ? i.replace(/\n/g, "").trim() : i; 101 | let r = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout"); 102 | r = r ? 1 * r : 20, 103 | r = e && e.timeout ? e.timeout : r; 104 | const [o, h] = i.split("@"), 105 | n = { 106 | url: `http://${h}/v1/scripting/evaluate`, 107 | body: { 108 | script_text: t, 109 | mock_type: "cron", 110 | timeout: r 111 | }, 112 | headers: { 113 | "X-Key": o, 114 | Accept: "*/*" 115 | } 116 | }; 117 | this.post(n, (t, e, i) => s(i)) 118 | }).catch(t => this.logErr(t)) 119 | } 120 | loaddata() { 121 | if (!this.isNode()) {return {};} { 122 | this.fs = this.fs ? this.fs : require("fs"), 123 | this.path = this.path ? this.path : require("path"); 124 | const t = this.path.resolve(this.dataFile), 125 | e = this.path.resolve(process.cwd(), this.dataFile), 126 | s = this.fs.existsSync(t), 127 | i = !s && this.fs.existsSync(e); 128 | if (!s && !i) {return {};} { 129 | const i = s ? t : e; 130 | try { 131 | return JSON.parse(this.fs.readFileSync(i)) 132 | } 133 | catch (t) { 134 | return {} 135 | } 136 | } 137 | } 138 | } 139 | writedata() { 140 | if (this.isNode()) { 141 | this.fs = this.fs ? this.fs : require("fs"), 142 | this.path = this.path ? this.path : require("path"); 143 | const t = this.path.resolve(this.dataFile), 144 | e = this.path.resolve(process.cwd(), this.dataFile), 145 | s = this.fs.existsSync(t), 146 | i = !s && this.fs.existsSync(e), 147 | r = JSON.stringify(this.data); 148 | s ? this.fs.writeFileSync(t, r) : i ? this.fs.writeFileSync(e, r) : this.fs.writeFileSync(t, r) 149 | } 150 | } 151 | lodash_get(t, e, s) { 152 | const i = e.replace(/\[(\d+)\]/g, ".$1").split("."); 153 | let r = t; 154 | for (const t of i) { 155 | if (r = Object(r)[t], void 0 === r) {return s;} 156 | } 157 | return r 158 | } 159 | lodash_set(t, e, s) { 160 | 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) 161 | } 162 | getdata(t) { 163 | let e = this.getval(t); 164 | if (/^@/.test(t)) { 165 | const [, s, i] = /^@(.*?)\.(.*?)$/.exec(t), 166 | r = s ? this.getval(s) : ""; 167 | if (r) { 168 | try { 169 | const t = JSON.parse(r); 170 | e = t ? this.lodash_get(t, i, "") : e 171 | } 172 | catch (t) { 173 | e = "" 174 | } 175 | } 176 | } 177 | return e 178 | } 179 | setdata(t, e) { 180 | let s = !1; 181 | if (/^@/.test(e)) { 182 | const [, i, r] = /^@(.*?)\.(.*?)$/.exec(e), 183 | o = this.getval(i), 184 | h = i ? "null" === o ? null : o || "{}" : "{}"; 185 | try { 186 | const e = JSON.parse(h); 187 | this.lodash_set(e, r, t), 188 | s = this.setval(JSON.stringify(e), i) 189 | } 190 | catch (e) { 191 | const o = {}; 192 | this.lodash_set(o, r, t), 193 | s = this.setval(JSON.stringify(o), i) 194 | } 195 | } 196 | else {s = this.setval(t, e);} 197 | return s 198 | } 199 | getval(t) { 200 | 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 201 | } 202 | setval(t, e) { 203 | 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 204 | } 205 | initGotEnv(t) { 206 | this.got = this.got ? this.got : require("got"), 207 | this.cktough = this.cktough ? this.cktough : require("tough-cookie"), 208 | this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar, 209 | t && (t.headers = t.headers ? t.headers : {}, void 0 === t.headers.Cookie && void 0 === t.cookieJar && (t.cookieJar = this.ckjar)) 210 | } 211 | get(t, e = (() => {})) { 212 | t.headers && (delete t.headers["Content-Type"], delete t.headers["Content-Length"]), 213 | this.isSurge() || this.isLoon() ? (this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { 214 | "X-Surge-Skip-Scripting": !1 215 | })), $httpClient.get(t, (t, s, i) => { 216 | !t && s && (s.body = i, s.statusCode = s.status), 217 | e(t, s, i) 218 | })) : this.isQuanX() ? (this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { 219 | hints: !1 220 | })), $task.fetch(t).then(t => { 221 | const { 222 | statusCode: s, 223 | statusCode: i, 224 | headers: r, 225 | body: o 226 | } = t; 227 | e(null, { 228 | status: s, 229 | statusCode: i, 230 | headers: r, 231 | body: o 232 | }, o) 233 | }, t => e(t))) : this.isNode() && (this.initGotEnv(t), this.got(t).on("redirect", (t, e) => { 234 | try { 235 | if (t.headers["set-cookie"]) { 236 | const s = t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString(); 237 | s && this.ckjar.setCookieSync(s, null), 238 | e.cookieJar = this.ckjar 239 | } 240 | } 241 | catch (t) { 242 | this.logErr(t) 243 | } 244 | }).then(t => { 245 | const { 246 | statusCode: s, 247 | statusCode: i, 248 | headers: r, 249 | body: o 250 | } = t; 251 | e(null, { 252 | status: s, 253 | statusCode: i, 254 | headers: r, 255 | body: o 256 | }, o) 257 | }, t => { 258 | const { 259 | message: s, 260 | response: i 261 | } = t; 262 | e(s, i, i && i.body) 263 | })) 264 | } 265 | post(t, e = (() => {})) { 266 | 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()) { 267 | this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { 268 | "X-Surge-Skip-Scripting": !1 269 | })), $httpClient.post(t, (t, s, i) => { 270 | !t && s && (s.body = i, s.statusCode = s.status), 271 | e(t, s, i) 272 | }); 273 | } 274 | else if (this.isQuanX()) { 275 | t.method = "POST", this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { 276 | hints: !1 277 | })), $task.fetch(t).then(t => { 278 | const { 279 | statusCode: s, 280 | statusCode: i, 281 | headers: r, 282 | body: o 283 | } = t; 284 | e(null, { 285 | status: s, 286 | statusCode: i, 287 | headers: r, 288 | body: o 289 | }, o) 290 | }, t => e(t)); 291 | } 292 | else if (this.isNode()) { 293 | this.initGotEnv(t); 294 | const { 295 | url: s, 296 | ...i 297 | } = t; 298 | this.got.post(s, i).then(t => { 299 | const { 300 | statusCode: s, 301 | statusCode: i, 302 | headers: r, 303 | body: o 304 | } = t; 305 | e(null, { 306 | status: s, 307 | statusCode: i, 308 | headers: r, 309 | body: o 310 | }, o) 311 | }, t => { 312 | const { 313 | message: s, 314 | response: i 315 | } = t; 316 | e(s, i, i && i.body) 317 | }) 318 | } 319 | } 320 | time(t, e = null) { 321 | const s = e ? new Date(e) : new Date; 322 | const i = { 323 | "M+": s.getMonth() + 1, 324 | "d+": s.getDate(), 325 | "H+": s.getHours(), 326 | "m+": s.getMinutes(), 327 | "s+": s.getSeconds(), 328 | "q+": Math.floor((s.getMonth() + 3) / 3), 329 | S: s.getMilliseconds() 330 | }; 331 | /(y+)/.test(t) && (t = t.replace(RegExp.$1, (s.getFullYear() + "").substr(4 - RegExp.$1.length))); 332 | for (const 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)));} 333 | return t 334 | } 335 | msg(e = t, s = "", i = "", r) { 336 | const o = t => { 337 | if (!t) {return t;} 338 | if ("string" == typeof t) { 339 | return this.isLoon() ? t : this.isQuanX() ? { 340 | "open-url": t 341 | } : 342 | this.isSurge() ? { 343 | url: t 344 | } : 345 | void 0; 346 | } 347 | if ("object" == typeof t) { 348 | if (this.isLoon()) { 349 | const e = t.openUrl || t.url || t["open-url"], 350 | s = t.mediaUrl || t["media-url"]; 351 | return { 352 | openUrl: e, 353 | mediaUrl: s 354 | } 355 | } 356 | if (this.isQuanX()) { 357 | const e = t["open-url"] || t.url || t.openUrl, 358 | s = t["media-url"] || t.mediaUrl; 359 | return { 360 | "open-url": e, 361 | "media-url": s 362 | } 363 | } 364 | if (this.isSurge()) { 365 | const e = t.url || t.openUrl || t["open-url"]; 366 | return { 367 | url: e 368 | } 369 | } 370 | } 371 | }; 372 | if (this.isMute || (this.isSurge() || this.isLoon() ? $notification.post(e, s, i, o(r)) : this.isQuanX() && $notify(e, s, i, o(r))), !this.isMuteLog) { 373 | const t = ["", "==============📣系统通知📣=============="]; 374 | t.push(e), 375 | s && t.push(s), 376 | i && t.push(i), 377 | console.log(t.join("\n")), 378 | this.logs = this.logs.concat(t) 379 | } 380 | } 381 | log(...t) { 382 | t.length > 0 && (this.logs = [...this.logs, ...t]), 383 | console.log(t.join(this.logSeparator)) 384 | } 385 | logErr(t) { 386 | const s = !this.isSurge() && !this.isQuanX() && !this.isLoon(); 387 | s ? this.log("", `❗️${this.name}, 错误!`, t.stack) : this.log("", `❗️${this.name}, 错误!`, t) 388 | } 389 | wait(t) { 390 | return new Promise(e => setTimeout(e, t)) 391 | } 392 | done(t = {}) { 393 | const e = (new Date).getTime(), 394 | s = (e - this.startTime) / 1e3; 395 | this.log("", `🔔${this.name}, 结束! 🕛 ${s} 秒`), 396 | this.log(), 397 | (this.isSurge() || this.isQuanX() || this.isLoon()) && $done(t) 398 | } 399 | }(t, e); 400 | } 401 | 402 | module.exports = Env; 403 | -------------------------------------------------------------------------------- /library_task.js: -------------------------------------------------------------------------------- 1 | const { SmzdmBot, requestApi, removeTags, wait } = require('./bot'); 2 | 3 | // ------------------------------------ 4 | 5 | class SmzdmTaskBot extends SmzdmBot { 6 | constructor(cookie, env) { 7 | super(cookie); 8 | 9 | this.$env = env; 10 | } 11 | 12 | // 执行任务列表中的任务 13 | async doTasks(tasks) { 14 | let notifyMsg = ''; 15 | 16 | for (let i = 0; i < tasks.length; i++) { 17 | const task = tasks[i]; 18 | 19 | // 待领取任务 20 | if (task.task_status == '3') { 21 | this.$env.log(`领取[${task.task_name}]奖励:`); 22 | 23 | const { isSuccess } = await this.receiveReward(task.task_id); 24 | 25 | notifyMsg += `${isSuccess ? '🟢' : '❌'}领取[${task.task_name}]奖励${isSuccess ? '成功' : '失败!请查看日志'}\n`; 26 | 27 | await wait(5, 15); 28 | } 29 | // 未完成任务 30 | else if (task.task_status == '2') { 31 | // 浏览文章任务 32 | if (task.task_event_type == 'interactive.view.article') { 33 | const { isSuccess } = await this.doViewTask(task); 34 | 35 | notifyMsg += this.getTaskNotifyMessage(isSuccess, task); 36 | 37 | await wait(5, 15); 38 | } 39 | // 分享任务 40 | else if (task.task_event_type == 'interactive.share') { 41 | const { isSuccess } = await this.doShareTask(task); 42 | 43 | notifyMsg += this.getTaskNotifyMessage(isSuccess, task); 44 | 45 | await wait(5, 15); 46 | } 47 | // 抽奖任务 48 | else if (task.task_event_type == 'guide.crowd') { 49 | const { isSuccess, code } = await this.doCrowdTask(task); 50 | 51 | if (code !== 99) { 52 | notifyMsg += this.getTaskNotifyMessage(isSuccess, task); 53 | } 54 | 55 | await wait(5, 15); 56 | } 57 | // 关注用户任务 58 | else if (task.task_event_type == 'interactive.follow.user') { 59 | const { isSuccess } = await this.doFollowUserTask(task); 60 | 61 | notifyMsg += this.getTaskNotifyMessage(isSuccess, task); 62 | 63 | await wait(5, 15); 64 | } 65 | // 关注栏目任务 66 | else if (task.task_event_type == 'interactive.follow.tag') { 67 | const { isSuccess } = await this.doFollowTagTask(task); 68 | 69 | notifyMsg += this.getTaskNotifyMessage(isSuccess, task); 70 | 71 | await wait(5, 15); 72 | } 73 | // 关注品牌 74 | else if (task.task_event_type == 'interactive.follow.brand') { 75 | const { isSuccess } = await this.doFollowBrandTask(task); 76 | 77 | notifyMsg += this.getTaskNotifyMessage(isSuccess, task); 78 | 79 | await wait(5, 15); 80 | } 81 | // 收藏任务 82 | else if (task.task_event_type == 'interactive.favorite') { 83 | const { isSuccess } = await this.doFavoriteTask(task); 84 | 85 | notifyMsg += this.getTaskNotifyMessage(isSuccess, task); 86 | 87 | await wait(5, 15); 88 | } 89 | // 点赞任务 90 | else if (task.task_event_type == 'interactive.rating') { 91 | const { isSuccess } = await this.doRatingTask(task); 92 | 93 | notifyMsg += this.getTaskNotifyMessage(isSuccess, task); 94 | 95 | await wait(5, 15); 96 | } 97 | // 评论任务 98 | else if (task.task_event_type == 'interactive.comment') { 99 | if (process.env.SMZDM_COMMENT && String(process.env.SMZDM_COMMENT).length > 10) { 100 | const { isSuccess } = await this.doCommentTask(task); 101 | 102 | notifyMsg += this.getTaskNotifyMessage(isSuccess, task); 103 | 104 | await wait(5, 15); 105 | } 106 | else { 107 | this.$env.log('🟡请设置 SMZDM_COMMENT 环境变量后才能做评论任务!'); 108 | } 109 | } 110 | } 111 | } 112 | 113 | return notifyMsg; 114 | } 115 | 116 | getTaskNotifyMessage(isSuccess, task) { 117 | return `${isSuccess ? '🟢' : '❌'}完成[${task.task_name}]任务${isSuccess ? '成功' : '失败!请查看日志'}\n`; 118 | } 119 | 120 | // 执行评论任务 121 | async doCommentTask(task) { 122 | this.$env.log(`开始任务: ${task.task_name}`); 123 | 124 | const articles = await this.getArticleList(20); 125 | 126 | if (articles.length < 1) { 127 | return { 128 | isSuccess: false 129 | }; 130 | } 131 | 132 | // 随机选一篇文章来评论 133 | const article = articles[Math.floor(Math.random() * articles.length)]; 134 | 135 | await wait(3, 10); 136 | 137 | const {isSuccess, data } = await this.submitComment({ 138 | articleId: article.article_id, 139 | channelId: article.article_channel_id, 140 | content: process.env.SMZDM_COMMENT 141 | }); 142 | 143 | if (!isSuccess) { 144 | return { 145 | isSuccess 146 | }; 147 | } 148 | 149 | this.$env.log('删除评论'); 150 | await wait(20, 30); 151 | 152 | const {isSuccess: result } = await this.removeComment(data.data.comment_ID); 153 | 154 | if (!result) { 155 | this.$env.log('再试一次'); 156 | await wait(10, 20); 157 | 158 | // 不成功再执行一次删除 159 | await this.removeComment(data.data.comment_ID); 160 | } 161 | 162 | this.$env.log('领取奖励'); 163 | await wait(5, 15); 164 | 165 | return await this.receiveReward(task.task_id); 166 | } 167 | 168 | // 执行点赞任务 169 | async doRatingTask(task) { 170 | this.$env.log(`开始任务: ${task.task_name}`); 171 | 172 | let article; 173 | 174 | if (task.task_description.indexOf('任意') >= 0 || task.task_redirect_url.link_val == '0' || !task.task_redirect_url.link_val) { 175 | // 随机选一篇文章 176 | const articles = await this.getArticleList(20); 177 | 178 | if (articles.length < 1) { 179 | return { 180 | isSuccess: false 181 | }; 182 | } 183 | 184 | article = this.getOneByRandom(articles); 185 | } 186 | else if (task.task_redirect_url.link_type === 'lanmu') { 187 | // 从栏目获取文章 188 | const articles = await this.getArticleListFromLanmu(task.task_redirect_url.link_val, 20); 189 | 190 | if (articles.length < 1) { 191 | return { 192 | isSuccess: false 193 | }; 194 | } 195 | 196 | article = this.getOneByRandom(articles); 197 | } 198 | else if (task.task_redirect_url.link != '' && task.task_redirect_url.link_val != '') { 199 | const channelId = await this.getArticleChannelIdForTesting(task.task_redirect_url.link); 200 | 201 | if (!channelId) { 202 | return { 203 | isSuccess: false 204 | }; 205 | } 206 | 207 | article = { 208 | 'article_id': task.task_redirect_url.link_val, 209 | 'article_channel_id': channelId 210 | }; 211 | } 212 | else { 213 | this.$env.log('尚未支持'); 214 | 215 | return { 216 | isSuccess: false 217 | }; 218 | } 219 | 220 | await wait(3, 10); 221 | 222 | if (article.article_price) { 223 | // 点值 224 | await this.rating({ 225 | method: 'worth_cancel', 226 | type: 3, 227 | id: article.article_id, 228 | channelId: article.article_channel_id 229 | }); 230 | 231 | await wait(3, 10); 232 | 233 | await this.rating({ 234 | method: 'worth_create', 235 | type: 1, 236 | id: article.article_id, 237 | channelId: article.article_channel_id 238 | }); 239 | 240 | await wait(3, 10); 241 | 242 | await this.rating({ 243 | method: 'worth_cancel', 244 | type: 3, 245 | id: article.article_id, 246 | channelId: article.article_channel_id 247 | }); 248 | } 249 | else { 250 | // 点赞 251 | await this.rating({ 252 | method: 'like_cancel', 253 | id: article.article_id, 254 | channelId: article.article_channel_id 255 | }); 256 | 257 | await wait(3, 10); 258 | 259 | await this.rating({ 260 | method: 'like_create', 261 | id: article.article_id, 262 | channelId: article.article_channel_id 263 | }); 264 | 265 | await wait(3, 10); 266 | 267 | await this.rating({ 268 | method: 'like_cancel', 269 | id: article.article_id, 270 | channelId: article.article_channel_id 271 | }); 272 | } 273 | 274 | this.$env.log('领取奖励'); 275 | await wait(5, 15); 276 | 277 | return await this.receiveReward(task.task_id); 278 | } 279 | 280 | // 执行收藏任务 281 | async doFavoriteTask(task) { 282 | this.$env.log(`开始任务: ${task.task_name}`); 283 | 284 | let articleId = ''; 285 | let channelId = ''; 286 | 287 | if (task.task_redirect_url.link_type === 'lanmu') { 288 | // 从栏目获取文章 289 | const articles = await this.getArticleListFromLanmu(task.task_redirect_url.link_val, 20); 290 | 291 | if (articles.length < 1) { 292 | return { 293 | isSuccess: false 294 | }; 295 | } 296 | 297 | const article = this.getOneByRandom(articles); 298 | 299 | articleId = article.article_id; 300 | channelId = article.article_channel_id; 301 | } 302 | else if (task.task_redirect_url.link_type === 'tag') { 303 | // 从 Tag 获取文章 304 | const articles = await this.getArticleListFromTag(task.task_redirect_url.link_val, task.task_redirect_url.link_title, 20); 305 | 306 | if (articles.length < 1) { 307 | return { 308 | isSuccess: false 309 | }; 310 | } 311 | 312 | const article = this.getOneByRandom(articles); 313 | 314 | articleId = article.article_id; 315 | channelId = article.article_channel_id; 316 | } 317 | else if (task.task_redirect_url.link_val == '0' || !task.task_redirect_url.link_val) { 318 | // 随机选一篇文章 319 | const articles = await this.getArticleList(20); 320 | 321 | if (articles.length < 1) { 322 | return { 323 | isSuccess: false 324 | }; 325 | } 326 | 327 | const article = this.getOneByRandom(articles); 328 | 329 | articleId = article.article_id; 330 | channelId = article.article_channel_id; 331 | } 332 | else { 333 | articleId = task.task_redirect_url.link_val; 334 | 335 | // 获取文章信息 336 | const articleDetail = await this.getArticleDetail(articleId); 337 | 338 | if (articleDetail === false) { 339 | return { 340 | isSuccess: false 341 | }; 342 | } 343 | 344 | channelId = articleDetail.channel_id; 345 | } 346 | 347 | await wait(3, 10); 348 | 349 | await this.favorite({ 350 | method: 'destroy', 351 | id: articleId, 352 | channelId 353 | }); 354 | 355 | await wait(3, 10); 356 | 357 | await this.favorite({ 358 | method: 'create', 359 | id: articleId, 360 | channelId 361 | }); 362 | 363 | await wait(3, 10); 364 | 365 | await this.favorite({ 366 | method: 'destroy', 367 | id: articleId, 368 | channelId 369 | }); 370 | 371 | this.$env.log('领取奖励'); 372 | await wait(5, 15); 373 | 374 | return await this.receiveReward(task.task_id); 375 | } 376 | 377 | // 执行关注用户任务 378 | async doFollowUserTask(task) { 379 | this.$env.log(`开始任务: ${task.task_name}`); 380 | 381 | // 随机选一个用户 382 | const user = await this.getUserByRandom(); 383 | 384 | if (!user) { 385 | return { 386 | isSuccess: false 387 | }; 388 | } 389 | 390 | await wait(3, 10); 391 | 392 | for (let i = 0; i < Number(task.task_even_num - task.task_finished_num); i++) { 393 | if (user.is_follow == '1') { 394 | await this.follow({ 395 | method: 'destroy', 396 | type: 'user', 397 | keyword: user.keyword 398 | }); 399 | 400 | await wait(3, 10); 401 | } 402 | 403 | await this.follow({ 404 | method: 'create', 405 | type: 'user', 406 | keyword: user.keyword 407 | }); 408 | 409 | await wait(3, 10); 410 | 411 | if (user.is_follow == '0') { 412 | await this.follow({ 413 | method: 'destroy', 414 | type: 'user', 415 | keyword: user.keyword 416 | }); 417 | } 418 | 419 | await wait(3, 10); 420 | } 421 | 422 | this.$env.log('领取奖励'); 423 | await wait(5, 15); 424 | 425 | return await this.receiveReward(task.task_id); 426 | } 427 | 428 | // 执行关注栏目任务(先取关,再关注,最后取关) 429 | async doFollowTagTask(task) { 430 | this.$env.log(`开始任务: ${task.task_name}`); 431 | 432 | let lanmuId = ''; 433 | 434 | if (task.task_redirect_url.link_val == '0') { 435 | const tag = await this.getTagByRandom(); 436 | 437 | if (tag === false) { 438 | return { 439 | isSuccess: false 440 | }; 441 | } 442 | 443 | lanmuId = tag.lanmu_id; 444 | 445 | await wait(3, 10); 446 | } 447 | else { 448 | lanmuId = task.task_redirect_url.link_val; 449 | } 450 | 451 | // 获取栏目信息 452 | const tagDetail = await this.getTagDetail(lanmuId); 453 | 454 | if (!tagDetail.lanmu_id) { 455 | this.$env.log('获取栏目信息失败!'); 456 | 457 | return { 458 | isSuccess: false 459 | }; 460 | } 461 | 462 | await wait(3, 10); 463 | 464 | await this.follow({ 465 | method: 'destroy', 466 | type: 'tag', 467 | keywordId: tagDetail.lanmu_id, 468 | keyword: tagDetail.lanmu_info.lanmu_name 469 | }); 470 | 471 | await wait(3, 10); 472 | 473 | await this.follow({ 474 | method: 'create', 475 | type: 'tag', 476 | keywordId: tagDetail.lanmu_id, 477 | keyword: tagDetail.lanmu_info.lanmu_name 478 | }); 479 | 480 | await wait(3, 10); 481 | 482 | await this.follow({ 483 | method: 'destroy', 484 | type: 'tag', 485 | keywordId: tagDetail.lanmu_id, 486 | keyword: tagDetail.lanmu_info.lanmu_name 487 | }); 488 | 489 | this.$env.log('领取奖励'); 490 | await wait(5, 15); 491 | 492 | return await this.receiveReward(task.task_id); 493 | } 494 | 495 | // 执行关注品牌任务(先取关,再关注,最后取关) 496 | async doFollowBrandTask(task) { 497 | this.$env.log(`开始任务: ${task.task_name}`); 498 | 499 | // 获取品牌信息 500 | const brandDetail = await this.getBrandDetail(task.task_redirect_url.link_val); 501 | 502 | if (!brandDetail.id) { 503 | return { 504 | isSuccess: false 505 | }; 506 | } 507 | 508 | await wait(3, 10); 509 | 510 | await this.followBrand({ 511 | method: 'dingyue_lanmu_del', 512 | keywordId: brandDetail.id, 513 | keyword: brandDetail.title 514 | }); 515 | 516 | await wait(3, 10); 517 | 518 | await this.followBrand({ 519 | method: 'dingyue_lanmu_add', 520 | keywordId: brandDetail.id, 521 | keyword: brandDetail.title 522 | }); 523 | 524 | await wait(3, 10); 525 | 526 | await this.followBrand({ 527 | method: 'dingyue_lanmu_del', 528 | keywordId: brandDetail.id, 529 | keyword: brandDetail.title 530 | }); 531 | 532 | this.$env.log('领取奖励'); 533 | await wait(5, 15); 534 | 535 | return await this.receiveReward(task.task_id); 536 | } 537 | 538 | // 执行抽奖任务 539 | async doCrowdTask(task) { 540 | this.$env.log(`开始任务: ${task.task_name}`); 541 | 542 | let { isSuccess, data } = await this.getCrowd('免费', 0); 543 | 544 | if (!isSuccess) { 545 | if (process.env.SMZDM_CROWD_SILVER_5 == 'yes') { 546 | ({ isSuccess, data } = await this.getCrowd('5碎银子', 5)); 547 | 548 | if (!isSuccess) { 549 | return { 550 | isSuccess, 551 | code: 99 552 | }; 553 | } 554 | } 555 | else { 556 | this.$env.log('🟡请设置 SMZDM_CROWD_SILVER_5 环境变量值为 yes 后才能进行5碎银子抽奖!'); 557 | 558 | return { 559 | isSuccess, 560 | code: 99 561 | }; 562 | } 563 | } 564 | 565 | await wait(5, 15); 566 | 567 | const result = await this.joinCrowd(data); 568 | 569 | if (!result.isSuccess) { 570 | return { 571 | isSuccess: result.isSuccess 572 | }; 573 | } 574 | 575 | this.$env.log('领取奖励'); 576 | await wait(5, 15); 577 | 578 | return await this.receiveReward(task.task_id); 579 | } 580 | 581 | // 执行文章分享任务 582 | async doShareTask(task) { 583 | this.$env.log(`开始任务: ${task.task_name}`); 584 | 585 | let articles = []; 586 | 587 | if (task.article_id == '0') { 588 | articles = await this.getArticleList(task.task_even_num - task.task_finished_num); 589 | 590 | await wait(3, 10); 591 | } 592 | else { 593 | articles = [{ 594 | article_id: task.article_id, 595 | article_channel_id: task.channel_id 596 | }]; 597 | } 598 | 599 | for (let i = 0; i < articles.length; i++) { 600 | this.$env.log(`开始分享第 ${i + 1} 篇文章...`); 601 | 602 | const article = articles[i]; 603 | 604 | if (task.task_redirect_url.link_type != 'other') { 605 | // 模拟打开文章 606 | if (/detail_haojia/i.test(task.task_redirect_url.scheme_url)) { 607 | await this.getHaojiaDetail(article.article_id); 608 | } 609 | else { 610 | await this.getArticleDetail(article.article_id); 611 | } 612 | 613 | await wait(8, 20); 614 | } 615 | 616 | await this.shareArticleDone(article.article_id, article.article_channel_id); 617 | await this.shareDailyReward(article.article_channel_id); 618 | await this.shareCallback(article.article_id, article.article_channel_id); 619 | 620 | await wait(5, 15); 621 | } 622 | 623 | this.$env.log('领取奖励'); 624 | await wait(3, 10); 625 | 626 | return await this.receiveReward(task.task_id); 627 | } 628 | 629 | // 执行浏览任务 630 | async doViewTask(task) { 631 | this.$env.log(`开始任务: ${task.task_name}`); 632 | 633 | let articles = []; 634 | let isRead = true; 635 | 636 | if (task.article_id == '0') { 637 | isRead = true; 638 | articles = await this.getArticleList(task.task_even_num - task.task_finished_num); 639 | 640 | await wait(3, 10); 641 | } 642 | else { 643 | for (let i = 0; i < task.task_even_num - task.task_finished_num; i++) { 644 | articles.push({ 645 | article_id: task.article_id, 646 | article_channel_id: task.channel_id 647 | }); 648 | } 649 | 650 | isRead = task.task_redirect_url.link_val != ''; 651 | } 652 | 653 | for (let i = 0; i < articles.length; i++) { 654 | this.$env.log(`开始阅读第 ${i + 1} 篇文章...`); 655 | 656 | const article = articles[i]; 657 | 658 | if (isRead) { 659 | // 模拟打开文章 660 | if (/detail_haojia/i.test(task.task_redirect_url.scheme_url)) { 661 | await this.getHaojiaDetail(article.article_id); 662 | } 663 | else { 664 | await this.getArticleDetail(article.article_id); 665 | } 666 | } 667 | 668 | this.$env.log('模拟阅读文章'); 669 | await wait(20, 50); 670 | 671 | const { isSuccess, response } = await requestApi('https://user-api.smzdm.com/task/event_view_article_sync', { 672 | method: 'post', 673 | headers: this.getHeaders(), 674 | data: { 675 | article_id: article.article_id, 676 | channel_id: article.article_channel_id, 677 | task_id: task.task_id 678 | } 679 | }); 680 | 681 | if (isSuccess) { 682 | this.$env.log('完成阅读成功。'); 683 | } 684 | else { 685 | this.$env.log(`完成阅读失败!${response}`); 686 | } 687 | 688 | await wait(5, 15); 689 | } 690 | 691 | this.$env.log('领取奖励'); 692 | await wait(3, 10); 693 | 694 | return await this.receiveReward(task.task_id); 695 | } 696 | 697 | // 关注/取关 698 | async follow({keywordId, keyword, type, method}) { 699 | let touchstone = ''; 700 | 701 | if (type === 'user') { 702 | touchstone = this.getTouchstoneEvent({ 703 | event_value: { 704 | cid: 'null', 705 | is_detail: false, 706 | p: '1' 707 | }, 708 | sourceMode: '我的_我的任务页', 709 | sourcePage: 'Android/关注/达人/爆料榜', 710 | upperLevel_url: '关注/达人/推荐/' 711 | }); 712 | } 713 | else if (type === 'tag') { 714 | touchstone = this.getTouchstoneEvent({ 715 | event_value: { 716 | cid: 'null', 717 | is_detail: false 718 | }, 719 | sourceMode: '栏目页', 720 | sourcePage: `Android/栏目页/${keyword}/${keywordId}/`, 721 | source_page_type_id: String(keywordId), 722 | upperLevel_url: '个人中心/赚奖励/', 723 | source_area: { 724 | lanmu_id: String(keywordId), 725 | prev_source_scence: '我的_我的任务页' 726 | } 727 | }); 728 | } 729 | 730 | const { isSuccess, response } = await requestApi(`https://dingyue-api.smzdm.com/dingyue/${method}`, { 731 | method: 'post', 732 | headers: this.getHeaders(), 733 | data: { 734 | touchstone_event: touchstone, 735 | refer: '', 736 | keyword_id: keywordId, 737 | keyword, 738 | type 739 | } 740 | }); 741 | 742 | if (isSuccess) { 743 | this.$env.log(`${method} 关注成功: ${keyword}`); 744 | } 745 | else { 746 | this.$env.log(`${method} 关注失败!${response}`); 747 | } 748 | 749 | return { 750 | isSuccess, 751 | response 752 | }; 753 | } 754 | 755 | // 随机获取用户 756 | async getUserByRandom() { 757 | const { isSuccess, data, response } = await requestApi('https://dingyue-api.smzdm.com/tuijian/search_result', { 758 | method: 'post', 759 | headers: this.getHeaders(), 760 | data: { 761 | nav_id: 0, 762 | page: 1, 763 | type: 'user', 764 | time_code: '' 765 | } 766 | }); 767 | 768 | if (isSuccess) { 769 | return data.data.rows[Math.floor(Math.random() * data.data.rows.length)]; 770 | } 771 | else { 772 | this.$env.log(`获取用户列表失败!${response}`); 773 | 774 | return false; 775 | } 776 | } 777 | 778 | // 参加抽奖 779 | async joinCrowd(id) { 780 | const { isSuccess, data, response } = await requestApi('https://zhiyou.m.smzdm.com/user/crowd/ajax_participate', { 781 | method: 'post', 782 | sign: false, 783 | headers: { 784 | ...this.getHeadersForWeb(), 785 | Origin: 'https://zhiyou.m.smzdm.com', 786 | Referer: `https://zhiyou.m.smzdm.com/user/crowd/p/${id}/` 787 | }, 788 | data: { 789 | crowd_id: id, 790 | sourcePage: `https://zhiyou.m.smzdm.com/user/crowd/p/${id}/`, 791 | client_type: 'android', 792 | sourceRoot: '个人中心', 793 | sourceMode: '幸运屋抽奖', 794 | price_id: 1 795 | } 796 | }); 797 | 798 | if (isSuccess) { 799 | this.$env.log(removeTags(data.data.msg)); 800 | } 801 | else { 802 | this.$env.log(`参加免费抽奖失败: ${response}`); 803 | } 804 | 805 | return { 806 | isSuccess, 807 | response 808 | }; 809 | } 810 | 811 | // 获取抽奖信息 812 | async getCrowd(name, price) { 813 | const { isSuccess, data, response } = await requestApi('https://zhiyou.smzdm.com/user/crowd/', { 814 | sign: false, 815 | parseJSON: false, 816 | headers: this.getHeadersForWeb() 817 | }); 818 | 819 | const re = new RegExp(`]+?)>\\s+?]+?>\\s*${name}(?:抽奖)?\\s*<\\/div>\\s+-${price}<\\/span>[\\s\\S]+?<\\/button>`, 'ig'); 820 | 821 | if (isSuccess) { 822 | const crowds = []; 823 | let match; 824 | 825 | while ((match = re.exec(data)) !== null) { 826 | crowds.push(match[1]); 827 | } 828 | 829 | if (crowds.length < 1) { 830 | this.$env.log(`未找到${name}抽奖`); 831 | 832 | return { 833 | isSuccess: false 834 | }; 835 | } 836 | 837 | let crowd; 838 | 839 | if (price > 0 && process.env.SMZDM_CROWD_KEYWORD) { 840 | crowd = crowds.find((item) => { 841 | const match = item.match(/data-title="([^"]+)"/i); 842 | 843 | return (match && match[1].indexOf(process.env.SMZDM_CROWD_KEYWORD) >= 0); 844 | }); 845 | 846 | if (!crowd) { 847 | this.$env.log('未找到符合关键词的抽奖,执行随机选取'); 848 | crowd = this.getOneByRandom(crowds); 849 | } 850 | } 851 | else { 852 | crowd = this.getOneByRandom(crowds); 853 | } 854 | 855 | const matchCrowd = crowd.match(/data-crowd_id="(\d+)"/i); 856 | 857 | if (matchCrowd) { 858 | this.$env.log(`${name}抽奖ID: ${matchCrowd[1]}`); 859 | 860 | return { 861 | isSuccess: true, 862 | data: matchCrowd[1] 863 | }; 864 | } 865 | else { 866 | this.$env.log(`未找到${name}抽奖ID`); 867 | 868 | return { 869 | isSuccess: false 870 | }; 871 | } 872 | } 873 | else { 874 | this.$env.log(`获取${name}抽奖失败: ${response}`); 875 | 876 | return { 877 | isSuccess: false 878 | }; 879 | } 880 | } 881 | 882 | // 分享完成 883 | async shareArticleDone(articleId, channelId) { 884 | const { isSuccess, response } = await requestApi('https://user-api.smzdm.com/share/complete_share_rule', { 885 | method: 'post', 886 | headers: this.getHeaders(), 887 | data: { 888 | token: this.token, 889 | article_id: articleId, 890 | channel_id: channelId, 891 | tag_name: 'gerenzhongxin' 892 | } 893 | }); 894 | 895 | if (isSuccess) { 896 | this.$env.log('完成分享成功。'); 897 | 898 | return { 899 | isSuccess, 900 | msg: '完成分享成功。' 901 | }; 902 | } 903 | else { 904 | this.$env.log(`完成分享失败!${response}`); 905 | 906 | return { 907 | isSuccess: false, 908 | msg: '完成分享失败!' 909 | }; 910 | } 911 | } 912 | 913 | // 分享完成后回调接口 914 | async shareCallback(articleId, channelId) { 915 | const { isSuccess, response } = await requestApi('https://user-api.smzdm.com/share/callback', { 916 | method: 'post', 917 | headers: this.getHeaders(), 918 | data: { 919 | token: this.token, 920 | article_id: articleId, 921 | channel_id: channelId, 922 | touchstone_event: this.getTouchstoneEvent({ 923 | event_value: { 924 | aid: articleId, 925 | cid: channelId, 926 | is_detail: true, 927 | pid: '无' 928 | }, 929 | sourceMode: '排行榜_社区_好文精选', 930 | sourcePage: `Android/长图文/P/${articleId}/`, 931 | upperLevel_url: '排行榜/社区/好文精选/文章_24H/' 932 | }) 933 | } 934 | }); 935 | 936 | if (isSuccess) { 937 | this.$env.log('分享回调完成。'); 938 | 939 | return { 940 | isSuccess, 941 | msg: '' 942 | }; 943 | } 944 | else { 945 | this.$env.log(`分享回调失败!${response}`); 946 | 947 | return { 948 | isSuccess, 949 | msg: '分享回调失败!' 950 | }; 951 | } 952 | } 953 | 954 | // 分享的每日奖励(貌似没啥用) 955 | async shareDailyReward(channelId) { 956 | const { isSuccess, data, response } = await requestApi('https://user-api.smzdm.com/share/daily_reward', { 957 | method: 'post', 958 | headers: this.getHeaders(), 959 | data: { 960 | token: this.token, 961 | channel_id: channelId 962 | } 963 | }); 964 | 965 | if (isSuccess) { 966 | this.$env.log(data.data.reward_desc); 967 | 968 | return { 969 | isSuccess, 970 | msg: data.data.reward_desc 971 | }; 972 | } 973 | else { 974 | if (data) { 975 | this.$env.log(data.error_msg); 976 | 977 | return { 978 | isSuccess, 979 | msg: data.error_msg 980 | }; 981 | } 982 | else { 983 | this.$env.log(`分享每日奖励请求失败!${response}`); 984 | 985 | return { 986 | isSuccess, 987 | msg: '分享每日奖励请求失败!' 988 | }; 989 | } 990 | } 991 | } 992 | 993 | // 获取文章列表 994 | async getArticleList(num = 1) { 995 | const { isSuccess, data, response } = await requestApi('https://article-api.smzdm.com/ranking_list/articles', { 996 | headers: this.getHeaders(), 997 | data: { 998 | offset: 0, 999 | channel_id: 76, 1000 | tab: 2, 1001 | order: 0, 1002 | limit: 20, 1003 | exclude_article_ids: '', 1004 | stream: 'a', 1005 | ab_code: 'b' 1006 | } 1007 | }); 1008 | 1009 | if (isSuccess) { 1010 | // 取前 num 个做任务 1011 | return data.data.rows.slice(0, num); 1012 | } 1013 | else { 1014 | this.$env.log(`获取文章列表失败: ${response}`); 1015 | return []; 1016 | } 1017 | } 1018 | 1019 | async getRobotToken() { 1020 | const { isSuccess, data, response } = await requestApi('https://user-api.smzdm.com/robot/token', { 1021 | method: 'post', 1022 | headers: this.getHeaders() 1023 | }); 1024 | 1025 | if (isSuccess) { 1026 | return data.data.token; 1027 | } 1028 | else { 1029 | this.$env.log(`Robot Token 获取失败!${response}`); 1030 | 1031 | return false; 1032 | } 1033 | } 1034 | 1035 | // 获取栏目信息 1036 | async getTagDetail(id) { 1037 | const { isSuccess, data, response } = await requestApi('https://common-api.smzdm.com/lanmu/config_data', { 1038 | headers: this.getHeaders(), 1039 | data: { 1040 | middle_page: '', 1041 | tab_selects: '', 1042 | redirect_params: id 1043 | } 1044 | }); 1045 | 1046 | if (isSuccess) { 1047 | return data.data; 1048 | } 1049 | else { 1050 | this.$env.log(`获取栏目信息失败!${response}`); 1051 | 1052 | return {}; 1053 | } 1054 | } 1055 | 1056 | // 获取栏目列表 1057 | async getTagByRandom() { 1058 | const { isSuccess, data, response } = await requestApi('https://dingyue-api.smzdm.com/tuijian/search_result', { 1059 | headers: this.getHeaders(), 1060 | data: { 1061 | time_code: '', 1062 | nav_id: '', 1063 | type: 'tag', 1064 | limit: 20 1065 | } 1066 | }); 1067 | 1068 | if (isSuccess) { 1069 | return data.data.rows[Math.floor(Math.random() * data.data.rows.length)]; 1070 | } 1071 | else { 1072 | this.$env.log(`获取栏目列表失败!${response}`); 1073 | 1074 | return false; 1075 | } 1076 | } 1077 | 1078 | // 获取文章详情 1079 | async getArticleDetail(id) { 1080 | const { isSuccess, data, response } = await requestApi(`https://article-api.smzdm.com/article_detail/${id}`, { 1081 | headers: this.getHeaders(), 1082 | data: { 1083 | comment_flow: '', 1084 | hashcode: '', 1085 | lastest_update_time: '', 1086 | uhome: 0, 1087 | imgmode: 0, 1088 | article_channel_id: 0, 1089 | h5hash: '' 1090 | } 1091 | }); 1092 | 1093 | if (isSuccess) { 1094 | return data.data; 1095 | } 1096 | else { 1097 | this.$env.log(`获取文章详情失败!${response}`); 1098 | 1099 | return false; 1100 | } 1101 | } 1102 | 1103 | // 获取好价详情 1104 | async getHaojiaDetail(id) { 1105 | const { isSuccess, data, response } = await requestApi(`https://haojia-api.smzdm.com/detail/${id}`, { 1106 | headers: this.getHeaders(), 1107 | data: { 1108 | imgmode: 0, 1109 | hashcode: '', 1110 | h5hash: '' 1111 | } 1112 | }); 1113 | 1114 | if (isSuccess) { 1115 | return data.data; 1116 | } 1117 | else { 1118 | this.$env.log(`获取好价详情失败!${response}`); 1119 | 1120 | return false; 1121 | } 1122 | } 1123 | 1124 | // 收藏 1125 | async favorite({id, channelId, method}) { 1126 | const { isSuccess, response } = await requestApi(`https://user-api.smzdm.com/favorites/${method}`, { 1127 | method: 'post', 1128 | headers: this.getHeaders(), 1129 | data: { 1130 | touchstone_event: this.getTouchstoneEvent({ 1131 | event_value: { 1132 | aid: id, 1133 | cid: channelId, 1134 | is_detail: true 1135 | }, 1136 | sourceMode: '我的_我的任务页', 1137 | sourcePage: `Android/长图文/P/${id}/`, 1138 | upperLevel_url: '个人中心/赚奖励/' 1139 | }), 1140 | token: this.token, 1141 | id, 1142 | channel_id: channelId 1143 | } 1144 | }); 1145 | 1146 | if (isSuccess) { 1147 | this.$env.log(`${method} 收藏成功: ${id}`); 1148 | } 1149 | else { 1150 | this.$env.log(`${method} 收藏失败!${response}`); 1151 | } 1152 | 1153 | return { 1154 | isSuccess, 1155 | response 1156 | }; 1157 | } 1158 | 1159 | getTouchstoneEvent(obj) { 1160 | const defaultObj = { 1161 | search_tv: 'f', 1162 | sourceRoot: '个人中心', 1163 | trafic_version: '113_a,115_b,116_e,118_b,131_b,132_b,134_b,136_b,139_a,144_a,150_b,153_a,179_a,183_b,185_b,188_b,189_b,193_a,196_b,201_a,204_a,205_a,208_b,222_b,226_a,228_a,22_b,230_b,232_b,239_b,254_a,255_b,256_b,258_b,260_b,265_a,267_a,269_a,270_c,273_b,276_a,278_a,27_a,280_a,281_a,283_b,286_a,287_a,290_a,291_b,295_a,302_a,306_b,308_b,312_b,314_a,317_a,318_a,322_b,325_a,326_a,329_b,32_c,332_b,337_c,341_a,347_a,349_b,34_a,351_a,353_b,355_a,357_b,366_b,373_B,376_b,378_b,380_b,388_b,391_b,401_d,403_b,405_b,407_b,416_a,421_a,424_b,425_b,427_a,436_b,43_j,440_a,442_a,444_b,448_a,450_b,451_b,454_b,455_a,458_c,460_a,463_c,464_b,466_b,467_b,46_a,470_b,471_b,474_b,475_a,484_b,489_a,494_b,496_b,498_a,500_a,503_b,507_b,510_bb,512_b,515_a,520_a,522_b,525_c,527_b,528_a,59_a,65_b,85_b,102_b,103_a,106_b,107_b,10_f,11_b,120_a,143_b,157_g,158_c,159_c,160_f,161_d,162_e,163_a,164_a,165_a,166_f,171_a,174_a,175_e,176_d,209_b,225_a,235_a,236_b,237_c,272_b,296_c,2_f,309_a,315_b,334_a,335_d,339_b,346_b,361_b,362_d,367_b,368_a,369_e,374_b,381_c,382_b,383_d,385_b,386_c,389_i,38_b,390_d,396_a,398_b,3_a,413_a,417_a,418_c,419_b,420_b,422_e,428_a,430_a,431_d,432_e,433_a,437_b,438_c,478_b,479_b,47_a,480_a,481_b,482_a,483_a,488_b,491_j,492_j,504_b,505_a,514_a,518_b,52_d,53_d,54_v,55_z1,56_z3,66_a,67_i,68_a1,69_i,74_i,77_d,93_a', 1164 | tv: 'z1' 1165 | }; 1166 | 1167 | return JSON.stringify({...defaultObj, ...obj}); 1168 | } 1169 | 1170 | // 关注品牌 1171 | async followBrand({keywordId, keyword, method}) { 1172 | const touchstone = this.getTouchstoneEvent({ 1173 | event_value: { 1174 | cid: '44', 1175 | is_detail: true, 1176 | aid: String(keywordId) 1177 | }, 1178 | sourceMode: '百科_品牌详情页', 1179 | sourcePage: `Android/其他/品牌详情页/${keyword}/${keywordId}/`, 1180 | upperLevel_url: '个人中心/赚奖励/' 1181 | }); 1182 | 1183 | const { isSuccess, response } = await requestApi(`https://dingyue-api.smzdm.com/dy/util/api/user_action`, { 1184 | method: 'post', 1185 | headers: this.getHeaders(), 1186 | data: { 1187 | action: method, 1188 | params: JSON.stringify({ 1189 | keyword: keywordId, 1190 | keyword_id: keywordId, 1191 | type: 'brand' 1192 | }), 1193 | refer: `Android/其他/品牌详情页/${keyword}/${keywordId}/`, 1194 | touchstone_event: touchstone 1195 | } 1196 | }); 1197 | 1198 | if (isSuccess) { 1199 | this.$env.log(`${method} 关注成功: ${keyword}`); 1200 | } 1201 | else { 1202 | this.$env.log(`${method} 关注失败!${response}`); 1203 | } 1204 | 1205 | return { 1206 | isSuccess, 1207 | response 1208 | }; 1209 | } 1210 | 1211 | // 获取品牌信息 1212 | async getBrandDetail(id) { 1213 | const { isSuccess, data, response } = await requestApi('https://brand-api.smzdm.com/brand/brand_basic', { 1214 | headers: this.getHeaders(), 1215 | data: { 1216 | brand_id: id 1217 | } 1218 | }); 1219 | 1220 | if (isSuccess) { 1221 | return data.data; 1222 | } 1223 | else { 1224 | this.$env.log(`获取品牌信息失败!${response}`); 1225 | 1226 | return {}; 1227 | } 1228 | } 1229 | 1230 | // 根据栏目信息获取文章列表 1231 | async getArticleListFromLanmu(id, num = 1) { 1232 | const lanmuDetail = await this.getTagDetail(id); 1233 | 1234 | if (!lanmuDetail.lanmu_id) { 1235 | return []; 1236 | } 1237 | 1238 | const { isSuccess, data, response } = await requestApi('https://common-api.smzdm.com/lanmu/list_data', { 1239 | headers: this.getHeaders(), 1240 | data: { 1241 | price_lt: '', 1242 | order: '', 1243 | category_ids: '', 1244 | price_gt: '', 1245 | referer_article: '', 1246 | tag_params: '', 1247 | mall_ids: '', 1248 | time_sort: '', 1249 | page: 1, 1250 | params: id, 1251 | limit: 20, 1252 | tab_params: lanmuDetail.tab[0].params 1253 | } 1254 | }); 1255 | 1256 | if (isSuccess) { 1257 | // 取前 num 个做任务 1258 | return data.data.rows.slice(0, num); 1259 | } 1260 | else { 1261 | this.$env.log(`获取文章列表失败: ${response}`); 1262 | return []; 1263 | } 1264 | } 1265 | 1266 | // 点赞 1267 | async rating({id, channelId, method, type}) { 1268 | const { isSuccess, response } = await requestApi(`https://user-api.smzdm.com/rating/${method}`, { 1269 | method: 'post', 1270 | headers: this.getHeaders(), 1271 | data: { 1272 | touchstone_event: this.getTouchstoneEvent({ 1273 | event_value: { 1274 | aid: id, 1275 | cid: channelId, 1276 | is_detail: true 1277 | }, 1278 | sourceMode: '栏目页', 1279 | sourcePage: `Android//P/${id}/`, 1280 | upperLevel_url: '栏目页///' 1281 | }), 1282 | token: this.token, 1283 | id, 1284 | channel_id: channelId, 1285 | wtype: type 1286 | } 1287 | }); 1288 | 1289 | if (isSuccess) { 1290 | this.$env.log(`${method} 点赞成功: ${id}`); 1291 | } 1292 | else { 1293 | this.$env.log(`${method} 点赞失败!${response}`); 1294 | } 1295 | 1296 | return { 1297 | isSuccess, 1298 | response 1299 | }; 1300 | } 1301 | 1302 | // 发表评论 1303 | async submitComment({ articleId, channelId, content }) { 1304 | const { isSuccess, data, response } = await requestApi('https://comment-api.smzdm.com/comments/submit', { 1305 | method: 'post', 1306 | headers: this.getHeaders(), 1307 | data: { 1308 | touchstone_event: this.getTouchstoneEvent({ 1309 | event_value: { 1310 | aid: articleId, 1311 | cid: channelId, 1312 | is_detail: true 1313 | }, 1314 | sourceMode: '好物社区_全部', 1315 | sourcePage: `Android/长图文/${articleId}/评论页/`, 1316 | upperLevel_url: '好物社区/首页/全部/', 1317 | sourceRoot: '社区' 1318 | }), 1319 | is_like: 3, 1320 | reply_from: 3, 1321 | smiles: 0, 1322 | atta: 0, 1323 | parentid: 0, 1324 | token: this.token, 1325 | article_id: articleId, 1326 | channel_id: channelId, 1327 | content 1328 | } 1329 | }); 1330 | 1331 | if (isSuccess) { 1332 | this.$env.log(`评论发表成功: ${data.data.comment_ID}`); 1333 | } 1334 | else { 1335 | this.$env.log(`评论发表失败!${response}`); 1336 | } 1337 | 1338 | return { 1339 | isSuccess, 1340 | data, 1341 | response 1342 | }; 1343 | } 1344 | 1345 | // 删除评论 1346 | async removeComment(id) { 1347 | const { isSuccess, response } = await requestApi('https://comment-api.smzdm.com/comments/delete_comment', { 1348 | method: 'post', 1349 | headers: this.getHeaders(), 1350 | data: { 1351 | comment_id: id 1352 | } 1353 | }); 1354 | 1355 | if (isSuccess) { 1356 | this.$env.log(`评论删除成功: ${id}`); 1357 | } 1358 | else { 1359 | this.$env.log(`评论删除失败!${response}`); 1360 | } 1361 | 1362 | return { 1363 | isSuccess, 1364 | response 1365 | }; 1366 | } 1367 | 1368 | // 获取 Dingyue 状态 1369 | async getDingyueStatus(name) { 1370 | const { isSuccess, data, response } = await requestApi('https://dingyue-api.smzdm.com/dingyue/follow_status', { 1371 | method: 'post', 1372 | headers: this.getHeaders(), 1373 | data: { 1374 | rules: JSON.stringify([{ 1375 | type: 'tag', 1376 | keyword: name 1377 | }]) 1378 | } 1379 | }); 1380 | 1381 | if (isSuccess) { 1382 | return data; 1383 | } 1384 | else { 1385 | this.$env.log(`获取订阅状态失败: ${response}`); 1386 | return {}; 1387 | } 1388 | } 1389 | 1390 | // 根据 Tag ID 获取文章列表 1391 | async getArticleListFromTag(id, name, num = 1) { 1392 | const status = this.getDingyueStatus(name); 1393 | 1394 | const { isSuccess, data, response } = await requestApi('https://tag-api.smzdm.com/theme/detail_feed', { 1395 | headers: this.getHeaders(), 1396 | data: { 1397 | article_source: 1, 1398 | past_num: 0, 1399 | feed_sort: 2, 1400 | smzdm_id: status.smzdm_id, 1401 | tag_id: id, 1402 | name, 1403 | time_sort: 0, 1404 | page: 1, 1405 | article_tab: 0, 1406 | limit: 20 1407 | } 1408 | }); 1409 | 1410 | if (isSuccess) { 1411 | // 取前 num 个做任务 1412 | return data.data.rows.slice(0, num); 1413 | } 1414 | else { 1415 | this.$env.log(`获取文章列表失败: ${response}`); 1416 | return []; 1417 | } 1418 | } 1419 | 1420 | // 通过 url 获取文章 channel_id 1421 | async getArticleChannelIdForTesting(url) { 1422 | const { isSuccess, response } = await requestApi(url, { 1423 | method: 'get', 1424 | headers: this.getHeaders(), 1425 | parseJSON: false, 1426 | sign: false 1427 | }); 1428 | 1429 | if (!isSuccess) { 1430 | this.$env.log(`获取文章信息失败!${response}`); 1431 | 1432 | return false; 1433 | } 1434 | 1435 | // 通过正则提取页面中的 channel_id 1436 | const re = /'channel_id'\s*:\s*'(\d+)'/; 1437 | const matchRet = response.match(re); 1438 | 1439 | if (!matchRet) { 1440 | this.$env.log(`获取文章信息失败!${response}`); 1441 | 1442 | return false; 1443 | } 1444 | 1445 | return matchRet[1]; 1446 | } 1447 | } 1448 | 1449 | module.exports = { 1450 | SmzdmTaskBot 1451 | }; 1452 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "smzdm-script", 3 | "version": "1.0.0", 4 | "description": "smzdm 自用脚本 for 青龙面板,支持 App 端签到、转盘抽奖、每日任务等功能", 5 | "main": "smzdm_checkin.js", 6 | "scripts": { 7 | "lint": "eslint --cache --max-warnings 0 \"./*.{js,ts}\" --ignore-path .gitignore" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/hex-ci/smzdm_script.git" 12 | }, 13 | "author": "Hex", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/hex-ci/smzdm_script/issues" 17 | }, 18 | "homepage": "https://github.com/hex-ci/smzdm_script", 19 | "devDependencies": { 20 | "eslint": "^8.36.0" 21 | }, 22 | "dependencies": { 23 | "crypto-js": "^4.1.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sendNotify.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: lxk0301 https://gitee.com/lxk0301 3 | * @Date: 2020-08-19 16:12:40 4 | * @Last Modified by: whyour 5 | * @Last Modified time: 2021-5-1 15:00:54 6 | * sendNotify 推送通知功能 7 | * @param text 通知头 8 | * @param desp 通知体 9 | * @param params 某些推送通知方式点击弹窗可跳转, 例:{ url: 'https://abc.com' } 10 | * @param author 作者仓库等信息 例:`本通知 By:https://github.com/whyour/qinglong` 11 | */ 12 | 13 | const querystring = require('querystring'); 14 | const $ = new Env(); 15 | const timeout = 15000; //超时时间(单位毫秒) 16 | // =======================================gotify通知设置区域============================================== 17 | //gotify_url 填写gotify地址,如https://push.example.de:8080 18 | //gotify_token 填写gotify的消息应用token 19 | //gotify_priority 填写推送消息优先级,默认为0 20 | let GOTIFY_URL = ''; 21 | let GOTIFY_TOKEN = ''; 22 | let GOTIFY_PRIORITY = 0; 23 | // =======================================go-cqhttp通知设置区域=========================================== 24 | //gobot_url 填写请求地址http://127.0.0.1/send_private_msg 25 | //gobot_token 填写在go-cqhttp文件设置的访问密钥 26 | //gobot_qq 填写推送到个人QQ或者QQ群号 27 | //go-cqhttp相关API https://docs.go-cqhttp.org/api 28 | let GOBOT_URL = ''; // 推送到个人QQ: http://127.0.0.1/send_private_msg 群:http://127.0.0.1/send_group_msg 29 | let GOBOT_TOKEN = ''; //访问密钥 30 | let GOBOT_QQ = ''; // 如果GOBOT_URL设置 /send_private_msg 则需要填入 user_id=个人QQ 相反如果是 /send_group_msg 则需要填入 group_id=QQ群 31 | 32 | // =======================================微信server酱通知设置区域=========================================== 33 | //此处填你申请的SCKEY. 34 | //(环境变量名 PUSH_KEY) 35 | let SCKEY = ''; 36 | 37 | // =======================================Bark App通知设置区域=========================================== 38 | //此处填你BarkAPP的信息(IP/设备码,例如:https://api.day.app/XXXXXXXX) 39 | let BARK_PUSH = ''; 40 | //BARK app推送图标,自定义推送图标(需iOS15或以上) 41 | let BARK_ICON = 'https://qn.whyour.cn/logo.png'; 42 | //BARK app推送铃声,铃声列表去APP查看复制填写 43 | let BARK_SOUND = ''; 44 | //BARK app推送消息的分组, 默认为"QingLong" 45 | let BARK_GROUP = 'QingLong'; 46 | 47 | // =======================================telegram机器人通知设置区域=========================================== 48 | //此处填你telegram bot 的Token,telegram机器人通知推送必填项.例如:1077xxx4424:AAFjv0FcqxxxxxxgEMGfi22B4yh15R5uw 49 | //(环境变量名 TG_BOT_TOKEN) 50 | let TG_BOT_TOKEN = ''; 51 | //此处填你接收通知消息的telegram用户的id,telegram机器人通知推送必填项.例如:129xxx206 52 | //(环境变量名 TG_USER_ID) 53 | let TG_USER_ID = ''; 54 | //tg推送HTTP代理设置(不懂可忽略,telegram机器人通知推送功能中非必填) 55 | let TG_PROXY_HOST = ''; //例如:127.0.0.1(环境变量名:TG_PROXY_HOST) 56 | let TG_PROXY_PORT = ''; //例如:1080(环境变量名:TG_PROXY_PORT) 57 | let TG_PROXY_AUTH = ''; //tg代理配置认证参数 58 | //Telegram api自建的反向代理地址(不懂可忽略,telegram机器人通知推送功能中非必填),默认tg官方api(环境变量名:TG_API_HOST) 59 | let TG_API_HOST = 'api.telegram.org'; 60 | // =======================================钉钉机器人通知设置区域=========================================== 61 | //此处填你钉钉 bot 的webhook,例如:5a544165465465645d0f31dca676e7bd07415asdasd 62 | //(环境变量名 DD_BOT_TOKEN) 63 | let DD_BOT_TOKEN = ''; 64 | //密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的字符串 65 | let DD_BOT_SECRET = ''; 66 | 67 | // =======================================企业微信机器人通知设置区域=========================================== 68 | //此处填你企业微信机器人的 webhook(详见文档 https://work.weixin.qq.com/api/doc/90000/90136/91770),例如:693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa 69 | //(环境变量名 QYWX_KEY) 70 | let QYWX_KEY = ''; 71 | 72 | // =======================================企业微信应用消息通知设置区域=========================================== 73 | /* 74 | 此处填你企业微信应用消息的值(详见文档 https://work.weixin.qq.com/api/doc/90000/90135/90236) 75 | 环境变量名 QYWX_AM依次填入 corpid,corpsecret,touser(注:多个成员ID使用|隔开),agentid,消息类型(选填,不填默认文本消息类型) 76 | 注意用,号隔开(英文输入法的逗号),例如:wwcff56746d9adwers,B-791548lnzXBE6_BWfxdf3kSTMJr9vFEPKAbh6WERQ,mingcheng,1000001,2COXgjH2UIfERF2zxrtUOKgQ9XklUqMdGSWLBoW_lSDAdafat 77 | 可选推送消息类型(推荐使用图文消息(mpnews)): 78 | - 文本卡片消息: 0 (数字零) 79 | - 文本消息: 1 (数字一) 80 | - 图文消息(mpnews): 素材库图片id, 可查看此教程(http://note.youdao.com/s/HMiudGkb)或者(https://note.youdao.com/ynoteshare1/index.html?id=1a0c8aff284ad28cbd011b29b3ad0191&type=note) 81 | */ 82 | let QYWX_AM = ''; 83 | 84 | // =======================================iGot聚合推送通知设置区域=========================================== 85 | //此处填您iGot的信息(推送key,例如:https://push.hellyw.com/XXXXXXXX) 86 | let IGOT_PUSH_KEY = ''; 87 | 88 | // =======================================push+设置区域======================================= 89 | //官方文档:http://www.pushplus.plus/ 90 | //PUSH_PLUS_TOKEN:微信扫码登录后一对一推送或一对多推送下面的token(您的Token),不提供PUSH_PLUS_USER则默认为一对一推送 91 | //PUSH_PLUS_USER: 一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送) 92 | let PUSH_PLUS_TOKEN = ''; 93 | let PUSH_PLUS_USER = ''; 94 | 95 | //==========================云端环境变量的判断与接收========================= 96 | if (process.env.GOTIFY_URL) { 97 | GOTIFY_URL = process.env.GOTIFY_URL; 98 | } 99 | if (process.env.GOTIFY_TOKEN) { 100 | GOTIFY_TOKEN = process.env.GOTIFY_TOKEN; 101 | } 102 | if (process.env.GOTIFY_PRIORITY) { 103 | GOTIFY_PRIORITY = process.env.GOTIFY_PRIORITY; 104 | } 105 | 106 | if (process.env.GOBOT_URL) { 107 | GOBOT_URL = process.env.GOBOT_URL; 108 | } 109 | if (process.env.GOBOT_TOKEN) { 110 | GOBOT_TOKEN = process.env.GOBOT_TOKEN; 111 | } 112 | if (process.env.GOBOT_QQ) { 113 | GOBOT_QQ = process.env.GOBOT_QQ; 114 | } 115 | 116 | if (process.env.PUSH_KEY) { 117 | SCKEY = process.env.PUSH_KEY; 118 | } 119 | 120 | if (process.env.BARK_PUSH) { 121 | if ( 122 | process.env.BARK_PUSH.indexOf('https') > -1 || 123 | process.env.BARK_PUSH.indexOf('http') > -1 124 | ) { 125 | //兼容BARK自建用户 126 | BARK_PUSH = process.env.BARK_PUSH; 127 | } 128 | else { 129 | BARK_PUSH = `https://api.day.app/${process.env.BARK_PUSH}`; 130 | } 131 | if (process.env.BARK_ICON) { 132 | BARK_ICON = process.env.BARK_ICON; 133 | } 134 | if (process.env.BARK_SOUND) { 135 | BARK_SOUND = process.env.BARK_SOUND; 136 | } 137 | if (process.env.BARK_GROUP) { 138 | BARK_GROUP = process.env.BARK_GROUP; 139 | } 140 | } 141 | else { 142 | if ( 143 | BARK_PUSH && 144 | BARK_PUSH.indexOf('https') === -1 && 145 | BARK_PUSH.indexOf('http') === -1 146 | ) { 147 | //兼容BARK本地用户只填写设备码的情况 148 | BARK_PUSH = `https://api.day.app/${BARK_PUSH}`; 149 | } 150 | } 151 | if (process.env.TG_BOT_TOKEN) { 152 | TG_BOT_TOKEN = process.env.TG_BOT_TOKEN; 153 | } 154 | if (process.env.TG_USER_ID) { 155 | TG_USER_ID = process.env.TG_USER_ID; 156 | } 157 | if (process.env.TG_PROXY_AUTH) {TG_PROXY_AUTH = process.env.TG_PROXY_AUTH;} 158 | if (process.env.TG_PROXY_HOST) {TG_PROXY_HOST = process.env.TG_PROXY_HOST;} 159 | if (process.env.TG_PROXY_PORT) {TG_PROXY_PORT = process.env.TG_PROXY_PORT;} 160 | if (process.env.TG_API_HOST) {TG_API_HOST = process.env.TG_API_HOST;} 161 | 162 | if (process.env.DD_BOT_TOKEN) { 163 | DD_BOT_TOKEN = process.env.DD_BOT_TOKEN; 164 | if (process.env.DD_BOT_SECRET) { 165 | DD_BOT_SECRET = process.env.DD_BOT_SECRET; 166 | } 167 | } 168 | 169 | if (process.env.QYWX_KEY) { 170 | QYWX_KEY = process.env.QYWX_KEY; 171 | } 172 | 173 | if (process.env.QYWX_AM) { 174 | QYWX_AM = process.env.QYWX_AM; 175 | } 176 | 177 | if (process.env.IGOT_PUSH_KEY) { 178 | IGOT_PUSH_KEY = process.env.IGOT_PUSH_KEY; 179 | } 180 | 181 | if (process.env.PUSH_PLUS_TOKEN) { 182 | PUSH_PLUS_TOKEN = process.env.PUSH_PLUS_TOKEN; 183 | } 184 | if (process.env.PUSH_PLUS_USER) { 185 | PUSH_PLUS_USER = process.env.PUSH_PLUS_USER; 186 | } 187 | //==========================云端环境变量的判断与接收========================= 188 | 189 | /** 190 | * sendNotify 推送通知功能 191 | * @param text 通知头 192 | * @param desp 通知体 193 | * @param params 某些推送通知方式点击弹窗可跳转, 例:{ url: 'https://abc.com' } 194 | * @param author 作者仓库等信息 例:`本通知 By:https://github.com/whyour/qinglong` 195 | * @returns {Promise} 196 | */ 197 | async function sendNotify( 198 | text, 199 | desp, 200 | params = {}, 201 | author = '\n\n本通知 By:https://github.com/whyour/qinglong' 202 | ) { 203 | //提供6种通知 204 | desp += author; //增加作者信息,防止被贩卖等 205 | await Promise.all([ 206 | serverNotify(text, desp), //微信server酱 207 | pushPlusNotify(text, desp) //pushplus(推送加) 208 | ]); 209 | //由于上述两种微信通知需点击进去才能查看到详情,故text(标题内容)携带了账号序号以及昵称信息,方便不点击也可知道是哪个京东哪个活动 210 | text = text.match(/.*?(?=\s?-)/g) ? text.match(/.*?(?=\s?-)/g)[0] : text; 211 | await Promise.all([ 212 | BarkNotify(text, desp, params), //iOS Bark APP 213 | tgBotNotify(text, desp), //telegram 机器人 214 | ddBotNotify(text, desp), //钉钉机器人 215 | qywxBotNotify(text, desp), //企业微信机器人 216 | qywxamNotify(text, desp), //企业微信应用消息推送 217 | iGotNotify(text, desp, params), //iGot 218 | gobotNotify(text, desp), //go-cqhttp 219 | gotifyNotify(text, desp) //gotify 220 | ]); 221 | } 222 | 223 | function gotifyNotify(text, desp) { 224 | return new Promise((resolve) => { 225 | if (GOTIFY_URL && GOTIFY_TOKEN) { 226 | const options = { 227 | url: `${GOTIFY_URL}/message?token=${GOTIFY_TOKEN}`, 228 | body: `title=${encodeURIComponent(text)}&message=${encodeURIComponent( 229 | desp 230 | )}&priority=${GOTIFY_PRIORITY}`, 231 | headers: { 232 | 'Content-Type': 'application/x-www-form-urlencoded' 233 | } 234 | }; 235 | $.post(options, (err, resp, data) => { 236 | try { 237 | if (err) { 238 | console.log('gotify发送通知调用API失败!!\n'); 239 | console.log(err); 240 | } 241 | else { 242 | data = JSON.parse(data); 243 | if (data.id) { 244 | console.log('gotify发送通知消息成功🎉\n'); 245 | } 246 | else { 247 | console.log(`${data.message}\n`); 248 | } 249 | } 250 | } 251 | catch (e) { 252 | $.logErr(e, resp); 253 | } 254 | finally { 255 | resolve(); 256 | } 257 | }); 258 | } 259 | else { 260 | resolve(); 261 | } 262 | }); 263 | } 264 | 265 | function gobotNotify(text, desp, time = 2100) { 266 | return new Promise((resolve) => { 267 | if (GOBOT_URL) { 268 | const options = { 269 | url: `${GOBOT_URL}?access_token=${GOBOT_TOKEN}&${GOBOT_QQ}`, 270 | json: { message: `${text}\n${desp}` }, 271 | headers: { 272 | 'Content-Type': 'application/json' 273 | }, 274 | timeout 275 | }; 276 | setTimeout(() => { 277 | $.post(options, (err, resp, data) => { 278 | try { 279 | if (err) { 280 | console.log('发送go-cqhttp通知调用API失败!!\n'); 281 | console.log(err); 282 | } 283 | else { 284 | data = JSON.parse(data); 285 | if (data.retcode === 0) { 286 | console.log('go-cqhttp发送通知消息成功🎉\n'); 287 | } 288 | else if (data.retcode === 100) { 289 | console.log(`go-cqhttp发送通知消息异常: ${data.errmsg}\n`); 290 | } 291 | else { 292 | console.log( 293 | `go-cqhttp发送通知消息异常\n${JSON.stringify(data)}` 294 | ); 295 | } 296 | } 297 | } 298 | catch (e) { 299 | $.logErr(e, resp); 300 | } 301 | finally { 302 | resolve(data); 303 | } 304 | }); 305 | }, time); 306 | } 307 | else { 308 | resolve(); 309 | } 310 | }); 311 | } 312 | 313 | function serverNotify(text, desp, time = 2100) { 314 | return new Promise((resolve) => { 315 | if (SCKEY) { 316 | //微信server酱推送通知一个\n不会换行,需要两个\n才能换行,故做此替换 317 | desp = desp.replace(/[\n\r]/g, '\n\n'); 318 | const options = { 319 | url: SCKEY.includes('SCT') 320 | ? `https://sctapi.ftqq.com/${SCKEY}.send` 321 | : `https://sc.ftqq.com/${SCKEY}.send`, 322 | body: `text=${text}&desp=${desp}`, 323 | headers: { 324 | 'Content-Type': 'application/x-www-form-urlencoded' 325 | }, 326 | timeout 327 | }; 328 | setTimeout(() => { 329 | $.post(options, (err, resp, data) => { 330 | try { 331 | if (err) { 332 | console.log('发送通知调用API失败!!\n'); 333 | console.log(err); 334 | } 335 | else { 336 | data = JSON.parse(data); 337 | //server酱和Server酱·Turbo版的返回json格式不太一样 338 | if (data.errno === 0 || data.data.errno === 0) { 339 | console.log('server酱发送通知消息成功🎉\n'); 340 | } 341 | else if (data.errno === 1024) { 342 | // 一分钟内发送相同的内容会触发 343 | console.log(`server酱发送通知消息异常: ${data.errmsg}\n`); 344 | } 345 | else { 346 | console.log( 347 | `server酱发送通知消息异常\n${JSON.stringify(data)}` 348 | ); 349 | } 350 | } 351 | } 352 | catch (e) { 353 | $.logErr(e, resp); 354 | } 355 | finally { 356 | resolve(data); 357 | } 358 | }); 359 | }, time); 360 | } 361 | else { 362 | resolve(); 363 | } 364 | }); 365 | } 366 | 367 | function BarkNotify(text, desp, params = {}) { 368 | return new Promise((resolve) => { 369 | if (BARK_PUSH) { 370 | const options = { 371 | url: `${BARK_PUSH}/${encodeURIComponent(text)}/${encodeURIComponent( 372 | desp 373 | )}?icon=${BARK_ICON}?sound=${BARK_SOUND}&group=${BARK_GROUP}&${querystring.stringify( 374 | params 375 | )}`, 376 | headers: { 377 | 'Content-Type': 'application/x-www-form-urlencoded' 378 | }, 379 | timeout 380 | }; 381 | $.get(options, (err, resp, data) => { 382 | try { 383 | if (err) { 384 | console.log('Bark APP发送通知调用API失败!!\n'); 385 | console.log(err); 386 | } 387 | else { 388 | data = JSON.parse(data); 389 | if (data.code === 200) { 390 | console.log('Bark APP发送通知消息成功🎉\n'); 391 | } 392 | else { 393 | console.log(`${data.message}\n`); 394 | } 395 | } 396 | } 397 | catch (e) { 398 | $.logErr(e, resp); 399 | } 400 | finally { 401 | resolve(); 402 | } 403 | }); 404 | } 405 | else { 406 | resolve(); 407 | } 408 | }); 409 | } 410 | 411 | function tgBotNotify(text, desp) { 412 | return new Promise((resolve) => { 413 | if (TG_BOT_TOKEN && TG_USER_ID) { 414 | const options = { 415 | url: `https://${TG_API_HOST}/bot${TG_BOT_TOKEN}/sendMessage`, 416 | body: `chat_id=${TG_USER_ID}&text=${text}\n\n${desp}&disable_web_page_preview=true`, 417 | headers: { 418 | 'Content-Type': 'application/x-www-form-urlencoded' 419 | }, 420 | timeout 421 | }; 422 | if (TG_PROXY_HOST && TG_PROXY_PORT) { 423 | const tunnel = require('tunnel'); 424 | const agent = { 425 | https: tunnel.httpsOverHttp({ 426 | proxy: { 427 | host: TG_PROXY_HOST, 428 | port: TG_PROXY_PORT * 1, 429 | proxyAuth: TG_PROXY_AUTH 430 | } 431 | }) 432 | }; 433 | Object.assign(options, { agent }); 434 | } 435 | $.post(options, (err, resp, data) => { 436 | try { 437 | if (err) { 438 | console.log('telegram发送通知消息失败!!\n'); 439 | console.log(err); 440 | } 441 | else { 442 | data = JSON.parse(data); 443 | if (data.ok) { 444 | console.log('Telegram发送通知消息成功🎉。\n'); 445 | } 446 | else if (data.error_code === 400) { 447 | console.log( 448 | '请主动给bot发送一条消息并检查接收用户ID是否正确。\n' 449 | ); 450 | } 451 | else if (data.error_code === 401) { 452 | console.log('Telegram bot token 填写错误。\n'); 453 | } 454 | } 455 | } 456 | catch (e) { 457 | $.logErr(e, resp); 458 | } 459 | finally { 460 | resolve(data); 461 | } 462 | }); 463 | } 464 | else { 465 | resolve(); 466 | } 467 | }); 468 | } 469 | function ddBotNotify(text, desp) { 470 | return new Promise((resolve) => { 471 | const options = { 472 | url: `https://oapi.dingtalk.com/robot/send?access_token=${DD_BOT_TOKEN}`, 473 | json: { 474 | msgtype: 'text', 475 | text: { 476 | content: ` ${text}\n\n${desp}` 477 | } 478 | }, 479 | headers: { 480 | 'Content-Type': 'application/json' 481 | }, 482 | timeout 483 | }; 484 | if (DD_BOT_TOKEN && DD_BOT_SECRET) { 485 | const crypto = require('crypto'); 486 | const dateNow = Date.now(); 487 | const hmac = crypto.createHmac('sha256', DD_BOT_SECRET); 488 | hmac.update(`${dateNow}\n${DD_BOT_SECRET}`); 489 | const result = encodeURIComponent(hmac.digest('base64')); 490 | options.url = `${options.url}×tamp=${dateNow}&sign=${result}`; 491 | $.post(options, (err, resp, data) => { 492 | try { 493 | if (err) { 494 | console.log('钉钉发送通知消息失败!!\n'); 495 | console.log(err); 496 | } 497 | else { 498 | data = JSON.parse(data); 499 | if (data.errcode === 0) { 500 | console.log('钉钉发送通知消息成功🎉。\n'); 501 | } 502 | else { 503 | console.log(`${data.errmsg}\n`); 504 | } 505 | } 506 | } 507 | catch (e) { 508 | $.logErr(e, resp); 509 | } 510 | finally { 511 | resolve(data); 512 | } 513 | }); 514 | } 515 | else if (DD_BOT_TOKEN) { 516 | $.post(options, (err, resp, data) => { 517 | try { 518 | if (err) { 519 | console.log('钉钉发送通知消息失败!!\n'); 520 | console.log(err); 521 | } 522 | else { 523 | data = JSON.parse(data); 524 | if (data.errcode === 0) { 525 | console.log('钉钉发送通知消息完成。\n'); 526 | } 527 | else { 528 | console.log(`${data.errmsg}\n`); 529 | } 530 | } 531 | } 532 | catch (e) { 533 | $.logErr(e, resp); 534 | } 535 | finally { 536 | resolve(data); 537 | } 538 | }); 539 | } 540 | else { 541 | resolve(); 542 | } 543 | }); 544 | } 545 | 546 | function qywxBotNotify(text, desp) { 547 | return new Promise((resolve) => { 548 | const options = { 549 | url: `https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${QYWX_KEY}`, 550 | json: { 551 | msgtype: 'text', 552 | text: { 553 | content: ` ${text}\n\n${desp}` 554 | } 555 | }, 556 | headers: { 557 | 'Content-Type': 'application/json' 558 | }, 559 | timeout 560 | }; 561 | if (QYWX_KEY) { 562 | $.post(options, (err, resp, data) => { 563 | try { 564 | if (err) { 565 | console.log('企业微信发送通知消息失败!!\n'); 566 | console.log(err); 567 | } 568 | else { 569 | data = JSON.parse(data); 570 | if (data.errcode === 0) { 571 | console.log('企业微信发送通知消息成功🎉。\n'); 572 | } 573 | else { 574 | console.log(`${data.errmsg}\n`); 575 | } 576 | } 577 | } 578 | catch (e) { 579 | $.logErr(e, resp); 580 | } 581 | finally { 582 | resolve(data); 583 | } 584 | }); 585 | } 586 | else { 587 | resolve(); 588 | } 589 | }); 590 | } 591 | 592 | function ChangeUserId(desp) { 593 | const QYWX_AM_AY = QYWX_AM.split(','); 594 | if (QYWX_AM_AY[2]) { 595 | const userIdTmp = QYWX_AM_AY[2].split('|'); 596 | let userId = ''; 597 | for (let i = 0; i < userIdTmp.length; i++) { 598 | const count2 = '签到号 ' + (i + 1); 599 | if (desp.match(count2)) { 600 | userId = userIdTmp[i]; 601 | } 602 | } 603 | if (!userId) {userId = QYWX_AM_AY[2];} 604 | return userId; 605 | } 606 | else { 607 | return '@all'; 608 | } 609 | } 610 | 611 | function qywxamNotify(text, desp) { 612 | return new Promise((resolve) => { 613 | if (QYWX_AM) { 614 | const QYWX_AM_AY = QYWX_AM.split(','); 615 | const options_accesstoken = { 616 | url: `https://qyapi.weixin.qq.com/cgi-bin/gettoken`, 617 | json: { 618 | corpid: `${QYWX_AM_AY[0]}`, 619 | corpsecret: `${QYWX_AM_AY[1]}` 620 | }, 621 | headers: { 622 | 'Content-Type': 'application/json' 623 | }, 624 | timeout 625 | }; 626 | $.post(options_accesstoken, (err, resp, data) => { 627 | const html = desp.replace(/\n/g, '
'); 628 | const json = JSON.parse(data); 629 | const accesstoken = json.access_token; 630 | let options; 631 | 632 | switch (QYWX_AM_AY[4]) { 633 | case '0': 634 | options = { 635 | msgtype: 'textcard', 636 | textcard: { 637 | title: `${text}`, 638 | description: `${desp}`, 639 | url: 'https://github.com/whyour/qinglong', 640 | btntxt: '更多' 641 | } 642 | }; 643 | break; 644 | 645 | case '1': 646 | options = { 647 | msgtype: 'text', 648 | text: { 649 | content: `${text}\n\n${desp}` 650 | } 651 | }; 652 | break; 653 | 654 | default: 655 | options = { 656 | msgtype: 'mpnews', 657 | mpnews: { 658 | articles: [ 659 | { 660 | title: `${text}`, 661 | thumb_media_id: `${QYWX_AM_AY[4]}`, 662 | author: `智能助手`, 663 | content_source_url: ``, 664 | content: `${html}`, 665 | digest: `${desp}` 666 | } 667 | ] 668 | } 669 | }; 670 | } 671 | if (!QYWX_AM_AY[4]) { 672 | //如不提供第四个参数,则默认进行文本消息类型推送 673 | options = { 674 | msgtype: 'text', 675 | text: { 676 | content: `${text}\n\n${desp}` 677 | } 678 | }; 679 | } 680 | options = { 681 | url: `https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${accesstoken}`, 682 | json: { 683 | touser: `${ChangeUserId(desp)}`, 684 | agentid: `${QYWX_AM_AY[3]}`, 685 | safe: '0', 686 | ...options 687 | }, 688 | headers: { 689 | 'Content-Type': 'application/json' 690 | } 691 | }; 692 | 693 | $.post(options, (err, resp, data) => { 694 | try { 695 | if (err) { 696 | console.log( 697 | '成员ID:' + 698 | ChangeUserId(desp) + 699 | '企业微信应用消息发送通知消息失败!!\n' 700 | ); 701 | console.log(err); 702 | } 703 | else { 704 | data = JSON.parse(data); 705 | if (data.errcode === 0) { 706 | console.log( 707 | '成员ID:' + 708 | ChangeUserId(desp) + 709 | '企业微信应用消息发送通知消息成功🎉。\n' 710 | ); 711 | } 712 | else { 713 | console.log(`${data.errmsg}\n`); 714 | } 715 | } 716 | } 717 | catch (e) { 718 | $.logErr(e, resp); 719 | } 720 | finally { 721 | resolve(data); 722 | } 723 | }); 724 | }); 725 | } 726 | else { 727 | resolve(); 728 | } 729 | }); 730 | } 731 | 732 | function iGotNotify(text, desp, params = {}) { 733 | return new Promise((resolve) => { 734 | if (IGOT_PUSH_KEY) { 735 | // 校验传入的IGOT_PUSH_KEY是否有效 736 | const IGOT_PUSH_KEY_REGX = new RegExp('^[a-zA-Z0-9]{24}$'); 737 | if (!IGOT_PUSH_KEY_REGX.test(IGOT_PUSH_KEY)) { 738 | console.log('您所提供的IGOT_PUSH_KEY无效\n'); 739 | resolve(); 740 | return; 741 | } 742 | const options = { 743 | url: `https://push.hellyw.com/${IGOT_PUSH_KEY.toLowerCase()}`, 744 | body: `title=${text}&content=${desp}&${querystring.stringify(params)}`, 745 | headers: { 746 | 'Content-Type': 'application/x-www-form-urlencoded' 747 | }, 748 | timeout 749 | }; 750 | $.post(options, (err, resp, data) => { 751 | try { 752 | if (err) { 753 | console.log('发送通知调用API失败!!\n'); 754 | console.log(err); 755 | } 756 | else { 757 | if (typeof data === 'string') {data = JSON.parse(data);} 758 | if (data.ret === 0) { 759 | console.log('iGot发送通知消息成功🎉\n'); 760 | } 761 | else { 762 | console.log(`iGot发送通知消息失败:${data.errMsg}\n`); 763 | } 764 | } 765 | } 766 | catch (e) { 767 | $.logErr(e, resp); 768 | } 769 | finally { 770 | resolve(data); 771 | } 772 | }); 773 | } 774 | else { 775 | resolve(); 776 | } 777 | }); 778 | } 779 | 780 | function pushPlusNotify(text, desp) { 781 | return new Promise((resolve) => { 782 | if (PUSH_PLUS_TOKEN) { 783 | desp = desp.replace(/[\n\r]/g, '
'); // 默认为html, 不支持plaintext 784 | const body = { 785 | token: `${PUSH_PLUS_TOKEN}`, 786 | title: `${text}`, 787 | content: `${desp}`, 788 | topic: `${PUSH_PLUS_USER}` 789 | }; 790 | const options = { 791 | url: `https://www.pushplus.plus/send`, 792 | body: JSON.stringify(body), 793 | headers: { 794 | 'Content-Type': ' application/json' 795 | }, 796 | timeout 797 | }; 798 | $.post(options, (err, resp, data) => { 799 | try { 800 | if (err) { 801 | console.log( 802 | `push+发送${ 803 | PUSH_PLUS_USER ? '一对多' : '一对一' 804 | }通知消息失败!!\n` 805 | ); 806 | console.log(err); 807 | } 808 | else { 809 | data = JSON.parse(data); 810 | if (data.code === 200) { 811 | console.log( 812 | `push+发送${ 813 | PUSH_PLUS_USER ? '一对多' : '一对一' 814 | }通知消息完成。\n` 815 | ); 816 | } 817 | else { 818 | console.log( 819 | `push+发送${ 820 | PUSH_PLUS_USER ? '一对多' : '一对一' 821 | }通知消息失败:${data.msg}\n` 822 | ); 823 | } 824 | } 825 | } 826 | catch (e) { 827 | $.logErr(e, resp); 828 | } 829 | finally { 830 | resolve(data); 831 | } 832 | }); 833 | } 834 | else { 835 | resolve(); 836 | } 837 | }); 838 | } 839 | 840 | module.exports = { 841 | sendNotify, 842 | BARK_PUSH 843 | }; 844 | 845 | // prettier-ignore 846 | function Env(t,s) { 847 | return new class { 848 | constructor(t,s) {this.name = t,this.data = null,this.dataFile = "box.dat",this.logs = [],this.logSeparator = "\n",this.startTime = (new Date).getTime(),Object.assign(this,s),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode() {return "undefined" != typeof module && !!module.exports}isQuanX() {return "undefined" != typeof $task}isSurge() {return "undefined" != typeof $httpClient && "undefined" == typeof $loon}isLoon() {return "undefined" != typeof $loon}getScript(t) {return new Promise(s=>{$.get({url: t},(t,e,i)=>s(i))})}runScript(t,s) {return new Promise(e=>{let i = this.getdata("@chavy_boxjs_userCfgs.httpapi"); i = i ? i.replace(/\n/g,"").trim() : i; let o = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout"); o = o ? 1 * o : 20,o = s && s.timeout ? s.timeout : o; const [h,a] = i.split("@"),r = {url: `http://${a}/v1/scripting/evaluate`,body: {script_text: t,mock_type: "cron",timeout: o},headers: {"X-Key": h,Accept: "*/*"}}; $.post(r,(t,s,i)=>e(i))}).catch(t=>this.logErr(t))}loaddata() { 849 | 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),s = this.path.resolve(process.cwd(),this.dataFile),e = this.fs.existsSync(t),i = !e && this.fs.existsSync(s); if (!e && !i) {return {};} {const i = e ? t : s; try {return JSON.parse(this.fs.readFileSync(i))} 850 | catch (t) {return {}}}} 851 | }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),s = this.path.resolve(process.cwd(),this.dataFile),e = this.fs.existsSync(t),i = !e && this.fs.existsSync(s),o = JSON.stringify(this.data); e ? this.fs.writeFileSync(t,o) : i ? this.fs.writeFileSync(s,o) : this.fs.writeFileSync(t,o)}}lodash_get(t,s,e) {const i = s.replace(/\[(\d+)\]/g,".$1").split("."); let o = t; for (const t of i) {if (o = Object(o)[t],void 0 === o) {return e;}} return o}lodash_set(t,s,e) {return Object(t) !== t ? t : (Array.isArray(s) || (s = s.toString().match(/[^.[\]]+/g) || []),s.slice(0,-1).reduce((t,e,i)=>Object(t[e]) === t[e] ? t[e] : t[e] = Math.abs(s[i + 1]) >> 0 == +s[i + 1] ? [] : {},t)[s[s.length - 1]] = e,t)}getdata(t) { 852 | let s = this.getval(t); if (/^@/.test(t)) { 853 | const [,e,i] = /^@(.*?)\.(.*?)$/.exec(t),o = e ? this.getval(e) : ""; if (o) { 854 | try {const t = JSON.parse(o); s = t ? this.lodash_get(t,i,"") : s} 855 | catch (t) {s = ""} 856 | } 857 | } return s 858 | }setdata(t,s) { 859 | let e = !1; if (/^@/.test(s)) { 860 | const [,i,o] = /^@(.*?)\.(.*?)$/.exec(s),h = this.getval(i),a = i ? "null" === h ? null : h || "{}" : "{}"; try {const s = JSON.parse(a); this.lodash_set(s,o,t),e = this.setval(JSON.stringify(s),i)} 861 | catch (s) {const h = {}; this.lodash_set(h,o,t),e = this.setval(JSON.stringify(h),i)} 862 | } 863 | else {e = $.setval(t,s);} return e 864 | }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,s) {return this.isSurge() || this.isLoon() ? $persistentStore.write(t,s) : this.isQuanX() ? $prefs.setValueForKey(t,s) : this.isNode() ? (this.data = this.loaddata(),this.data[s] = t,this.writedata(),!0) : this.data && this.data[s] || 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,s = (()=>{})) { 865 | t.headers && (delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge() || this.isLoon() ? $httpClient.get(t,(t,e,i)=>{!t && e && (e.body = i,e.statusCode = e.status),s(t,e,i)}) : this.isQuanX() ? $task.fetch(t).then(t=>{const {statusCode: e,statusCode: i,headers: o,body: h} = t; s(null,{status: e,statusCode: i,headers: o,body: h},h)},t=>s(t)) : this.isNode() && (this.initGotEnv(t),this.got(t).on("redirect",(t,s)=>{ 866 | try {const e = t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString(); this.ckjar.setCookieSync(e,null),s.cookieJar = this.ckjar} 867 | catch (t) {this.logErr(t)} 868 | }).then(t=>{const {statusCode: e,statusCode: i,headers: o,body: h} = t; s(null,{status: e,statusCode: i,headers: o,body: h},h)},t=>s(t))) 869 | }post(t,s = (()=>{})) { 870 | if (t.body && t.headers && !t.headers["Content-Type"] && (t.headers["Content-Type"] = "application/x-www-form-urlencoded"),delete t.headers["Content-Length"],this.isSurge() || this.isLoon()) {$httpClient.post(t,(t,e,i)=>{!t && e && (e.body = i,e.statusCode = e.status),s(t,e,i)});} 871 | else if (this.isQuanX()) {t.method = "POST",$task.fetch(t).then(t=>{const {statusCode: e,statusCode: i,headers: o,body: h} = t; s(null,{status: e,statusCode: i,headers: o,body: h},h)},t=>s(t));} 872 | else if (this.isNode()) {this.initGotEnv(t); const {url: e,...i} = t; this.got.post(e,i).then(t=>{const {statusCode: e,statusCode: i,headers: o,body: h} = t; s(null,{status: e,statusCode: i,headers: o,body: h},h)},t=>s(t))} 873 | }time(t) {const s = {"M+": (new Date).getMonth() + 1,"d+": (new Date).getDate(),"H+": (new Date).getHours(),"m+": (new Date).getMinutes(),"s+": (new Date).getSeconds(),"q+": Math.floor(((new Date).getMonth() + 3) / 3),S: (new Date).getMilliseconds()}; /(y+)/.test(t) && (t = t.replace(RegExp.$1,((new Date).getFullYear() + "").substr(4 - RegExp.$1.length))); for (const e in s) {new RegExp("(" + e + ")").test(t) && (t = t.replace(RegExp.$1,1 == RegExp.$1.length ? s[e] : ("00" + s[e]).substr(("" + s[e]).length)));} return t}msg(s = t,e = "",i = "",o) {const h = t=>!t || !this.isLoon() && this.isSurge() ? t : "string" == typeof t ? this.isLoon() ? t : this.isQuanX() ? {"open-url": t} : void 0 : "object" == typeof t && (t["open-url"] || t["media-url"]) ? this.isLoon() ? t["open-url"] : this.isQuanX() ? t : void 0 : void 0; $.isMute || (this.isSurge() || this.isLoon() ? $notification.post(s,e,i,h(o)) : this.isQuanX() && $notify(s,e,i,h(o))),this.logs.push("","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="),this.logs.push(s),e && this.logs.push(e),i && this.logs.push(i)}log(...t) {t.length > 0 ? this.logs = [...this.logs,...t] : console.log(this.logs.join(this.logSeparator))}logErr(t) {const e = !this.isSurge() && !this.isQuanX() && !this.isLoon(); e ? $.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack) : $.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t) {return new Promise(s=>setTimeout(s,t))}done(t = {}) {const s = (new Date).getTime(),e = (s - this.startTime) / 1e3; this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${e} \u79d2`),this.log(),(this.isSurge() || this.isQuanX() || this.isLoon()) && $done(t)} 874 | }(t,s) 875 | } 876 | -------------------------------------------------------------------------------- /smzdm_checkin.js: -------------------------------------------------------------------------------- 1 | /* 2 | smzdm 签到脚本 3 | 项目地址: https://github.com/hex-ci/smzdm_script 4 | 5 | cron: 10 8 * * * 6 | */ 7 | 8 | const Env = require('./env'); 9 | const { SmzdmBot, requestApi, removeTags, getEnvCookies, wait } = require('./bot'); 10 | const notify = require('./sendNotify'); 11 | const CryptoJS = require('crypto-js'); 12 | 13 | // ------------------------------------ 14 | 15 | const $ = new Env('smzdm 签到'); 16 | 17 | class SmzdmCheckinBot extends SmzdmBot { 18 | constructor(cookie, sk) { 19 | super(cookie); 20 | 21 | this.sk = sk ? sk.trim() : ''; 22 | } 23 | 24 | async run() { 25 | const { msg: msg1 } = await this.checkin(); 26 | 27 | const { msg: msg2 } = await this.allReward(); 28 | 29 | const { msg: msg3 } = await this.extraReward(); 30 | 31 | return `${msg1}${msg2}${msg3}`; 32 | } 33 | 34 | async checkin() { 35 | const { isSuccess, data, response } = await requestApi('https://user-api.smzdm.com/checkin', { 36 | method: 'post', 37 | headers: this.getHeaders(), 38 | data: { 39 | touchstone_event: '', 40 | sk: this.sk || '1', 41 | token: this.token, 42 | captcha: '' 43 | } 44 | }); 45 | 46 | if (isSuccess) { 47 | let msg = `⭐签到成功${data.data.daily_num}天 48 | 🏅金币: ${data.data.cgold} 49 | 🏅碎银: ${data.data.pre_re_silver} 50 | 🏅补签卡: ${data.data.cards}`; 51 | 52 | await wait(3, 10); 53 | 54 | const vip = await this.getVipInfo(); 55 | 56 | if (vip) { 57 | msg += `\n🏅经验: ${vip.vip.exp_current} 58 | 🏅值会员等级: ${vip.vip.exp_level} 59 | 🏅值会员经验: ${vip.vip.exp_current_level} 60 | 🏅值会员有效期至: ${vip.vip.exp_level_expire}`; 61 | } 62 | 63 | $.log(`${msg}\n`); 64 | 65 | return { 66 | isSuccess, 67 | msg: `${msg}\n\n` 68 | }; 69 | } 70 | else { 71 | $.log(`签到失败!${response}`); 72 | 73 | return { 74 | isSuccess, 75 | msg: '签到失败!' 76 | }; 77 | } 78 | } 79 | 80 | async allReward() { 81 | const { isSuccess, data, response } = await requestApi('https://user-api.smzdm.com/checkin/all_reward', { 82 | method: 'post', 83 | headers: this.getHeaders(), 84 | debug: process.env.SMZDM_DEBUG 85 | }); 86 | 87 | if (isSuccess) { 88 | const msg1 = `${data.data.normal_reward.reward_add.title}: ${data.data.normal_reward.reward_add.content}`; 89 | 90 | let msg2 = ''; 91 | 92 | if (data.data.normal_reward.gift.title) { 93 | msg2 = `${data.data.normal_reward.gift.title}: ${data.data.normal_reward.gift.content_str}`; 94 | } 95 | else { 96 | msg2 = `${data.data.normal_reward.gift.sub_content}`; 97 | } 98 | 99 | $.log(`${msg1}\n${msg2}\n`); 100 | 101 | return { 102 | isSuccess, 103 | msg: `${msg1}\n${msg2}\n\n` 104 | }; 105 | } 106 | else { 107 | if (data.error_code != '4') { 108 | $.log(`查询奖励失败!${response}`); 109 | } 110 | 111 | return { 112 | isSuccess, 113 | msg: '' 114 | }; 115 | } 116 | } 117 | 118 | async extraReward() { 119 | const isContinue = await this.isContinueCheckin(); 120 | 121 | if (!isContinue) { 122 | const msg = '今天没有额外奖励'; 123 | 124 | $.log(`${msg}\n`); 125 | 126 | return { 127 | isSuccess: false, 128 | msg: `${msg}\n` 129 | }; 130 | } 131 | 132 | await wait(5, 10); 133 | 134 | const { isSuccess, data, response } = await requestApi('https://user-api.smzdm.com/checkin/extra_reward', { 135 | method: 'post', 136 | headers: this.getHeaders() 137 | }); 138 | 139 | if (isSuccess) { 140 | const msg = `${data.data.title}: ${removeTags(data.data.gift.content)}`; 141 | 142 | $.log(msg); 143 | 144 | return { 145 | isSuccess: true, 146 | msg: `${msg}\n` 147 | }; 148 | } 149 | else { 150 | $.log(`领取额外奖励失败!${response}`); 151 | 152 | return { 153 | isSuccess: false, 154 | msg: '' 155 | }; 156 | } 157 | } 158 | 159 | async isContinueCheckin() { 160 | const { isSuccess, data, response } = await requestApi('https://user-api.smzdm.com/checkin/show_view_v2', { 161 | method: 'post', 162 | headers: this.getHeaders() 163 | }); 164 | 165 | if (isSuccess) { 166 | const result = data.data.rows.find(item => item.cell_type == '18001'); 167 | 168 | return result.cell_data.checkin_continue.continue_checkin_reward_show; 169 | } 170 | else { 171 | $.log(`查询是否有额外奖励失败!${response}`); 172 | 173 | return false; 174 | } 175 | } 176 | 177 | async getVipInfo() { 178 | const { isSuccess, data, response } = await requestApi('https://user-api.smzdm.com/vip', { 179 | method: 'post', 180 | headers: this.getHeaders(), 181 | data: { 182 | token: this.token 183 | } 184 | }); 185 | 186 | if (isSuccess) { 187 | return data.data; 188 | } 189 | else { 190 | $.log(`查询信息失败!${response}`); 191 | 192 | return false; 193 | } 194 | } 195 | } 196 | 197 | function random32() { 198 | const chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 199 | let result = ''; 200 | 201 | for (let i = 0; i < 32; i++) { 202 | result += chars.charAt(Math.floor(Math.random() * chars.length)); 203 | } 204 | 205 | return result; 206 | } 207 | 208 | function getSk(cookie) { 209 | const matchUserId = cookie.match(/smzdm_id=([^;]*)/); 210 | 211 | if (!matchUserId) { 212 | return '' 213 | } 214 | 215 | const userId = matchUserId[1]; 216 | const deviceId = getDeviceId(cookie); 217 | const key = CryptoJS.enc.Utf8.parse('geZm53XAspb02exN'); 218 | const cipherText = CryptoJS.DES.encrypt(userId + deviceId, key, { 219 | mode: CryptoJS.mode.ECB, 220 | padding: CryptoJS.pad.Pkcs7 221 | }); 222 | 223 | return cipherText.toString(); 224 | } 225 | 226 | function getDeviceId(cookie) { 227 | const matchDeviceId = cookie.match(/device_id=([^;]*)/); 228 | 229 | if (matchDeviceId) { 230 | return matchDeviceId[1]; 231 | } 232 | 233 | return random32(); 234 | } 235 | 236 | !(async () => { 237 | const cookies = getEnvCookies(); 238 | 239 | if (cookies === false) { 240 | $.log('\n请先设置 SMZDM_COOKIE 环境变量'); 241 | 242 | return; 243 | } 244 | 245 | let sks = []; 246 | 247 | if (process.env.SMZDM_SK) { 248 | if (process.env.SMZDM_SK.indexOf('&') > -1) { 249 | sks = process.env.SMZDM_SK.split('&'); 250 | } 251 | else if (process.env.SMZDM_SK.indexOf('\n') > -1) { 252 | sks = process.env.SMZDM_SK.split('\n'); 253 | } 254 | else { 255 | sks = [process.env.SMZDM_SK]; 256 | } 257 | } 258 | 259 | let notifyContent = ''; 260 | 261 | for (let i = 0; i < cookies.length; i++) { 262 | const cookie = cookies[i]; 263 | 264 | if (!cookie) { 265 | continue; 266 | } 267 | 268 | let sk = sks[i]; 269 | if (!sk) { 270 | sk = getSk(cookie) 271 | } 272 | 273 | if (i > 0) { 274 | await wait(10, 30); 275 | } 276 | 277 | const sep = `\n****** 账号${i + 1} ******\n`; 278 | 279 | $.log(sep); 280 | 281 | const bot = new SmzdmCheckinBot(cookie, sk); 282 | const msg = await bot.run(); 283 | 284 | notifyContent += sep + msg + '\n'; 285 | } 286 | 287 | $.log(); 288 | 289 | await notify.sendNotify($.name, notifyContent); 290 | })().catch((e) => { 291 | $.log('', `❌ ${$.name}, 失败! 原因: ${e}!`, '') 292 | }).finally(() => { 293 | $.done(); 294 | }); 295 | -------------------------------------------------------------------------------- /smzdm_lottery.js: -------------------------------------------------------------------------------- 1 | /* 2 | smzdm 抽奖脚本 3 | 项目地址: https://github.com/hex-ci/smzdm_script 4 | 5 | cron: 20 8 * * * 6 | */ 7 | 8 | const Env = require('./env'); 9 | const { SmzdmBot, requestApi, parseJSON, getEnvCookies, wait } = require('./bot'); 10 | const notify = require('./sendNotify'); 11 | 12 | // ------------------------------------ 13 | 14 | const $ = new Env('smzdm 抽奖'); 15 | 16 | class SmzdmLotteryBot extends SmzdmBot { 17 | constructor(cookie) { 18 | super(cookie); 19 | } 20 | 21 | async run() { 22 | let notifyMsg = ''; 23 | 24 | // const lifeId = await this.getActivityIdFromLife(); 25 | 26 | // if (lifeId) { 27 | // await wait(3, 10); 28 | 29 | // notifyMsg += `转盘抽奖ID: ${lifeId}\n`; 30 | // notifyMsg += await this.draw(lifeId); 31 | // notifyMsg += '\n\n'; 32 | // } 33 | 34 | const vipId1 = await this.getActivityIdFromVip('https://m.smzdm.com/topic/bwrzf5/516lft'); 35 | 36 | if (vipId1) { 37 | await wait(3, 10); 38 | 39 | notifyMsg += `转盘抽奖ID: ${vipId1}\n`; 40 | notifyMsg += await this.draw(vipId1); 41 | notifyMsg += '\n\n'; 42 | } 43 | 44 | $.log(); 45 | await wait(5, 15); 46 | $.log(); 47 | 48 | const vipId2 = await this.getActivityIdFromVip('https://m.smzdm.com/topic/zhyzhuanpan/cjzp/'); 49 | 50 | if (vipId2) { 51 | await wait(3, 10); 52 | 53 | notifyMsg += `转盘抽奖ID: ${vipId2}\n`; 54 | notifyMsg += await this.draw(vipId2); 55 | } 56 | 57 | return notifyMsg; 58 | } 59 | 60 | async draw(id) { 61 | const { isSuccess, data, response } = await requestApi('https://zhiyou.smzdm.com/user/lottery/jsonp_draw', { 62 | sign: false, 63 | parseJSON: false, 64 | headers: { 65 | ...this.getHeadersForWeb(), 66 | 'x-requested-with': 'com.smzdm.client.android', 67 | Referer: 'https://m.smzdm.com/' 68 | }, 69 | data: { 70 | active_id: id, 71 | callback: `jQuery34107538452897131465_${new Date().getTime()}` 72 | } 73 | }); 74 | 75 | if (isSuccess) { 76 | const match = data.match(/\((.*)\)/); 77 | 78 | if (match) { 79 | const result = parseJSON(match[1]); 80 | 81 | if (result.error_code == 0 || result.error_code == 1 || result.error_code == 4) { 82 | $.log(result.error_msg); 83 | 84 | return result.error_msg; 85 | } 86 | else { 87 | $.log(`转盘抽奖失败,接口响应异常:${response}`); 88 | 89 | return '转盘抽奖失败,接口响应异常'; 90 | } 91 | } 92 | else { 93 | $.log(`转盘抽奖失败,接口响应异常: ${response}`); 94 | 95 | return '转盘抽奖失败,接口响应异常'; 96 | } 97 | } 98 | else { 99 | $.log(`转盘抽奖失败,接口响应异常: ${response}`); 100 | 101 | return '转盘抽奖失败,接口响应异常'; 102 | } 103 | } 104 | 105 | // 获取生活频道转盘抽奖ID 106 | async getActivityIdFromLife() { 107 | const { isSuccess, data, response } = await requestApi('https://m.smzdm.com/zhuanti/life/choujiang/', { 108 | sign: false, 109 | parseJSON: false, 110 | headers: { 111 | ...this.getHeadersForWeb(), 112 | 'x-requested-with': 'com.smzdm.client.android' 113 | } 114 | }); 115 | 116 | if (isSuccess) { 117 | const match = data.match(/name\s?=\s?"lottery_activity_id"\s+value\s?=\s?"([a-zA-Z0-9]*)"/i); 118 | 119 | if (match) { 120 | $.log(`转盘抽奖ID: ${match[1]}`); 121 | 122 | return match[1]; 123 | } 124 | else { 125 | $.log(`未找到转盘抽奖ID`); 126 | 127 | return false; 128 | } 129 | } 130 | else { 131 | $.log(`获取转盘抽奖失败: ${response}`); 132 | 133 | return false; 134 | } 135 | } 136 | 137 | // 获取会员中心转盘抽奖ID 138 | async getActivityIdFromVip(url) { 139 | const { isSuccess, data, response } = await requestApi(url, { 140 | sign: false, 141 | parseJSON: false, 142 | headers: { 143 | ...this.getHeadersForWeb(), 144 | 'x-requested-with': 'com.smzdm.client.android' 145 | } 146 | }); 147 | 148 | if (isSuccess) { 149 | const match = data.match(/\\"hashId\\":\\"([^\\]+)\\"/i); 150 | 151 | if (match) { 152 | $.log(`转盘抽奖ID: ${match[1]}`); 153 | 154 | return match[1]; 155 | } 156 | else { 157 | $.log(`未找到转盘抽奖ID`); 158 | 159 | return false; 160 | } 161 | } 162 | else { 163 | $.log(`获取转盘抽奖失败: ${response}`); 164 | 165 | return false; 166 | } 167 | } 168 | } 169 | 170 | !(async () => { 171 | const cookies = getEnvCookies(); 172 | 173 | if (cookies === false) { 174 | $.log('\n请先设置 SMZDM_COOKIE 环境变量'); 175 | 176 | return; 177 | } 178 | 179 | let notifyContent = ''; 180 | 181 | for (let i = 0; i < cookies.length; i++) { 182 | const cookie = cookies[i]; 183 | 184 | if (!cookie) { 185 | continue; 186 | } 187 | 188 | if (i > 0) { 189 | $.log(); 190 | await wait(10, 30); 191 | $.log(); 192 | } 193 | 194 | const sep = `\n****** 账号${i + 1} ******\n`; 195 | 196 | $.log(sep); 197 | 198 | const bot = new SmzdmLotteryBot(cookie); 199 | const msg = await bot.run(); 200 | 201 | notifyContent += sep + msg + '\n'; 202 | } 203 | 204 | $.log(); 205 | 206 | await notify.sendNotify($.name, notifyContent); 207 | })().catch((e) => { 208 | $.log('', `❌ ${$.name}, 失败! 原因: ${e}!`, '') 209 | }).finally(() => { 210 | $.done(); 211 | }); 212 | -------------------------------------------------------------------------------- /smzdm_task.js: -------------------------------------------------------------------------------- 1 | /* 2 | smzdm 每日任务脚本 3 | 项目地址: https://github.com/hex-ci/smzdm_script 4 | 5 | cron: 20 14 * * * 6 | */ 7 | 8 | const Env = require('./env'); 9 | const { requestApi, removeTags, getEnvCookies, wait } = require('./bot'); 10 | const notify = require('./sendNotify'); 11 | const { SmzdmTaskBot } = require('./library_task'); 12 | 13 | // ------------------------------------ 14 | 15 | const $ = new Env('smzdm 每日任务'); 16 | 17 | class SmzdmNormalTaskBot extends SmzdmTaskBot { 18 | constructor(cookie) { 19 | super(cookie, $); 20 | } 21 | 22 | // 主函数 23 | async run() { 24 | $.log('获取任务列表'); 25 | 26 | const { tasks } = await this.getTaskList(); 27 | 28 | await wait(5, 10); 29 | 30 | let notifyMsg = ''; 31 | 32 | notifyMsg = await this.doTasks(tasks); 33 | 34 | $.log('查询是否有限时累计活动阶段奖励'); 35 | await wait(5, 15); 36 | 37 | // 领取活动奖励 38 | const { detail } = await this.getTaskList(); 39 | 40 | if (detail.cell_data && detail.cell_data.activity_reward_status == '1') { 41 | $.log('有奖励,领取奖励'); 42 | await wait(5, 15); 43 | 44 | const { isSuccess } = await this.receiveActivity(detail.cell_data); 45 | 46 | notifyMsg += `${isSuccess ? '🟢' : '❌'}限时累计活动阶段奖励领取${isSuccess ? '成功' : '失败!请查看日志'}\n`; 47 | } 48 | else { 49 | $.log('无奖励'); 50 | } 51 | 52 | return notifyMsg || '无可执行任务'; 53 | } 54 | 55 | // 获取任务列表 56 | async getTaskList() { 57 | const { isSuccess, data, response } = await requestApi('https://user-api.smzdm.com/task/list_v2', { 58 | method: 'post', 59 | headers: this.getHeaders() 60 | }); 61 | 62 | if (isSuccess) { 63 | let tasks = []; 64 | 65 | if (data.data.rows[0]) { 66 | data.data.rows[0].cell_data.activity_task.accumulate_list.task_list_v2.forEach(item => { 67 | tasks = tasks.concat(item.task_list); 68 | }); 69 | 70 | return { 71 | tasks: tasks, 72 | detail: data.data.rows[0] 73 | }; 74 | } 75 | else { 76 | $.log(`任务列表获取失败!${response}`); 77 | 78 | return { 79 | tasks: [], 80 | detail: {} 81 | }; 82 | } 83 | } 84 | else { 85 | $.log(`任务列表获取失败!${response}`); 86 | 87 | return { 88 | tasks: [], 89 | detail: {} 90 | }; 91 | } 92 | } 93 | 94 | // 领取活动奖励 95 | async receiveActivity(activity) { 96 | $.log(`领取奖励: ${activity.activity_name}`); 97 | 98 | const { isSuccess, data, response } = await requestApi('https://user-api.smzdm.com/task/activity_receive', { 99 | method: 'post', 100 | headers: this.getHeaders(), 101 | data: { 102 | activity_id: activity.activity_id 103 | } 104 | }); 105 | 106 | if (isSuccess) { 107 | $.log(removeTags(data.data.reward_msg)); 108 | 109 | return { 110 | isSuccess 111 | }; 112 | } 113 | else { 114 | $.log(`领取奖励失败!${response}`); 115 | 116 | return { 117 | isSuccess 118 | }; 119 | } 120 | } 121 | 122 | // 领取任务奖励 123 | async receiveReward(taskId) { 124 | const robotToken = await this.getRobotToken(); 125 | 126 | if (robotToken === false) { 127 | return { 128 | isSuccess, 129 | msg: '领取任务奖励失败!' 130 | }; 131 | } 132 | 133 | const { isSuccess, data, response } = await requestApi('https://user-api.smzdm.com/task/activity_task_receive', { 134 | method: 'post', 135 | headers: this.getHeaders(), 136 | data: { 137 | robot_token: robotToken, 138 | geetest_seccode: '', 139 | geetest_validate: '', 140 | geetest_challenge: '', 141 | captcha: '', 142 | task_id: taskId 143 | } 144 | }); 145 | 146 | if (isSuccess) { 147 | const msg = removeTags(data.data.reward_msg); 148 | 149 | $.log(msg); 150 | 151 | return { 152 | isSuccess, 153 | msg 154 | }; 155 | } 156 | else { 157 | $.log(`领取任务奖励失败!${response}`); 158 | 159 | return { 160 | isSuccess, 161 | msg: '领取任务奖励失败!' 162 | }; 163 | } 164 | } 165 | } 166 | 167 | !(async () => { 168 | const cookies = getEnvCookies(); 169 | 170 | if (cookies === false) { 171 | $.log('\n请先设置 SMZDM_COOKIE 环境变量'); 172 | 173 | return; 174 | } 175 | 176 | let notifyContent = ''; 177 | 178 | for (let i = 0; i < cookies.length; i++) { 179 | const cookie = cookies[i]; 180 | 181 | if (!cookie) { 182 | continue; 183 | } 184 | 185 | if (i > 0) { 186 | $.log(); 187 | await wait(10, 30); 188 | $.log(); 189 | } 190 | 191 | const sep = `\n****** 账号${i + 1} ******\n`; 192 | 193 | $.log(sep); 194 | 195 | const bot = new SmzdmNormalTaskBot(cookie); 196 | const msg = await bot.run(); 197 | 198 | notifyContent += `${sep}${msg}\n`; 199 | } 200 | 201 | $.log(); 202 | 203 | await notify.sendNotify($.name, notifyContent); 204 | })().catch((e) => { 205 | $.log('', `❌ ${$.name}, 失败! 原因: ${e}!`, '') 206 | }).finally(() => { 207 | $.done(); 208 | }); 209 | -------------------------------------------------------------------------------- /smzdm_testing.js: -------------------------------------------------------------------------------- 1 | /* 2 | smzdm 全民众测能量值任务脚本 3 | 项目地址: https://github.com/hex-ci/smzdm_script 4 | 5 | cron: 20 15 * * * 6 | */ 7 | 8 | const Env = require('./env'); 9 | const { requestApi, getEnvCookies, wait } = require('./bot'); 10 | const notify = require('./sendNotify'); 11 | const { SmzdmTaskBot } = require('./library_task'); 12 | 13 | // ------------------------------------ 14 | 15 | const $ = new Env('smzdm 全民众测能量值任务'); 16 | 17 | class SmzdmTestingTaskBot extends SmzdmTaskBot { 18 | constructor(cookie) { 19 | super(cookie, $); 20 | } 21 | 22 | // 主函数 23 | async run() { 24 | const activityId = await this.getTestingActivityId(); 25 | 26 | if (!activityId) { 27 | return ''; 28 | } 29 | 30 | await wait(5, 10); 31 | 32 | const activityInfo = await this.getTestingActivityInfo(activityId); 33 | 34 | if (!activityInfo) { 35 | return ''; 36 | } 37 | 38 | await wait(5, 10); 39 | 40 | let notifyMsg = await this.doTasks(activityInfo.activity_task.default_list); 41 | 42 | await wait(3, 5); 43 | 44 | // 查询当前拥有的能量数量, 以及过期时间 45 | notifyMsg += await this.getMyTestingInfo(); 46 | 47 | return notifyMsg || '无可执行任务'; 48 | } 49 | 50 | // 获取当前能量值任务的活动 ID 51 | async getTestingActivityId() { 52 | $.log('获取活动 ID'); 53 | 54 | const { isSuccess, data, response } = await requestApi('https://zhiyou.m.smzdm.com/task/task/ajax_get_activity_id', { 55 | method: 'get', 56 | data: { 57 | 'from': 'zhongce' 58 | }, 59 | headers: { 60 | ...this.getHeadersForWeb(), 61 | Origin: 'https://test.m.smzdm.com', 62 | Referer: 'https://test.m.smzdm.com/' 63 | } 64 | }); 65 | 66 | if (isSuccess) { 67 | return data.data.activity_id; 68 | } 69 | else { 70 | $.log(`获取活动 ID 失败!${response}`); 71 | 72 | return false; 73 | } 74 | } 75 | 76 | // 获取活动下的所有任务 77 | async getTestingActivityInfo(id) { 78 | $.log('获取活动信息'); 79 | 80 | const { isSuccess, data, response } = await requestApi('https://zhiyou.m.smzdm.com/task/task/ajax_get_activity_info', { 81 | method: 'get', 82 | data: { 83 | 'activity_id': id 84 | }, 85 | headers: this.getHeadersForWeb() 86 | }); 87 | 88 | if (isSuccess) { 89 | return data.data; 90 | } 91 | else { 92 | $.log(`获取活动信息失败!${response}`); 93 | 94 | return false; 95 | } 96 | } 97 | 98 | // 众测中心-必中券信息查询 99 | async getMyTestingInfo() { 100 | $.log('获取必中券信息'); 101 | 102 | const { isSuccess, data, response } = await requestApi('https://test.m.smzdm.com/win_coupon/user_data', { 103 | method: 'get', 104 | headers: this.getHeadersForWeb() 105 | }); 106 | 107 | if (isSuccess) { 108 | const msg = `当前拥有必中券: ${data.data.my_energy.my_energy_total}\n必中券过期时间: ${data.data.my_energy.energy_expired_time}`; 109 | 110 | $.log(msg); 111 | 112 | return `\n${msg}\n`; 113 | } 114 | else { 115 | $.log(`获取个人必中券信息失败!${response}`); 116 | 117 | return ''; 118 | } 119 | } 120 | 121 | // 领取奖励 122 | async receiveReward(taskId) { 123 | const { isSuccess, response } = await requestApi('https://zhiyou.m.smzdm.com/task/task/ajax_activity_task_receive', { 124 | method: 'post', 125 | data: { 126 | 'task_id': taskId 127 | }, 128 | headers: this.getHeadersForWeb() 129 | }); 130 | 131 | if (isSuccess) { 132 | $.log('领取成功!'); 133 | 134 | return { 135 | isSuccess, 136 | msg: '' 137 | }; 138 | } 139 | else { 140 | $.log(`领取任务奖励失败!${response}`); 141 | 142 | return { 143 | isSuccess, 144 | msg: '领取任务奖励失败!' 145 | }; 146 | } 147 | } 148 | } 149 | 150 | !(async () => { 151 | if (process.env.SMZDM_TASK_TESTING != 'yes') { 152 | $.log('\n🟡请设置 SMZDM_TASK_TESTING 环境变量值为 yes 后才能运行全民众测能量值任务!'); 153 | 154 | return; 155 | } 156 | 157 | const cookies = getEnvCookies(); 158 | 159 | if (cookies === false) { 160 | $.log('\n请先设置 SMZDM_COOKIE 环境变量'); 161 | 162 | return; 163 | } 164 | 165 | let notifyContent = ''; 166 | 167 | for (let i = 0; i < cookies.length; i++) { 168 | const cookie = cookies[i]; 169 | 170 | if (!cookie) { 171 | continue; 172 | } 173 | 174 | if (i > 0) { 175 | $.log(); 176 | await wait(10, 30); 177 | $.log(); 178 | } 179 | 180 | const sep = `\n****** 账号${i + 1} ******\n`; 181 | 182 | $.log(sep); 183 | 184 | const bot = new SmzdmTestingTaskBot(cookie); 185 | const msg = await bot.run(); 186 | 187 | notifyContent += `${sep}${msg}\n`; 188 | } 189 | 190 | $.log(); 191 | 192 | await notify.sendNotify($.name, notifyContent); 193 | })().catch((e) => { 194 | $.log('', `❌ ${$.name}, 失败! 原因: ${e}!`, '') 195 | }).finally(() => { 196 | $.done(); 197 | }); 198 | --------------------------------------------------------------------------------