├── .gitattributes ├── JD ├── USER_AGENTS.js ├── jdCookie.js ├── jd_bean_sign.js └── sendNotify.js └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=node 2 | -------------------------------------------------------------------------------- /JD/USER_AGENTS.js: -------------------------------------------------------------------------------- 1 | const USER_AGENTS = [] 2 | /** 3 | * 生成随机数字 4 | * @param {number} min 最小值(包含) 5 | * @param {number} max 最大值(不包含) 6 | */ 7 | function randomNumber(min = 0, max = 100) { 8 | return Math.min(Math.floor(min + Math.random() * (max - min)), max); 9 | } 10 | 11 | /** 12 | * 得到一个两数之间的随机整数,包括两个数在内 13 | * @param min 14 | * @param max 15 | * @returns {number} 16 | */ 17 | function getRandomIntInclusive(min, max) { 18 | min = Math.ceil(min); 19 | max = Math.floor(max); 20 | return Math.floor(Math.random() * (max - min + 1)) + min; //含最大值,含最小值 21 | } 22 | /** 23 | * 生成随机 iPhoneID 24 | * @returns {string} 25 | */ 26 | function randPhoneId() { 27 | return Math.random().toString(36).slice(2, 10) + 28 | Math.random().toString(36).slice(2, 10) + 29 | Math.random().toString(36).slice(2, 10) + 30 | Math.random().toString(36).slice(2, 10) + 31 | Math.random().toString(36).slice(2, 10); 32 | } 33 | 34 | const USER_AGENT = `jdapp;iPhone;10.1.2;${Math.ceil(Math.random()*4+10)}.${Math.ceil(Math.random()*4)};${randPhoneId()};network/4g;model/iPhone11,8;addressid/1188016812;appBuild/167724;jdSupportDarkMode/0;Mozilla/5.0 (iPhone; CPU iPhone OS ${getRandomIntInclusive(11, 14)}_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1`; 35 | 36 | module.exports = { 37 | USER_AGENT 38 | } 39 | -------------------------------------------------------------------------------- /JD/jdCookie.js: -------------------------------------------------------------------------------- 1 | /* 2 | 此文件为Node.js专用。其他用户请忽略 3 | */ 4 | //此处填写京东账号cookie。 5 | let CookieJDs = [ 6 | '',//账号一ck,例:pt_key=XXX;pt_pin=XXX; 7 | '',//账号二ck,例:pt_key=XXX;pt_pin=XXX;如有更多,依次类推 8 | ] 9 | // 判断环境变量里面是否有京东ck 10 | if (process.env.JD_COOKIE) { 11 | if (process.env.JD_COOKIE.indexOf('&') > -1) { 12 | CookieJDs = process.env.JD_COOKIE.split('&'); 13 | } else if (process.env.JD_COOKIE.indexOf('\n') > -1) { 14 | CookieJDs = process.env.JD_COOKIE.split('\n'); 15 | } else { 16 | CookieJDs = [process.env.JD_COOKIE]; 17 | } 18 | } 19 | if (JSON.stringify(process.env).indexOf('GITHUB')>-1) { 20 | console.log(`请勿使用github action运行此脚本,无论你是从你自己的私库还是其他哪里拉取的源代码,都会导致我被封号\n`); 21 | !(async () => { 22 | await require('./sendNotify').sendNotify('提醒', `请勿使用github action、滥用github资源会封我仓库以及账号`) 23 | await process.exit(0); 24 | })() 25 | } 26 | CookieJDs = [...new Set(CookieJDs.filter(item => !!item))] 27 | console.log(`\n====================共${CookieJDs.length}个京东账号Cookie=========\n`); 28 | console.log(`==================脚本执行- 北京时间(UTC+8):${new Date(new Date().getTime() + new Date().getTimezoneOffset()*60*1000 + 8*60*60*1000).toLocaleString()}=====================\n`) 29 | if (process.env.JD_DEBUG && process.env.JD_DEBUG === 'false') console.log = () => {}; 30 | for (let i = 0; i < CookieJDs.length; i++) { 31 | if (!CookieJDs[i].match(/pt_pin=(.+?);/) || !CookieJDs[i].match(/pt_key=(.+?);/)) console.log(`\n提示:京东cookie 【${CookieJDs[i]}】填写不规范,可能会影响部分脚本正常使用。正确格式为: pt_key=xxx;pt_pin=xxx;(分号;不可少)\n`); 32 | const index = (i + 1 === 1) ? '' : (i + 1); 33 | exports['CookieJD' + index] = CookieJDs[i].trim(); 34 | } 35 | -------------------------------------------------------------------------------- /JD/jd_bean_sign.js: -------------------------------------------------------------------------------- 1 | /* 2 | 京东多合一签到,自用,可N个京东账号 3 | 活动入口:各处的签到汇总 4 | Node.JS专用 5 | IOS软件用户请使用 https://raw.githubusercontent.com/NobyDa/Script/master/JD-DailyBonus/JD_DailyBonus.js 6 | 更新时间:2021-8-18 7 | 推送通知默认简洁模式(多账号只发送一次)。如需详细通知,设置环境变量 JD_BEAN_SIGN_NOTIFY_SIMPLE 为false即可(N账号推送N次通知)。 8 | Modified From github https://github.com/ruicky/jd_sign_bot 9 | */ 10 | const $ = new Env('京东多合一签到'); 11 | const notify = $.isNode() ? require('./sendNotify') : ''; 12 | //Node.js用户请在jdCookie.js处填写京东ck; 13 | const jdCookieNode = $.isNode() ? require('./jdCookie.js') : ''; 14 | const exec = require('child_process').execSync 15 | const fs = require('fs') 16 | const download = require('download'); 17 | let resultPath = "./result.txt"; 18 | let JD_DailyBonusPath = "./JD_DailyBonus.js"; 19 | let outPutUrl = './'; 20 | let NodeSet = 'CookieSet.json'; 21 | let cookiesArr = [], cookie = '', allMessage = ''; 22 | 23 | if ($.isNode()) { 24 | Object.keys(jdCookieNode).forEach((item) => { 25 | cookiesArr.push(jdCookieNode[item]) 26 | }) 27 | if (process.env.JD_DEBUG && process.env.JD_DEBUG === 'false') console.log = () => {}; 28 | } 29 | !(async() => { 30 | if (!cookiesArr[0]) { 31 | $.msg($.name, '【提示】请先获取cookie\n直接使用NobyDa的京东签到获取', 'https://bean.m.jd.com/bean/signIndex.action', {"open-url": "https://bean.m.jd.com/bean/signIndex.action"}); 32 | return; 33 | } 34 | process.env.JD_BEAN_SIGN_NOTIFY_SIMPLE = process.env.JD_BEAN_SIGN_NOTIFY_SIMPLE ? process.env.JD_BEAN_SIGN_NOTIFY_SIMPLE : 'true'; 35 | await requireConfig(); 36 | // 下载最新代码 37 | await downFile(); 38 | if (!await fs.existsSync(JD_DailyBonusPath)) { 39 | console.log(`\nJD_DailyBonus.js 文件不存在,停止执行${$.name}\n`); 40 | await notify.sendNotify($.name, `本次执行${$.name}失败,JD_DailyBonus.js 文件下载异常,详情请查看日志`) 41 | return 42 | } 43 | const content = await fs.readFileSync(JD_DailyBonusPath, 'utf8') 44 | for (let i =0; i < cookiesArr.length; i++) { 45 | cookie = cookiesArr[i]; 46 | if (cookie) { 47 | $.UserName = decodeURIComponent(cookie.match(/pt_pin=([^; ]+)(?=;?)/) && cookie.match(/pt_pin=([^; ]+)(?=;?)/)[1]) 48 | $.index = i + 1; 49 | $.nickName = ''; 50 | $.isLogin = true; 51 | await TotalBean(); 52 | console.log(`*****************开始京东账号${$.index} ${$.nickName || $.UserName} ${$.name}*******************\n`); 53 | if (!$.isLogin) { 54 | $.msg($.name, `【提示】cookie已失效`, `京东账号${$.index} ${$.nickName || $.UserName}\n请重新登录获取\nhttps://bean.m.jd.com/bean/signIndex.action`, {"open-url": "https://bean.m.jd.com/bean/signIndex.action"}); 55 | if ($.isNode()) { 56 | await notify.sendNotify(`${$.name}cookie已失效 - ${$.UserName}`, `京东账号${$.index} ${$.UserName}\n请重新登录获取cookie`); 57 | } 58 | continue 59 | } 60 | await changeFile(content); 61 | await execSign(); 62 | } 63 | } 64 | //await deleteFile(JD_DailyBonusPath);//删除下载的JD_DailyBonus.js文件 65 | if ($.isNode() && allMessage && process.env.JD_BEAN_SIGN_NOTIFY_SIMPLE === 'true') { 66 | $.msg($.name, '', allMessage); 67 | await notify.sendNotify($.name, allMessage) 68 | } 69 | })() 70 | .catch((e) => $.logErr(e)) 71 | .finally(() => $.done()) 72 | async function execSign() { 73 | console.log(`\n开始执行 ${$.name} 签到,请稍等...\n`); 74 | try { 75 | // if (notify.SCKEY || notify.BARK_PUSH || notify.DD_BOT_TOKEN || (notify.TG_BOT_TOKEN && notify.TG_USER_ID) || notify.IGOT_PUSH_KEY || notify.QQ_SKEY) { 76 | // await exec(`${process.execPath} ${JD_DailyBonusPath} >> ${resultPath}`); 77 | // const notifyContent = await fs.readFileSync(resultPath, "utf8"); 78 | // console.log(`👇👇👇👇👇👇👇👇👇👇👇LOG记录👇👇👇👇👇👇👇👇👇👇👇\n${notifyContent}\n👆👆👆👆👆👆👆👆👆LOG记录👆👆👆👆👆👆👆👆👆👆👆`); 79 | // } else { 80 | // console.log('没有提供通知推送,则打印脚本执行日志') 81 | // await exec(`${process.execPath} ${JD_DailyBonusPath}`, { stdio: "inherit" }); 82 | // } 83 | await exec(`${process.execPath} ${JD_DailyBonusPath} >> ${resultPath}`); 84 | const notifyContent = await fs.readFileSync(resultPath, "utf8"); 85 | console.log(`👇👇👇👇👇👇👇👇👇👇👇签到详情👇👇👇👇👇👇👇👇👇👇👇\n${notifyContent}\n👆👆👆👆👆👆👆👆👆签到详情👆👆👆👆👆👆👆👆👆👆👆`); 86 | // await exec("node JD_DailyBonus.js", { stdio: "inherit" }); 87 | // console.log('执行完毕', new Date(new Date().getTime() + 8 * 3600000).toLocaleDateString()) 88 | //发送通知 89 | let BarkContent = ''; 90 | if (fs.existsSync(resultPath)) { 91 | const barkContentStart = notifyContent.indexOf('【签到概览】') 92 | const barkContentEnd = notifyContent.length; 93 | if (process.env.JD_BEAN_SIGN_STOP_NOTIFY !== 'true') { 94 | if (process.env.JD_BEAN_SIGN_NOTIFY_SIMPLE === 'true') { 95 | if (barkContentStart > -1 && barkContentEnd > -1) { 96 | BarkContent = notifyContent.substring(barkContentStart, barkContentEnd); 97 | } 98 | BarkContent = BarkContent.split('\n\n')[0]; 99 | } else { 100 | if (barkContentStart > -1 && barkContentEnd > -1) { 101 | BarkContent = notifyContent.substring(barkContentStart, barkContentEnd); 102 | } 103 | } 104 | } 105 | } 106 | //不管哪个时区,这里得到的都是北京时间的时间戳; 107 | const UTC8 = new Date().getTime() + new Date().getTimezoneOffset()*60000 + 28800000; 108 | $.beanSignTime = new Date(UTC8).toLocaleString('zh', {hour12: false}); 109 | //console.log(`脚本执行完毕时间:${$.beanSignTime}`) 110 | if (BarkContent) { 111 | allMessage += `【京东号 ${$.index}】: ${$.nickName || $.UserName}\n【签到时间】: ${$.beanSignTime}\n${BarkContent}${$.index !== cookiesArr.length ? '\n\n' : ''}`; 112 | if (!process.env.JD_BEAN_SIGN_NOTIFY_SIMPLE || (process.env.JD_BEAN_SIGN_NOTIFY_SIMPLE && process.env.JD_BEAN_SIGN_NOTIFY_SIMPLE !== 'true')) { 113 | await notify.sendNotify(`${$.name} - 账号${$.index} - ${$.nickName || $.UserName}`, `【签到号 ${$.index}】: ${$.nickName || $.UserName}\n【签到时间】: ${$.beanSignTime}\n${BarkContent}`); 114 | } 115 | } 116 | //运行完成后,删除下载的文件 117 | await Promise.all([ 118 | deleteFile(resultPath),//删除result.txt 119 | deleteFile(NodeSet),//删除CookieSet.json 120 | ]) 121 | console.log(`\n\n*****************${new Date(new Date().getTime()).toLocaleString('zh', {hour12: false})} 京东账号${$.index} ${$.nickName || $.UserName} ${$.name}完成*******************\n\n`); 122 | } catch (e) { 123 | console.log("京东签到脚本执行异常:" + e); 124 | } 125 | } 126 | async function downFile () { 127 | let url = ''; 128 | await downloadUrl(); 129 | if ($.body) { 130 | url = 'https://raw.githubusercontent.com/NobyDa/Script/master/JD-DailyBonus/JD_DailyBonus.js'; 131 | } else { 132 | url = 'https://cdn.jsdelivr.net/gh/NobyDa/Script@master/JD-DailyBonus/JD_DailyBonus.js'; 133 | } 134 | try { 135 | const options = { } 136 | if (process.env.TG_PROXY_HOST && process.env.TG_PROXY_PORT) { 137 | url = 'https://raw.githubusercontent.com/NobyDa/Script/master/JD-DailyBonus/JD_DailyBonus.js'; 138 | const tunnel = require("tunnel"); 139 | const agent = { 140 | https: tunnel.httpsOverHttp({ 141 | proxy: { 142 | host: process.env.TG_PROXY_HOST, 143 | port: process.env.TG_PROXY_PORT * 1 144 | } 145 | }) 146 | } 147 | Object.assign(options, { agent }) 148 | } 149 | await download(url, outPutUrl, options); 150 | console.log(`JD_DailyBonus.js文件下载完毕\n\n`); 151 | } catch (e) { 152 | console.log("JD_DailyBonus.js 文件下载异常:" + e); 153 | } 154 | } 155 | 156 | async function changeFile (content) { 157 | console.log(`开始替换变量`) 158 | // let newContent = content.replace(/var OtherKey = `.*`/, "var OtherKey = " + "`[{\"cookie\":\"" + cookie+ "\"}]`"); 159 | let newContent = content.replace(/var OtherKey = `.*`/, `var OtherKey = \`[{"cookie":"${cookie}"}]\``); 160 | newContent = newContent.replace(/const NodeSet = 'CookieSet.json'/, `const NodeSet = '${NodeSet}'`) 161 | if (process.env.JD_BEAN_STOP && process.env.JD_BEAN_STOP !== '0') { 162 | newContent = newContent.replace(/var stop = '0'/, `var stop = '${process.env.JD_BEAN_STOP}'`); 163 | } 164 | const zone = new Date().getTimezoneOffset(); 165 | if (zone === 0) { 166 | //此处针对UTC-0时区用户做的 167 | newContent = newContent.replace(/tm\s=.*/, `tm = new Date(new Date().toLocaleDateString()).getTime() - 28800000;`); 168 | } 169 | try { 170 | await fs.writeFileSync(JD_DailyBonusPath, newContent, 'utf8'); 171 | console.log('替换变量完毕'); 172 | } catch (e) { 173 | console.log("京东签到写入文件异常:" + e); 174 | } 175 | } 176 | async function deleteFile(path) { 177 | // 查看文件result.txt是否存在,如果存在,先删除 178 | const fileExists = await fs.existsSync(path); 179 | // console.log('fileExists', fileExists); 180 | if (fileExists) { 181 | const unlinkRes = await fs.unlinkSync(path); 182 | // console.log('unlinkRes', unlinkRes) 183 | } 184 | } 185 | function TotalBean() { 186 | return new Promise(async resolve => { 187 | const options = { 188 | "url": `https://wq.jd.com/user/info/QueryJDUserInfo?sceneval=2`, 189 | "headers": { 190 | "Accept": "application/json,text/plain, */*", 191 | "Content-Type": "application/x-www-form-urlencoded", 192 | "Accept-Encoding": "gzip, deflate, br", 193 | "Accept-Language": "zh-cn", 194 | "Connection": "keep-alive", 195 | "Cookie": cookie, 196 | "Referer": "https://wqs.jd.com/my/jingdou/my.shtml?sceneval=2", 197 | "User-Agent": $.isNode() ? (process.env.JD_USER_AGENT ? process.env.JD_USER_AGENT : (require('./USER_AGENTS').USER_AGENT)) : ($.getdata('JDUA') ? $.getdata('JDUA') : "jdapp;iPhone;9.4.4;14.3;network/4g;Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1") 198 | }, 199 | "timeout": 10000 200 | } 201 | $.post(options, (err, resp, data) => { 202 | try { 203 | if (err) { 204 | console.log(`${JSON.stringify(err)}`) 205 | console.log(`${$.name} API请求失败,请检查网路重试`) 206 | } else { 207 | if (data) { 208 | data = JSON.parse(data); 209 | if (data['retcode'] === 13) { 210 | $.isLogin = false; //cookie过期 211 | return 212 | } 213 | if (data['retcode'] === 0) { 214 | $.nickName = (data['base'] && data['base'].nickname) || $.UserName; 215 | } else { 216 | $.nickName = $.UserName 217 | } 218 | } else { 219 | console.log(`京东服务器返回空数据`) 220 | } 221 | } 222 | } catch (e) { 223 | $.logErr(e, resp) 224 | } finally { 225 | resolve(); 226 | } 227 | }) 228 | }) 229 | } 230 | function downloadUrl(url = 'https://raw.githubusercontent.com/NobyDa/Script/master/JD-DailyBonus/JD_DailyBonus.js') { 231 | return new Promise(resolve => { 232 | const options = { url, "timeout": 10000 }; 233 | if ($.isNode() && process.env.TG_PROXY_HOST && process.env.TG_PROXY_PORT) { 234 | const tunnel = require("tunnel"); 235 | const agent = { 236 | https: tunnel.httpsOverHttp({ 237 | proxy: { 238 | host: process.env.TG_PROXY_HOST, 239 | port: process.env.TG_PROXY_PORT * 1 240 | } 241 | }) 242 | } 243 | Object.assign(options, { agent }) 244 | } 245 | $.get(options, async (err, resp, data) => { 246 | try { 247 | if (err) { 248 | // console.log(`${JSON.stringify(err)}`) 249 | console.log(`检测到您当前网络环境不能访问外网,将使用jsdelivr CDN下载JD_DailyBonus.js文件`); 250 | await $.http.get({url: `https://purge.jsdelivr.net/gh/NobyDa/Script@master/JD-DailyBonus/JD_DailyBonus.js`, timeout: 10000}).then((resp) => { 251 | if (resp.statusCode === 200) { 252 | let { body } = resp; 253 | body = JSON.parse(body); 254 | if (body['success']) { 255 | console.log(`JD_DailyBonus.js文件 CDN刷新成功`) 256 | } else { 257 | console.log(`JD_DailyBonus.js文件 CDN刷新失败`) 258 | } 259 | } 260 | }); 261 | } else { 262 | $.body = data; 263 | } 264 | } catch (e) { 265 | $.logErr(e, resp) 266 | } finally { 267 | resolve(); 268 | } 269 | }) 270 | }) 271 | } 272 | function requireConfig() { 273 | return new Promise(resolve => { 274 | // const file = 'jd_bean_sign.js'; 275 | // fs.access(file, fs.constants.W_OK, (err) => { 276 | // resultPath = err ? '/tmp/result.txt' : resultPath; 277 | // JD_DailyBonusPath = err ? '/tmp/JD_DailyBonus.js' : JD_DailyBonusPath; 278 | // outPutUrl = err ? '/tmp/' : outPutUrl; 279 | // NodeSet = err ? '/tmp/CookieSet.json' : NodeSet; 280 | // resolve() 281 | // }); 282 | //判断是否是云函数环境。原函数跟目录目录没有可写入权限,文件只能放到根目录下虚拟的/temp/文件夹(具有可写入权限) 283 | resultPath = process.env.TENCENTCLOUD_RUNENV === 'SCF' ? '/tmp/result.txt' : resultPath; 284 | JD_DailyBonusPath = process.env.TENCENTCLOUD_RUNENV === 'SCF' ? '/tmp/JD_DailyBonus.js' : JD_DailyBonusPath; 285 | outPutUrl = process.env.TENCENTCLOUD_RUNENV === 'SCF' ? '/tmp/' : outPutUrl; 286 | NodeSet = process.env.TENCENTCLOUD_RUNENV === 'SCF' ? '/tmp/CookieSet.json' : NodeSet; 287 | resolve() 288 | }) 289 | } 290 | function timeFormat(time) { 291 | let date; 292 | if (time) { 293 | date = new Date(time) 294 | } else { 295 | date = new Date(); 296 | } 297 | return date.getFullYear() + '-' + ((date.getMonth() + 1) >= 10 ? (date.getMonth() + 1) : '0' + (date.getMonth() + 1)) + '-' + (date.getDate() >= 10 ? date.getDate() : '0' + date.getDate()); 298 | } 299 | function Env(t,e){"undefined"!=typeof process&&JSON.stringify(process.env).indexOf("GITHUB")>-1&&process.exit(0);class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`🔔${this.name}, 开始!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),n={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(n,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon()?(this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)})):this.isQuanX()?(this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t))):this.isNode()&&(this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>{const{message:s,response:i}=t;e(s,i,i&&i.body)}))}post(t,e=(()=>{})){if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.post(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method="POST",this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){this.initGotEnv(t);const{url:s,...i}=t;this.got.post(s,i).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>{const{message:s,response:i}=t;e(s,i,i&&i.body)})}}time(t,e=null){const s=e?new Date(e):new Date;let i={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in i)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?i[e]:("00"+i[e]).substr((""+i[e]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl;return{"open-url":e,"media-url":s}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============📣系统通知📣=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`❗️${this.name}, 错误!`,t.stack):this.log("",`❗️${this.name}, 错误!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`🔔${this.name}, 结束! 🕛 ${s} 秒`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)} 300 | -------------------------------------------------------------------------------- /JD/sendNotify.js: -------------------------------------------------------------------------------- 1 | /* 2 | Last Modified time: 2021-9-28 17:42:54 3 | */ 4 | /** 5 | * sendNotify 推送通知功能 6 | * @param text 通知头 7 | * @param desp 通知体 8 | * @param params 某些推送通知方式点击弹窗可跳转, 例:{ url: 'https://abc.com' } 9 | * @param author 作者仓库等信息 例:`本脚本免费使用 By:xxx` 10 | * @returns {Promise} 11 | */ 12 | const querystring = require("querystring"); 13 | const $ = new Env(); 14 | const timeout = 15000;//超时时间(单位毫秒) 15 | // =======================================微信server酱通知设置区域=========================================== 16 | //此处填你申请的SCKEY. 17 | //(环境变量名 PUSH_KEY) 18 | let SCKEY = ''; 19 | 20 | // =======================================Bark App通知设置区域=========================================== 21 | //此处填你BarkAPP的信息(IP/设备码,例如:https://api.day.app/XXXXXXXX) 22 | let BARK_PUSH = ''; 23 | //BARK app推送铃声,铃声列表去APP查看复制填写 24 | let BARK_SOUND = ''; 25 | //BARK v1.1.5版本的BARK 支持分组功能,可在历史消息中分组查看消息,默认'京东' 26 | let BARK_GROUP = '京东'; 27 | 28 | // =======================================telegram机器人通知设置区域=========================================== 29 | //此处填你telegram bot 的Token,telegram机器人通知推送必填项.例如:1077xxx4424:AAFjv0FcqxxxxxxgEMGfi22B4yh15R5uw 30 | //(环境变量名 TG_BOT_TOKEN) 31 | let TG_BOT_TOKEN = ''; 32 | //此处填你接收通知消息的telegram用户的id,telegram机器人通知推送必填项.例如:129xxx206 33 | //(环境变量名 TG_USER_ID) 34 | let TG_USER_ID = ''; 35 | //tg推送HTTP代理设置(不懂可忽略,telegram机器人通知推送功能中非必填) 36 | let TG_PROXY_HOST = '';//例如:127.0.0.1(环境变量名:TG_PROXY_HOST) 37 | let TG_PROXY_PORT = '';//例如:1080(环境变量名:TG_PROXY_PORT) 38 | let TG_PROXY_AUTH = '';//tg代理配置认证参数 39 | //Telegram api自建的反向代理地址(不懂可忽略,telegram机器人通知推送功能中非必填),默认tg官方api(环境变量名:TG_API_HOST) 40 | let TG_API_HOST = 'api.telegram.org' 41 | // =======================================钉钉机器人通知设置区域=========================================== 42 | //此处填你钉钉 bot 的webhook,例如:5a544165465465645d0f31dca676e7bd07415asdasd 43 | //(环境变量名 DD_BOT_TOKEN) 44 | let DD_BOT_TOKEN = ''; 45 | //密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的字符串 46 | let DD_BOT_SECRET = ''; 47 | 48 | // =======================================企业微信机器人通知设置区域=========================================== 49 | //此处填你企业微信机器人的 webhook(详见文档 https://work.weixin.qq.com/api/doc/90000/90136/91770),例如:693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa 50 | //(环境变量名 QYWX_KEY) 51 | let QYWX_KEY = ''; 52 | 53 | // =======================================企业微信应用消息通知设置区域=========================================== 54 | /* 55 | 此处填你企业微信应用消息的值(详见文档 https://work.weixin.qq.com/api/doc/90000/90135/90236) 56 | 环境变量名 QYWX_AM依次填入 corpid,corpsecret,touser(注:多个成员ID使用|隔开),agentid,消息类型(选填,不填默认文本消息类型) 57 | 注意用,号隔开(英文输入法的逗号),例如:wwcff56746d9adwers,B-791548lnzXBE6_BWfxdf3kSTMJr9vFEPKAbh6WERQ,mingcheng,1000001,2COXgjH2UIfERF2zxrtUOKgQ9XklUqMdGSWLBoW_lSDAdafat 58 | 可选推送消息类型(推荐使用图文消息(mpnews)): 59 | - 文本卡片消息: 0 (数字零) 60 | - 文本消息: 1 (数字一) 61 | - 图文消息(mpnews): 素材库图片id, 可查看此教程(http://note.youdao.com/s/HMiudGkb)或者(https://note.youdao.com/ynoteshare1/index.html?id=1a0c8aff284ad28cbd011b29b3ad0191&type=note) 62 | 企业微信应用消息通知已实现一对一推送:(第一个微信ID可为@all,也可为具体某个人的微信ID,例3情况则发送到第一个微信ID,如果有不想发送通知的账号,可设置为@N) 63 | 1、@ll|账号1|账号2|@N|账号4(配置说明:例3情况发送给@all,账号1发送给配置的微信ID1,账号2发送给配置的微信ID2,@N则表示不给账号3推送,账号4发送给配置的微信ID4) 64 | 2、如果只配置了一个微信ID,则把全部消息发送给这个已配置的微信ID 65 | 3、如果账号数量比已配置的微信ID数量要多,则超出的账号消息合并到一块,再一次性发送给第一个配置的微信ID 66 | */ 67 | let QYWX_AM = ''; 68 | 69 | // =======================================iGot聚合推送通知设置区域=========================================== 70 | //此处填您iGot的信息(推送key,例如:https://push.hellyw.com/XXXXXXXX) 71 | let IGOT_PUSH_KEY = ''; 72 | 73 | // =======================================push+设置区域======================================= 74 | //官方文档:http://www.pushplus.plus/ 75 | //PUSH_PLUS_TOKEN:微信扫码登录后一对一推送或一对多推送下面的token(您的Token),不提供PUSH_PLUS_USER则默认为一对一推送 76 | //PUSH_PLUS_USER: 一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送) 77 | let PUSH_PLUS_TOKEN = ''; 78 | let PUSH_PLUS_USER = ''; 79 | 80 | //==========================云端环境变量的判断与接收========================= 81 | if (process.env.PUSH_KEY) { 82 | SCKEY = process.env.PUSH_KEY; 83 | } 84 | 85 | if (process.env.QQ_SKEY) { 86 | QQ_SKEY = process.env.QQ_SKEY; 87 | } 88 | 89 | if (process.env.QQ_MODE) { 90 | QQ_MODE = process.env.QQ_MODE; 91 | } 92 | 93 | 94 | if (process.env.BARK_PUSH) { 95 | if(process.env.BARK_PUSH.indexOf('https') > -1 || process.env.BARK_PUSH.indexOf('http') > -1) { 96 | //兼容BARK自建用户 97 | BARK_PUSH = process.env.BARK_PUSH 98 | } else { 99 | BARK_PUSH = `https://api.day.app/${process.env.BARK_PUSH}` 100 | } 101 | } else { 102 | if(BARK_PUSH && BARK_PUSH.indexOf('https') === -1 && BARK_PUSH.indexOf('http') === -1) { 103 | //兼容BARK本地用户只填写设备码的情况 104 | BARK_PUSH = `https://api.day.app/${BARK_PUSH}` 105 | } 106 | } 107 | if (process.env.BARK_SOUND) { 108 | BARK_SOUND = process.env.BARK_SOUND 109 | } 110 | if (process.env.BARK_GROUP) { 111 | BARK_GROUP = process.env.BARK_GROUP; 112 | } 113 | 114 | 115 | if (process.env.TG_BOT_TOKEN) { 116 | TG_BOT_TOKEN = process.env.TG_BOT_TOKEN; 117 | } 118 | if (process.env.TG_USER_ID) { 119 | TG_USER_ID = process.env.TG_USER_ID; 120 | } 121 | if (process.env.TG_PROXY_AUTH) TG_PROXY_AUTH = process.env.TG_PROXY_AUTH; 122 | if (process.env.TG_PROXY_HOST) TG_PROXY_HOST = process.env.TG_PROXY_HOST; 123 | if (process.env.TG_PROXY_PORT) TG_PROXY_PORT = process.env.TG_PROXY_PORT; 124 | if (process.env.TG_API_HOST) TG_API_HOST = process.env.TG_API_HOST; 125 | 126 | if (process.env.DD_BOT_TOKEN) { 127 | DD_BOT_TOKEN = process.env.DD_BOT_TOKEN; 128 | if (process.env.DD_BOT_SECRET) { 129 | DD_BOT_SECRET = process.env.DD_BOT_SECRET; 130 | } 131 | } 132 | 133 | if (process.env.QYWX_KEY) { 134 | QYWX_KEY = process.env.QYWX_KEY; 135 | } 136 | 137 | if (process.env.QYWX_AM) { 138 | QYWX_AM = process.env.QYWX_AM; 139 | } 140 | 141 | if (process.env.IGOT_PUSH_KEY) { 142 | IGOT_PUSH_KEY = process.env.IGOT_PUSH_KEY 143 | } 144 | 145 | if (process.env.PUSH_PLUS_TOKEN) { 146 | PUSH_PLUS_TOKEN = process.env.PUSH_PLUS_TOKEN; 147 | } 148 | if (process.env.PUSH_PLUS_USER) { 149 | PUSH_PLUS_USER = process.env.PUSH_PLUS_USER; 150 | } 151 | //==========================云端环境变量的判断与接收========================= 152 | 153 | /** 154 | * sendNotify 推送通知功能 155 | * @param text 通知头 156 | * @param desp 通知体 157 | * @param params 某些推送通知方式点击弹窗可跳转, 例:{ url: 'https://abc.com' } 158 | * @param author 作者仓库等信息 例:`本脚本免费使用 By:xxxx` 159 | * @returns {Promise} 160 | */ 161 | async function sendNotify(text, desp, params = {}, author = '') { 162 | //提供6种通知 163 | desp += author;//增加作者信息,防止被贩卖等 164 | await Promise.all([ 165 | serverNotify(text, desp),//微信server酱 166 | pushPlusNotify(text, desp)//pushplus(推送加) 167 | ]) 168 | //由于上述两种微信通知需点击进去才能查看到详情,故text(标题内容)携带了账号序号以及昵称信息,方便不点击也可知道是哪个京东哪个活动 169 | text = text.match(/.*?(?=\s?-)/g) ? text.match(/.*?(?=\s?-)/g)[0] : text; 170 | await Promise.all([ 171 | // BarkNotify(text, desp, params),//iOS Bark APP 172 | // tgBotNotify(text, desp),//telegram 机器人 173 | ddBotNotify(text, desp),//钉钉机器人 174 | qywxBotNotify(text, desp), //企业微信机器人 175 | qywxamNotify(text, desp), //企业微信应用消息推送 176 | iGotNotify(text, desp, params),//iGot 177 | //CoolPush(text, desp)//QQ酷推 178 | ]) 179 | let despArr = desp.split('\n\n'); 180 | let str = '', arr = []; 181 | for (let i = 0; i < despArr.length; i++) { 182 | if (i + 1 === despArr.length) { 183 | str += despArr[i] 184 | } else { 185 | str += despArr[i] + '\n\n' 186 | } 187 | if (str.length >= 3000) { 188 | if (str.lastIndexOf('\n\n') > -1) str = str.substring(0, str.length - 2); 189 | arr.push(str); 190 | str = ''; 191 | continue 192 | } 193 | if (i + 1 === despArr.length) { 194 | arr.push(str); 195 | str = ''; 196 | } 197 | } 198 | if (arr.length > 1) console.log(`tg bot 机器人拆分${arr.length}次发送\n`) 199 | let promiseArr = arr.filter(item => !!item).map(des => tgBotNotify(text, des)); 200 | await Promise.all(promiseArr); 201 | str = '', arr = []; 202 | for (let i = 0; i < despArr.length; i++) { 203 | if (i + 1 === despArr.length) { 204 | str += despArr[i] 205 | } else { 206 | str += despArr[i] + '\n\n' 207 | } 208 | if (str.length >= 500) { 209 | if (str.lastIndexOf('\n\n') > -1) str = str.substring(0, str.length - 2); 210 | arr.push(str); 211 | str = ''; 212 | continue 213 | } 214 | if (i + 1 === despArr.length) { 215 | arr.push(str); 216 | str = ''; 217 | } 218 | } 219 | if (arr.length > 1) console.log(`BARK APP 将拆分${arr.length}次发送\n`) 220 | promiseArr = arr.filter(item => !!item).map(des => BarkNotify(text, des, params)); 221 | await Promise.all(promiseArr); 222 | } 223 | 224 | function serverNotify(text, desp, time = 2100) { 225 | return new Promise(resolve => { 226 | if (SCKEY) { 227 | //微信server酱推送通知一个\n不会换行,需要两个\n才能换行,故做此替换 228 | desp = desp.replace(/[\n\r]/g, '\n\n'); 229 | const options = { 230 | url: SCKEY.includes('SCT') ? `https://sctapi.ftqq.com/${SCKEY}.send` : `https://sc.ftqq.com/${SCKEY}.send`, 231 | body: `text=${text}&desp=${desp}`, 232 | headers: { 233 | 'Content-Type': 'application/x-www-form-urlencoded' 234 | }, 235 | timeout 236 | } 237 | setTimeout(() => { 238 | $.post(options, (err, resp, data) => { 239 | try { 240 | if (err) { 241 | console.log('发送通知调用API失败!!\n') 242 | console.log(err); 243 | } else { 244 | data = JSON.parse(data); 245 | //server酱和Server酱·Turbo版的返回json格式不太一样 246 | if (data.errno === 0 || data.data.errno === 0 ) { 247 | console.log('server酱发送通知消息成功🎉\n') 248 | } else if (data.errno === 1024) { 249 | // 一分钟内发送相同的内容会触发 250 | console.log(`server酱发送通知消息异常: ${data.errmsg}\n`) 251 | } else { 252 | console.log(`server酱发送通知消息异常\n${JSON.stringify(data)}`) 253 | } 254 | } 255 | } catch (e) { 256 | $.logErr(e, resp); 257 | } finally { 258 | resolve(data); 259 | } 260 | }) 261 | }, time) 262 | } else { 263 | // console.log('\n\n您未提供server酱的SCKEY,取消微信推送消息通知🚫\n'); 264 | resolve() 265 | } 266 | }) 267 | } 268 | 269 | function CoolPush(text, desp) { 270 | return new Promise(resolve => { 271 | if (QQ_SKEY) { 272 | let options = { 273 | url: `https://push.xuthus.cc/${QQ_MODE}/${QQ_SKEY}`, 274 | headers: { 275 | 'Content-Type': 'application/json' 276 | } 277 | } 278 | 279 | // 已知敏感词 280 | text = text.replace(/京豆/g, "豆豆"); 281 | desp = desp.replace(/京豆/g, ""); 282 | desp = desp.replace(/🐶/g, ""); 283 | desp = desp.replace(/红包/g, "H包"); 284 | 285 | switch (QQ_MODE) { 286 | case "email": 287 | options.json = { 288 | "t": text, 289 | "c": desp, 290 | }; 291 | break; 292 | default: 293 | options.body = `${text}\n\n${desp}`; 294 | } 295 | 296 | let pushMode = function(t) { 297 | switch (t){ 298 | case "send": 299 | return "个人"; 300 | case "group": 301 | return "QQ群"; 302 | case "wx": 303 | return "微信"; 304 | case "ww": 305 | return "企业微信"; 306 | case "email": 307 | return "邮件"; 308 | default: 309 | return "未知方式" 310 | } 311 | } 312 | 313 | $.post(options, (err, resp, data) => { 314 | try { 315 | if (err) { 316 | console.log(`发送${pushMode(QQ_MODE)}通知调用API失败!!\n`) 317 | console.log(err); 318 | } else { 319 | data = JSON.parse(data); 320 | if (data.code === 200) { 321 | console.log(`酷推发送${pushMode(QQ_MODE)}通知消息成功🎉\n`) 322 | } else if (data.code === 400) { 323 | console.log(`QQ酷推(Cool Push)发送${pushMode(QQ_MODE)}推送失败:${data.msg}\n`) 324 | } else if (data.code === 503) { 325 | console.log(`QQ酷推出错,${data.message}:${data.data}\n`) 326 | }else{ 327 | console.log(`酷推推送异常: ${JSON.stringify(data)}`); 328 | } 329 | } 330 | } catch (e) { 331 | $.logErr(e, resp); 332 | } finally { 333 | resolve(data); 334 | } 335 | }) 336 | } else { 337 | // console.log('您未提供酷推的SKEY,取消QQ推送消息通知🚫\n'); 338 | resolve() 339 | } 340 | }) 341 | } 342 | 343 | function BarkNotify(text, desp, params={}) { 344 | return new Promise(resolve => { 345 | if (BARK_PUSH) { 346 | const options = { 347 | url: `${BARK_PUSH}/${encodeURIComponent(text)}/${encodeURIComponent(desp)}?sound=${BARK_SOUND}&group=${BARK_GROUP}&${querystring.stringify(params)}`, 348 | headers: { 349 | 'Content-Type': 'application/x-www-form-urlencoded' 350 | }, 351 | timeout 352 | } 353 | $.get(options, (err, resp, data) => { 354 | try { 355 | if (err) { 356 | console.log('Bark APP发送通知调用API失败!!\n') 357 | console.log(err); 358 | } else { 359 | data = JSON.parse(data); 360 | if (data.code === 200) { 361 | console.log('Bark APP发送通知消息成功🎉\n') 362 | } else { 363 | console.log(`${data.message}\n`); 364 | } 365 | } 366 | } catch (e) { 367 | $.logErr(e, resp); 368 | } finally { 369 | resolve(); 370 | } 371 | }) 372 | } else { 373 | // console.log('您未提供Bark的APP推送BARK_PUSH,取消Bark推送消息通知🚫\n'); 374 | resolve() 375 | } 376 | }) 377 | } 378 | 379 | function tgBotNotify(text, desp) { 380 | return new Promise(resolve => { 381 | if (TG_BOT_TOKEN && TG_USER_ID) { 382 | const options = { 383 | url: `https://${TG_API_HOST}/bot${TG_BOT_TOKEN}/sendMessage`, 384 | body: `chat_id=${TG_USER_ID}&text=${text}\n\n${desp}&disable_web_page_preview=true`, 385 | headers: { 386 | 'Content-Type': 'application/x-www-form-urlencoded' 387 | }, 388 | timeout 389 | } 390 | if (TG_PROXY_HOST && TG_PROXY_PORT) { 391 | const tunnel = require("tunnel"); 392 | const agent = { 393 | https: tunnel.httpsOverHttp({ 394 | proxy: { 395 | host: TG_PROXY_HOST, 396 | port: TG_PROXY_PORT * 1, 397 | proxyAuth: TG_PROXY_AUTH 398 | } 399 | }) 400 | } 401 | Object.assign(options, { agent }) 402 | } 403 | $.post(options, (err, resp, data) => { 404 | try { 405 | if (err) { 406 | console.log('telegram发送通知消息失败!!\n') 407 | console.log(err); 408 | } else { 409 | data = JSON.parse(data); 410 | if (data.ok) { 411 | console.log('Telegram发送通知消息成功🎉。\n') 412 | } else if (data.error_code === 400) { 413 | console.log('请主动给bot发送一条消息并检查接收用户ID是否正确。\n') 414 | } else if (data.error_code === 401){ 415 | console.log('Telegram bot token 填写错误。\n') 416 | } 417 | } 418 | } catch (e) { 419 | $.logErr(e, resp); 420 | } finally { 421 | resolve(data); 422 | } 423 | }) 424 | } else { 425 | // console.log('您未提供telegram机器人推送所需的TG_BOT_TOKEN和TG_USER_ID,取消telegram推送消息通知🚫\n'); 426 | resolve() 427 | } 428 | }) 429 | } 430 | function ddBotNotify(text, desp) { 431 | return new Promise(resolve => { 432 | const options = { 433 | url: `https://oapi.dingtalk.com/robot/send?access_token=${DD_BOT_TOKEN}`, 434 | json: { 435 | "msgtype": "text", 436 | "text": { 437 | "content": ` ${text}\n\n${desp}` 438 | } 439 | }, 440 | headers: { 441 | 'Content-Type': 'application/json' 442 | }, 443 | timeout 444 | } 445 | if (DD_BOT_TOKEN && DD_BOT_SECRET) { 446 | const crypto = require('crypto'); 447 | const dateNow = Date.now(); 448 | const hmac = crypto.createHmac('sha256', DD_BOT_SECRET); 449 | hmac.update(`${dateNow}\n${DD_BOT_SECRET}`); 450 | const result = encodeURIComponent(hmac.digest('base64')); 451 | options.url = `${options.url}×tamp=${dateNow}&sign=${result}`; 452 | $.post(options, (err, resp, data) => { 453 | try { 454 | if (err) { 455 | console.log('钉钉发送通知消息失败!!\n') 456 | console.log(err); 457 | } else { 458 | data = JSON.parse(data); 459 | if (data.errcode === 0) { 460 | console.log('钉钉发送通知消息成功🎉。\n') 461 | } else { 462 | console.log(`${data.errmsg}\n`) 463 | } 464 | } 465 | } catch (e) { 466 | $.logErr(e, resp); 467 | } finally { 468 | resolve(data); 469 | } 470 | }) 471 | } else if (DD_BOT_TOKEN) { 472 | $.post(options, (err, resp, data) => { 473 | try { 474 | if (err) { 475 | console.log('钉钉发送通知消息失败!!\n') 476 | console.log(err); 477 | } else { 478 | data = JSON.parse(data); 479 | if (data.errcode === 0) { 480 | console.log('钉钉发送通知消息完成。\n') 481 | } else { 482 | console.log(`${data.errmsg}\n`) 483 | } 484 | } 485 | } catch (e) { 486 | $.logErr(e, resp); 487 | } finally { 488 | resolve(data); 489 | } 490 | }) 491 | } else { 492 | // console.log('您未提供钉钉机器人推送所需的DD_BOT_TOKEN或者DD_BOT_SECRET,取消钉钉推送消息通知🚫\n'); 493 | resolve() 494 | } 495 | }) 496 | } 497 | 498 | function qywxBotNotify(text, desp) { 499 | return new Promise(resolve => { 500 | const options = { 501 | url: `https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${QYWX_KEY}`, 502 | json: { 503 | msgtype: 'text', 504 | text: { 505 | content: ` ${text}\n\n${desp}`, 506 | }, 507 | }, 508 | headers: { 509 | 'Content-Type': 'application/json', 510 | }, 511 | timeout 512 | }; 513 | if (QYWX_KEY) { 514 | $.post(options, (err, resp, data) => { 515 | try { 516 | if (err) { 517 | console.log('企业微信发送通知消息失败!!\n'); 518 | console.log(err); 519 | } else { 520 | data = JSON.parse(data); 521 | if (data.errcode === 0) { 522 | console.log('企业微信发送通知消息成功🎉。\n'); 523 | } else { 524 | console.log(`${data.errmsg}\n`); 525 | } 526 | } 527 | } catch (e) { 528 | $.logErr(e, resp); 529 | } finally { 530 | resolve(data); 531 | } 532 | }); 533 | } else { 534 | // console.log('您未提供企业微信机器人推送所需的QYWX_KEY,取消企业微信推送消息通知🚫\n'); 535 | resolve(); 536 | } 537 | }); 538 | } 539 | 540 | function isBlank(str) { 541 | str = str.replace(/\ +/g, ""); 542 | str = str.replace(/[ ]/g, ""); 543 | str = str.replace(/[\r\n]/g, ""); 544 | return !Boolean(str); 545 | } 546 | async function qywxamNotify(text, desp) { 547 | if (!QYWX_AM) return; 548 | const [corpid, corpsecret, userIds, agentid, thumb_media_id] = QYWX_AM.split(","); 549 | const despTmp = desp.split("\n\n").filter(item => !!item); 550 | const userIdsTmp = userIds.split("|"); 551 | const accIdxRE = /\d+/; 552 | let accIdx, userId, remainDes = []; 553 | for (let i = 0; i < despTmp.length; i++) { 554 | if (despTmp[i].match(accIdxRE) && despTmp[i].indexOf('账号') > -1) { 555 | accIdx = parseInt(despTmp[i].match(accIdxRE)[0]); 556 | if (userIdsTmp.length === 1) { 557 | //如果只配置了一个微信ID,则把已经拆分的消息合并起来再一次性发送给这个已配置的微信ID 558 | accIdx = 0; 559 | remainDes.push(despTmp[i]); 560 | continue; 561 | } 562 | userId = userIdsTmp[accIdx]; 563 | if (typeof userId == "undefined") { 564 | //如果账号数量比配置的微信ID数量要多,则超出的账号消息合并到一块,再一次性发送给第一个配置的微信ID 565 | remainDes.push(despTmp[i]); 566 | } else if (userId === "@N") { 567 | console.log("\n账户" + despTmp[i].match(accIdxRE)[0] + " 企业微信应用通知配置ID为@N,跳过通知\n"); 568 | } else if (!!userId) { 569 | //账号与对应微信userId存在 570 | await qywxamSplitNotify(text, despTmp[i], userIdsTmp[accIdx]); 571 | } 572 | } else if (!isBlank(despTmp[i])) { 573 | await qywxamSplitNotify(text, despTmp[i], userIdsTmp[0]); 574 | } 575 | } 576 | if (remainDes && remainDes.length) { 577 | let str = ''; 578 | for (let i = 0; i < remainDes.length; i++) { 579 | if (i + 1 === remainDes.length) { 580 | str += remainDes[i] 581 | } else { 582 | str += remainDes[i] + '\n\n' 583 | } 584 | } 585 | await qywxamSplitNotify(text, str, userIdsTmp[0]); 586 | } 587 | } 588 | function qywxamSplitNotify(text, desp, userId = '@all') { 589 | return new Promise(resolve => { 590 | if (QYWX_AM) { 591 | // const QYWX_AM_AY = QYWX_AM.split(','); 592 | const [corpid, corpsecret, userIds, agentid, thumb_media_id] = QYWX_AM.split(','); 593 | const options_accesstoken = { 594 | url: `https://qyapi.weixin.qq.com/cgi-bin/gettoken`, 595 | json: { 596 | corpid, 597 | corpsecret, 598 | }, 599 | headers: { 600 | 'Content-Type': 'application/json', 601 | }, 602 | timeout 603 | }; 604 | $.post(options_accesstoken, (err, resp, data) => { 605 | html = desp.replace(/\n/g, "
") 606 | var json = JSON.parse(data); 607 | accesstoken = json.access_token; 608 | let options; 609 | 610 | switch (thumb_media_id) { 611 | case '0': 612 | options = { 613 | msgtype: 'textcard', 614 | textcard: { 615 | title: `${text}`, 616 | description: `${desp}`, 617 | url: '', 618 | btntxt: '更多' 619 | } 620 | } 621 | break; 622 | 623 | case '1': 624 | options = { 625 | msgtype: 'text', 626 | text: { 627 | content: `${text}\n\n${desp}` 628 | } 629 | } 630 | break; 631 | 632 | default: 633 | options = { 634 | msgtype: 'mpnews', 635 | mpnews: { 636 | articles: [ 637 | { 638 | title: `${text}`, 639 | thumb_media_id, 640 | author: `智能助手`, 641 | content_source_url: ``, 642 | content: `${html}`, 643 | digest: `${desp}` 644 | } 645 | ] 646 | } 647 | } 648 | }; 649 | if (!thumb_media_id) { 650 | //如不提供第四个参数,则默认进行文本消息类型推送 651 | options = { 652 | msgtype: 'text', 653 | text: { 654 | content: `${text}\n\n${desp}` 655 | } 656 | } 657 | } 658 | options = { 659 | url: `https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${accesstoken}`, 660 | json: { 661 | touser: `${userId}`, 662 | agentid: agentid, 663 | safe: '0', 664 | ...options 665 | }, 666 | headers: { 667 | 'Content-Type': 'application/json', 668 | }, 669 | } 670 | 671 | $.post(options, (err, resp, data) => { 672 | try { 673 | if (err) { 674 | console.log('\n成员ID:' + userId + ' 企业微信应用消息发送通知消息失败!!\n'); 675 | console.log(err); 676 | } else { 677 | data = JSON.parse(data); 678 | if (data.errcode === 0) { 679 | console.log('\n成员ID:' + userId + ' 企业微信应用消息发送通知消息成功🎉。\n'); 680 | } else { 681 | console.log(`${data.errmsg}\n`); 682 | } 683 | } 684 | } catch (e) { 685 | $.logErr(e, resp); 686 | } finally { 687 | resolve(data); 688 | } 689 | }); 690 | }); 691 | } else { 692 | // console.log('您未提供企业微信应用消息推送所需的QYWX_AM,取消企业微信应用消息推送消息通知🚫\n'); 693 | resolve(); 694 | } 695 | }); 696 | } 697 | 698 | function iGotNotify(text, desp, params={}){ 699 | return new Promise(resolve => { 700 | if (IGOT_PUSH_KEY) { 701 | // 校验传入的IGOT_PUSH_KEY是否有效 702 | const IGOT_PUSH_KEY_REGX = new RegExp("^[a-zA-Z0-9]{24}$") 703 | if(!IGOT_PUSH_KEY_REGX.test(IGOT_PUSH_KEY)) { 704 | console.log('您所提供的IGOT_PUSH_KEY无效\n') 705 | resolve() 706 | return 707 | } 708 | const options = { 709 | url: `https://push.hellyw.com/${IGOT_PUSH_KEY.toLowerCase()}`, 710 | body: `title=${text}&content=${desp}&${querystring.stringify(params)}`, 711 | headers: { 712 | 'Content-Type': 'application/x-www-form-urlencoded' 713 | }, 714 | timeout 715 | } 716 | $.post(options, (err, resp, data) => { 717 | try { 718 | if (err) { 719 | console.log('发送通知调用API失败!!\n') 720 | console.log(err); 721 | } else { 722 | if(typeof data === 'string') data = JSON.parse(data); 723 | if (data.ret === 0) { 724 | console.log('iGot发送通知消息成功🎉\n') 725 | } else { 726 | console.log(`iGot发送通知消息失败:${data.errMsg}\n`) 727 | } 728 | } 729 | } catch (e) { 730 | $.logErr(e, resp); 731 | } finally { 732 | resolve(data); 733 | } 734 | }) 735 | } else { 736 | // console.log('您未提供iGot的推送IGOT_PUSH_KEY,取消iGot推送消息通知🚫\n'); 737 | resolve() 738 | } 739 | }) 740 | } 741 | 742 | function pushPlusNotify(text, desp) { 743 | return new Promise(resolve => { 744 | if (PUSH_PLUS_TOKEN) { 745 | desp = desp.replace(/[\n\r]/g, '
'); // 默认为html, 不支持plaintext 746 | const body = { 747 | token: `${PUSH_PLUS_TOKEN}`, 748 | title: `${text}`, 749 | content:`${desp}`, 750 | topic: `${PUSH_PLUS_USER}` 751 | }; 752 | const options = { 753 | url: `http://www.pushplus.plus/send`, 754 | body: JSON.stringify(body), 755 | headers: { 756 | 'Content-Type': ' application/json' 757 | }, 758 | timeout 759 | } 760 | $.post(options, (err, resp, data) => { 761 | try { 762 | if (err) { 763 | console.log(`push+发送${PUSH_PLUS_USER ? '一对多' : '一对一'}通知消息失败!!\n`) 764 | console.log(err); 765 | } else { 766 | data = JSON.parse(data); 767 | if (data.code === 200) { 768 | console.log(`push+发送${PUSH_PLUS_USER ? '一对多' : '一对一'}通知消息完成。\n`) 769 | } else { 770 | console.log(`push+发送${PUSH_PLUS_USER ? '一对多' : '一对一'}通知消息失败:${data.msg}\n`) 771 | } 772 | } 773 | } catch (e) { 774 | $.logErr(e, resp); 775 | } finally { 776 | resolve(data); 777 | } 778 | }) 779 | } else { 780 | // console.log('您未提供push+推送所需的PUSH_PLUS_TOKEN,取消push+推送消息通知🚫\n'); 781 | resolve() 782 | } 783 | }) 784 | } 785 | 786 | module.exports = { 787 | sendNotify, 788 | BARK_PUSH 789 | } 790 | // prettier-ignore 791 | function Env(t,s){return new class{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(){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))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),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){let s=this.getval(t);if(/^@/.test(t)){const[,e,i]=/^@(.*?)\.(.*?)$/.exec(t),o=e?this.getval(e):"";if(o)try{const t=JSON.parse(o);s=t?this.lodash_get(t,i,""):s}catch(t){s=""}}return s}setdata(t,s){let e=!1;if(/^@/.test(s)){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)}catch(s){const h={};this.lodash_set(h,o,t),e=this.setval(JSON.stringify(h),i)}}else e=$.setval(t,s);return e}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=(()=>{})){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)=>{try{const e=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();this.ckjar.setCookieSync(e,null),s.cookieJar=this.ckjar}catch(t){this.logErr(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)))}post(t,s=(()=>{})){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)});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));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))}}time(t){let 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(let 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,s){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)}}(t,s)} 792 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AutoJD 2 | 3 | 京东自动签到领京豆脚本
4 | 5 | ## !!!需要nodejs运行环境!!!
6 | 7 | ## 参考了多位大佬的开源配置,但是实在是找不到原作者是谁。。所以就不挂了,如您认为此项目侵犯了您的权益请通知我将其移除!
8 | 9 | # 使用先决条件:
10 |
11 | 1. 一台部署了nodejs运行环境的设备。
12 |
13 | 2. 京东账号登录的cookie。
14 | 15 | # 使用说明:
16 |
17 | 1. 将JD这个目录整个上传到您的设备上,并确保其拥有执行权限。
18 |
19 | 2. 修改jdCookie.js文件,按照注释填写即可(仅需填写你获取到的cookie,其他保持默认,支持多账号同时挂)
20 |
21 | 3. 在JD目录内执行以下操作:
22 |
23 | npm init -f #初始化项目
24 | npm install formidable --save #安装依赖
25 | npm i download #安装依赖
26 | npm i formidable #安装依赖
27 | npm i request #安装依赖
28 | npm i tough-cookie #安装依赖
29 | node jd_bean_sign.js #运行签到脚本
30 |
31 | 4. 将node jd_bean_sign.js这条指令添加到您系统的计划任务中,每天执行一次即可,因为大家用的系统可能都不一样,所以这里就不详细写了,如果不会搞自行百度。 32 |
33 | 5. 修改sendNotify.js文件,依旧是按照注释填写,这个文件是用来做推送的,支持server酱、企业微信、bark之类的,按照需求修改(Bark不太好使,目前正在解决,解决了之后会放更新)
34 | --------------------------------------------------------------------------------