diff --git a/docker/crontab_list.sh b/docker/crontab_list.sh index 071045a..1cd6f9e 100755 --- a/docker/crontab_list.sh +++ b/docker/crontab_list.sh @@ -4,6 +4,8 @@ #30 * * * * sh +x /scripts/docker/auto_help.sh collect >> /scripts/logs/auto_help_collect.log 2>&1 ##############短期活动############## +#手机狂欢城 +0 0-18/6 * * * node /scripts/jd_5g.js >> /scripts/logs/jd_5g.log 2>&1 #七夕 36 0,10,21 4-15 8 * node /scripts/jd_qixi.js >> /scripts/logs/jd_qixi.log 2>&1 #柠檬赚金币 diff --git a/getJDCookie.js b/getJDCookie.js index b0a7ba8..3b73f91 100755 --- a/getJDCookie.js +++ b/getJDCookie.js @@ -1,33 +1,30 @@ /** - * 扫码获取京东cookie,此方式得到的cookie有效期为90天(实际待测试) - * @Author: LXK9301 https://github.com/LXK9301 - * @Date: 2021-01-13 12:12:40 - * @Last Modified by: LXK9301 - * @Last Modified time: 2021-01-13 12:22:54 + * 扫码获取京东cookie,此方式得到的cookie有效期为30天 * Modify from FanchangWang https://github.com/FanchangWang */ - const $ = new Env('扫码获取京东cookie'); - const qrcode = require('qrcode-terminal'); - let s_token, cookies, guid, lsid, lstoken, okl_token, token + + const jd_env = require("./utils/JDEnv.js"); + const $ = jd_env.env("扫码获取京东cookie"); + const qrcode = require("qrcode-terminal"); + let s_token, cookies, guid, lsid, lstoken, okl_token, token; !(async () => { await loginEntrance(); await generateQrcode(); await getCookie(); })() - .catch((e) => { - $.log('', `❌ ${$.name}, 失败! 原因: ${e}!`, '') - }) - .finally(() => { - // $.done(); - }) - + .catch((e) => { + $.log("", `❌ ${$.name}, 失败! 原因: ${e}!`, ""); + }) + .finally(() => { + // $.done(); + }); function loginEntrance() { return new Promise((resolve) => { $.get(taskUrl(), async (err, resp, data) => { try { if (err) { - console.log(`${JSON.stringify(err)}`) + console.log(`${JSON.stringify(err)}`); console.log(`${$.name} API请求失败,请检查网路重试`); } else { $.headers = resp.headers; @@ -35,12 +32,12 @@ await formatSetCookies($.headers, $.data); } } catch (e) { - $.logErr(e, resp) + $.logErr(e, resp); } finally { resolve(); } - }) - }) + }); + }); } function generateQrcode() { @@ -48,27 +45,28 @@ $.post(taskPostUrl(), (err, resp, data) => { try { if (err) { - console.log(`${JSON.stringify(err)}`) + console.log(`${JSON.stringify(err)}`); console.log(`${$.name} API请求失败,请检查网路重试`); } else { $.stepsHeaders = resp.headers; data = JSON.parse(data); - token = data['token']; + token = data["token"]; // $.log('token', token) - const setCookie = resp.headers['set-cookie'][0]; - okl_token = setCookie.substring(setCookie.indexOf("=") + 1, setCookie.indexOf(";")) - const url = 'https://plogin.m.jd.com/cgi-bin/m/tmauth?appid=300&client_type=m&token=' + token; - qrcode.generate(url, {small: true}); // 输出二维码 + const setCookie = resp.headers["set-cookie"][0]; + okl_token = setCookie.substring(setCookie.indexOf("=") + 1, setCookie.indexOf(";")); + const url = "https://plogin.m.jd.com/cgi-bin/m/tmauth?appid=300&client_type=m&token=" + token; + qrcode.generate(url, { small: true }); // 输出二维码 console.log("请打开 京东APP 扫码登录(二维码有效期为3分钟)"); + console.log(`\n\n注:如扫描不到,请使用工具(例如在线二维码工具:https://cli.im)手动生成如下url二维码\n\n${url}\n\n`); } } catch (e) { - $.logErr(e, resp) + $.logErr(e, resp); } finally { resolve(); } - }) - }) + }); + }); } function checkLogin() { @@ -77,18 +75,19 @@ url: `https://plogin.m.jd.com/cgi-bin/m/tmauthchecktoken?&token=${token}&ou_state=0&okl_token=${okl_token}`, body: `lang=chs&appid=300&source=wq_passport&returnurl=https://wqlogin2.jd.com/passport/LoginRedirect?state=${Date.now()}&returnurl=//home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action`, headers: { - 'Referer': `https://plogin.m.jd.com/login/login?appid=300&returnurl=https://wqlogin2.jd.com/passport/LoginRedirect?state=${Date.now()}&returnurl=//home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action&source=wq_passport`, - 'Cookie': cookies, - 'Connection': 'Keep-Alive', - 'Content-Type': 'application/x-www-form-urlencoded; Charset=UTF-8', - 'Accept': 'application/json, text/plain, */*', - 'User-Agent': process.env.JD_USER_AGENT ? process.env.JD_USER_AGENT : (require('./USER_AGENTS').USER_AGENT), - } - } + Referer: `https://plogin.m.jd.com/login/login?appid=300&returnurl=https://wqlogin2.jd.com/passport/LoginRedirect?state=${Date.now()}&returnurl=//home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action&source=wq_passport`, + Cookie: cookies, + Connection: "Keep-Alive", + "Content-Type": "application/x-www-form-urlencoded; Charset=UTF-8", + Accept: "application/json, text/plain, */*", + "User-Agent": + "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 SP-engine/2.14.0 main%2F1.0 baiduboxapp/11.18.0.16 (Baidu; P2 13.3.1) NABar/0.0", + }, + }; $.post(options, (err, resp, data) => { try { if (err) { - console.log(`${JSON.stringify(err)}`) + console.log(`${JSON.stringify(err)}`); console.log(`${$.name} API请求失败,请检查网路重试`); } else { data = JSON.parse(data); @@ -96,79 +95,80 @@ // $.log(`errcode:${data['errcode']}`) } } catch (e) { - $.logErr(e, resp) + $.logErr(e, resp); } finally { resolve(data); } - }) - }) + }); + }); } function getCookie() { $.timer = setInterval(async () => { const checkRes = await checkLogin(); - if (checkRes['errcode'] === 0) { + if (checkRes["errcode"] === 0) { //扫描登录成功 - $.log(`扫描登录成功\n`) + $.log(`扫描登录成功\n`); clearInterval($.timer); await formatCookie($.checkLoginHeaders); $.done(); - } else if (checkRes['errcode'] === 21) { + } else if (checkRes["errcode"] === 21) { $.log(`二维码已失效,请重新获取二维码重新扫描\n`); clearInterval($.timer); $.done(); - } else if (checkRes['errcode'] === 176) { + } else if (checkRes["errcode"] === 176) { //未扫描登录 } else { $.log(`其他异常:${JSON.stringify(checkRes)}\n`); clearInterval($.timer); $.done(); } - }, 1000) + }, 1000); } function formatCookie(headers) { - new Promise(resolve => { - let pt_key = headers['set-cookie'][1] - pt_key = pt_key.substring(pt_key.indexOf("=") + 1, pt_key.indexOf(";")) - let pt_pin = headers['set-cookie'][2] - pt_pin = pt_pin.substring(pt_pin.indexOf("=") + 1, pt_pin.indexOf(";")) + new Promise((resolve) => { + let pt_key = headers["set-cookie"][1]; + pt_key = pt_key.substring(pt_key.indexOf("=") + 1, pt_key.indexOf(";")); + let pt_pin = headers["set-cookie"][2]; + pt_pin = pt_pin.substring(pt_pin.indexOf("=") + 1, pt_pin.indexOf(";")); const cookie1 = "pt_key=" + pt_key + ";pt_pin=" + pt_pin + ";"; - $.UserName = decodeURIComponent(cookie1.match(/pt_pin=(.+?);/) && cookie1.match(/pt_pin=(.+?);/)[1]) - $.log(`京东用户:${$.UserName} Cookie获取成功(有效期:${headers['strict-transport-security'].substring("max-age=7776000".indexOf('=') + 1, "max-age=7776000".length)}秒),cookie如下:`); + $.UserName = decodeURIComponent(cookie1.match(/pt_pin=([^; ]+)(?=;?)/) && cookie1.match(/pt_pin=([^; ]+)(?=;?)/)[1]); + $.log(`京东用户:${$.UserName} Cookie获取成功,cookie如下:`); $.log(`\n${cookie1}\n`); - resolve() - }) + resolve(); + }); } function formatSetCookies(headers, body) { - new Promise(resolve => { - s_token = body['s_token'] - guid = headers['set-cookie'][0] - guid = guid.substring(guid.indexOf("=") + 1, guid.indexOf(";")) - lsid = headers['set-cookie'][2] - lsid = lsid.substring(lsid.indexOf("=") + 1, lsid.indexOf(";")) - lstoken = headers['set-cookie'][3] - lstoken = lstoken.substring(lstoken.indexOf("=") + 1, lstoken.indexOf(";")) - cookies = "guid=" + guid + "; lang=chs; lsid=" + lsid + "; lstoken=" + lstoken + "; " - resolve() - }) + new Promise((resolve) => { + s_token = body["s_token"]; + guid = headers["set-cookie"][0]; + guid = guid.substring(guid.indexOf("=") + 1, guid.indexOf(";")); + lsid = headers["set-cookie"][2]; + lsid = lsid.substring(lsid.indexOf("=") + 1, lsid.indexOf(";")); + lstoken = headers["set-cookie"][3]; + lstoken = lstoken.substring(lstoken.indexOf("=") + 1, lstoken.indexOf(";")); + cookies = "guid=" + guid + "; lang=chs; lsid=" + lsid + "; lstoken=" + lstoken + "; "; + resolve(); + }); } function taskUrl() { return { url: `https://plogin.m.jd.com/cgi-bin/mm/new_login_entrance?lang=chs&appid=300&returnurl=https://wq.jd.com/passport/LoginRedirect?state=${Date.now()}&returnurl=https://home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action&source=wq_passport`, headers: { - 'Connection': 'Keep-Alive', - 'Content-Type': 'application/x-www-form-urlencoded', - 'Accept': 'application/json, text/plain, */*', - 'Accept-Language': 'zh-cn', - 'Referer': `https://plogin.m.jd.com/login/login?appid=300&returnurl=https://wq.jd.com/passport/LoginRedirect?state=${Date.now()}&returnurl=https://home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action&source=wq_passport`, - 'User-Agent': process.env.JD_USER_AGENT ? process.env.JD_USER_AGENT : (require('./USER_AGENTS').USER_AGENT), - 'Host': 'plogin.m.jd.com' - } - } + Connection: "Keep-Alive", + "Content-Type": "application/x-www-form-urlencoded", + Accept: "application/json, text/plain, */*", + "Accept-Language": "zh-cn", + Referer: `https://plogin.m.jd.com/login/login?appid=300&returnurl=https://wq.jd.com/passport/LoginRedirect?state=${Date.now()}&returnurl=https://home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action&source=wq_passport`, + "User-Agent": + "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 SP-engine/2.14.0 main%2F1.0 baiduboxapp/11.18.0.16 (Baidu; P2 13.3.1) NABar/0.0", + Host: "plogin.m.jd.com", + }, + }; } function taskPostUrl() { @@ -176,16 +176,15 @@ url: `https://plogin.m.jd.com/cgi-bin/m/tmauthreflogurl?s_token=${s_token}&v=${Date.now()}&remember=true`, body: `lang=chs&appid=300&source=wq_passport&returnurl=https://wqlogin2.jd.com/passport/LoginRedirect?state=${Date.now()}&returnurl=//home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action`, headers: { - 'Connection': 'Keep-Alive', - 'Content-Type': 'application/x-www-form-urlencoded', - 'Accept': 'application/json, text/plain, */*', - 'Accept-Language': 'zh-cn', - 'Referer': `https://plogin.m.jd.com/login/login?appid=300&returnurl=https://wq.jd.com/passport/LoginRedirect?state=${Date.now()}&returnurl=https://home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action&source=wq_passport`, - 'User-Agent': process.env.JD_USER_AGENT ? process.env.JD_USER_AGENT : (require('./USER_AGENTS').USER_AGENT), - 'Host': 'plogin.m.jd.com' - } - } + Connection: "Keep-Alive", + "Content-Type": "application/x-www-form-urlencoded", + Accept: "application/json, text/plain, */*", + "Accept-Language": "zh-cn", + Referer: `https://plogin.m.jd.com/login/login?appid=300&returnurl=https://wq.jd.com/passport/LoginRedirect?state=${Date.now()}&returnurl=https://home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action&source=wq_passport`, + "User-Agent": + "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 SP-engine/2.14.0 main%2F1.0 baiduboxapp/11.18.0.16 (Baidu; P2 13.3.1) NABar/0.0", + Host: "plogin.m.jd.com", + }, + }; } - - // prettier-ignore - function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}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("@"),a={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(a,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),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){let e={"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 s in e)new RegExp("("+s+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?e[s]:("00"+e[s]).substr((""+e[s]).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=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)} \ No newline at end of file + \ No newline at end of file diff --git a/jd_5g.js b/jd_5g.js new file mode 100755 index 0000000..c4d6509 --- /dev/null +++ b/jd_5g.js @@ -0,0 +1,767 @@ +/* +京东手机狂欢城活动 +活动时间: 2021-8-9至2021-8-28 +活动入口:暂无 [活动地址](https://carnivalcity.m.jd.com) + +往期奖励: +a、第1名可获得实物手机一部 +b、 每日第2-10000名,可获得50个京豆 +c、 每日第10001-30000名可获得20个京豆 + +脚本兼容: QuantumultX, Surge, Loon, JSBox, Node.js +===================quantumultx================ +[task_local] +#京东手机狂欢城 +0 0-18/6 * * * jd_5g.js, tag=京东手机狂欢城, img-url=https://raw.githubusercontent.com/Orz-3/mini/master/Color/jd.png, enabled=true + +=====================Loon================ +[Script] +cron "0 0-18/6 * * *" script-path=jd_5g.js, tag=京东手机狂欢城 + +====================Surge================ +京东手机狂欢城 = type=cron,cronexp=0 0-18/6 * * *,wake-system=1,timeout=3600,script-path=gua_carnivalcity.js + +============小火箭========= +5G狂欢城 = type=cron,script-path=jd_5g.js, cronexpr="0 0,6,12,18 * * *", timeout=3600, enable=true +*/ +const jd_heplers = require("./utils/JDHelpers.js"); +const jd_env = require("./utils/JDEnv.js"); +const $ = jd_env.env("京东手机狂欢城"); +const notify = $.isNode() ? require("./sendNotify") : ""; +//Node.js用户请在jdCookie.js处填写京东ck; +const jdCookieNode = $.isNode() ? require("./jdCookie.js") : ""; + +//IOS等用户直接用NobyDa的jd cookie + +let cookiesArr = [], + cookie = "", + message = "", + allMessage = ""; + +if ($.isNode()) { + Object.keys(jdCookieNode).forEach((item) => { + cookiesArr.push(jdCookieNode[item]); + }); + if (process.env.JD_DEBUG && process.env.JD_DEBUG === "false") console.log = () => {}; + if (JSON.stringify(process.env).indexOf("GITHUB") > -1) process.exit(0); +} else { + cookiesArr = [$.getdata("CookieJD"), $.getdata("CookieJD2"), ...jd_heplers.jsonParse($.getdata("CookiesJD") || "[]").map((item) => item.cookie)].filter((item) => !!item); +} +let inviteCodes = []; +$.shareCodesArr = []; +const JD_API_HOST = "https://api.m.jd.com/api"; +const activeEndTime = "2021/08/28 00:00:00+08:00"; //活动结束时间 +let nowTime = new Date().getTime() + new Date().getTimezoneOffset() * 60 * 1000 + 8 * 60 * 60 * 1000; +!(async () => { + if (!cookiesArr[0]) { + $.msg($.name, "【提示】请先获取京东账号一cookie\n直接使用NobyDa的京东签到获取", "https://bean.m.jd.com/bean/signIndex.action", { "open-url": "https://bean.m.jd.com/bean/signIndex.action" }); + return; + } + $.temp = []; + if (nowTime > new Date(activeEndTime).getTime()) { + //活动结束后弹窗提醒 + $.msg($.name, "活动已结束", `该活动累计获得京豆:${$.jingBeanNum}个\n请删除此脚本\n咱江湖再见`); + if ($.isNode()) await notify.sendNotify($.name + "活动已结束", `请删除此脚本\n咱江湖再见`); + return; + } + for (let i = 0; i < cookiesArr.length; i++) { + if (cookiesArr[i]) { + cookie = cookiesArr[i]; + $.UserName = decodeURIComponent(cookie.match(/pt_pin=([^; ]+)(?=;?)/) && cookie.match(/pt_pin=([^; ]+)(?=;?)/)[1]); + $.index = i + 1; + $.isLogin = true; + $.nickName = ""; + $.jingBeanNum = 0; //累计获得京豆 + $.integralCount = 0; //累计获得积分 + $.integer = 0; //当天获得积分 + $.lasNum = 0; //当天参赛人数 + $.num = 0; //当天排名 + $.beans = 0; //本次运行获得京豆数量 + $.blockAccount = false; //黑号 + message = ""; + console.log(`\n开始【京东账号${$.index}】${$.nickName || $.UserName}\n`); + getUA(); + await shareCodesFormat(); + await JD818(); + } + } + for (let i = 0; i < cookiesArr.length; i++) { + if (cookiesArr[i]) { + cookie = cookiesArr[i]; + $.canHelp = true; //能否助力 + $.UserName = decodeURIComponent(cookie.match(/pt_pin=([^; ]+)(?=;?)/) && cookie.match(/pt_pin=([^; ]+)(?=;?)/)[1]); + if (cookiesArr && cookiesArr.length >= 1 && $.canHelp) { + console.log(`\n先自己账号内部相互邀请助力\n`); + for (let item of $.temp) { + console.log(`\n${$.UserName} 去参助力 ${item}`); + const helpRes = await toHelp(item.trim()); + if (helpRes.data.status === 5) { + console.log(`助力机会已耗尽,跳出助力`); + $.canHelp = false; + break; + } + } + } + if ($.canHelp) { + console.log(`\n\n如果有剩余助力机会,则给作者以及随机码助力`); + await doHelp(); + } + } + } + // console.log(JSON.stringify($.temp)) + if (allMessage) { + //NODE端,默认每月一日运行进行推送通知一次 + if ($.isNode()) { + await notify.sendNotify($.name, allMessage, { url: JD_API_HOST }); + $.msg($.name, "", allMessage); + } + } +})() + .catch((e) => { + $.log("", `❌ ${$.name}, 失败! 原因: ${e}!`, ""); + }) + .finally(() => { + $.done(); + }); + +async function JD818() { + try { + await indexInfo(); //获取任务 + await supportList(); //助力情况 + await getHelp(); //获取邀请码 + if ($.blockAccount) return; + await indexInfo(true); //获取任务 + await doHotProducttask(); //做热销产品任务 + await doBrandTask(); //做品牌手机任务 + await doBrowseshopTask(); //逛好货街,做任务 + // await doHelp(); + await myRank(); //领取往期排名奖励 + await getListRank(); + await getListIntegral(); + await getListJbean(); + await check(); //查询抽奖记录(未兑换的,发送提醒通知); + await showMsg(); + } catch (e) { + $.logErr(e); + } +} +async function doHotProducttask() { + $.hotProductList = $.hotProductList.filter((v) => !!v && v["status"] === "1"); + if ($.hotProductList && $.hotProductList.length) console.log(`开始 【浏览热销手机产品】任务,需等待6秒`); + for (let item of $.hotProductList) { + await doBrowse(item["id"], "", "hot", "browse", "browseHotSku"); + await $.wait(1000 * 6); + if ($.browseId) { + await getBrowsePrize($.browseId); + } + } +} +//做任务 API +function doBrowse(id = "", brandId = "", taskMark = "hot", type = "browse", logMark = "browseHotSku") { + $.browseId = ""; + return new Promise((resolve) => { + const body = { brandId: `${brandId}`, id: `${id}`, taskMark: `${taskMark}`, type: `${type}`, logMark: `${logMark}` }; + const options = taskPostUrl("/khc/task/doBrowse", body); + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + console.log(`doBrowse 做${taskMark}任务:${data}`); + data = JSON.parse(data); + if (data && data["code"] === 200) { + $.browseId = data["data"]["browseId"] || ""; + } else { + console.log(`doBrowse异常`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(); + } + }); + }); +} +//领取奖励 +function getBrowsePrize(browseId, brandId = "") { + return new Promise((resolve) => { + const body = { browseId: browseId, brandId: `${brandId}` }; + const options = taskPostUrl("/khc/task/getBrowsePrize", body); + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + console.log(`getBrowsePrize 领取奖励 结果:${data}`); + data = JSON.parse(data); + if (data && data["code"] === 200) { + if (data["data"]["jingBean"]) $.beans += data["data"]["jingBean"]; + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + }); +} +// 关注 +function followShop(browseId, brandId = "") { + return new Promise((resolve) => { + const body = { id: `${browseId}`, brandId: `${brandId}` }; + const options = taskPostUrl("/khc/task/followShop", body); + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + console.log(`followShop 领取奖励 结果:${data}`); + data = JSON.parse(data); + if (data && data["code"] === 200) { + if (data["data"]["jingBean"]) $.beans += data["data"]["jingBean"]; + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + }); +} + +async function doBrandTask() { + for (let brand of $.brandList) { + await brandTaskInfo(brand["brandId"]); + } +} +function brandTaskInfo(brandId) { + const body = { brandId: `${brandId}` }; + const options = taskPostUrl("/khc/index/brandTaskInfo", body); + $.skuTask = []; + $.shopTask = []; + $.meetingTask = []; + $.questionTask = {}; + return new Promise((resolve) => { + $.post(options, async (err, resp, data) => { + try { + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + data = $.toObj(data); + if (data.code === 200) { + let brandId = data["data"]["brandId"]; + $.skuTask = data["data"]["skuTask"] || []; + $.shopTask = data["data"]["shopTask"] || []; + $.meetingTask = data["data"]["meetingTask"] || []; + $.questionTask = data["data"]["questionTask"] || []; + let flag = true; + for (let sku of $.shopTask.filter((vo) => !!vo && vo["status"] !== "4")) { + if (flag) console.log(`\n开始做 品牌手机 【${data["data"]["brandName"]}】 任务`); + if (flag) flag = false; + console.log(`开始浏览 1-F 关注 任务 ${sku["name"]}`); + if (sku["status"] == 3) { + await followShop(sku["id"], brandId); + } else if (sku["status"] == 8) { + await doBrowse(sku["id"], brandId, "brand", "follow", "browseShop"); + await $.wait(1000 * 6); + if ($.browseId) await getBrowsePrize($.browseId, brandId); + } else { + console.log(`未知任务状态 ${sku["status"]}`); + } + } + flag = true; + for (let sku of $.skuTask.filter((vo) => !!vo && vo["status"] !== "4")) { + if (flag) console.log(`\n开始做 品牌手机 【${data["data"]["brandName"]}】 任务`); + if (flag) flag = false; + console.log(`开始浏览 2-F 单品区 任务 ${sku["name"]}`); + await doBrowse(sku["id"], brandId, "brand", "presell", "browseSku"); + await $.wait(1000 * 6); + if ($.browseId) await getBrowsePrize($.browseId, brandId); + } + flag = true; + for (let sku of $.meetingTask.filter((vo) => !!vo && vo["status"] !== "4")) { + if (flag) console.log(`\n开始做 品牌手机 【${data["data"]["brandName"]}】 任务`); + if (flag) flag = false; + console.log(`开始浏览 3-F 综合区 任务 ${sku["name"]},需等待10秒`); + await doBrowse(sku["id"], brandId, "brand", "meeting", "browseVenue"); + await $.wait(10500); + if ($.browseId) await getBrowsePrize($.browseId, brandId); + } + flag = true; + if ($.questionTask.hasOwnProperty("id") && $.questionTask["result"] === "0") { + if (flag) console.log(`\n开始做 品牌手机 【${data["data"]["brandName"]}】 任务`); + if (flag) flag = false; + console.log(`开始做答题任务 ${$.questionTask["question"]}`); + let result = 0; + for (let i = 0; i < $.questionTask["answers"].length; i++) { + if ($.questionTask["answers"][i]["right"]) { + result = i + 1; //正确答案 + } + } + if (result !== 0) { + await doQuestion(brandId, $.questionTask["id"], result); + } + } + } else { + console.log(`失败:${JSON.stringify(data)}`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + }); +} +function doQuestion(brandId, questionId, result) { + return new Promise((resolve) => { + const body = { brandId: `${brandId}`, questionId: `${questionId}`, result: result }; + const options = taskPostUrl("/khc/task/doQuestion", body); + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + console.log(`doQuestion 领取答题任务奖励 结果:${data}`); + data = JSON.parse(data); + if (data && data["code"] === 200) { + if (data["data"]["jingBean"]) $.beans += data["data"]["jingBean"]; + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + }); +} +//逛好货街,做任务 +async function doBrowseshopTask() { + $.browseshopList = $.browseshopList.filter((v) => !!v && v["status"] === "6"); + if ($.browseshopList && $.browseshopList.length) console.log(`\n开始 【逛好货街,做任务】,需等待10秒`); + for (let shop of $.browseshopList) { + await doBrowse(shop["id"], "", "browseShop", "browse", "browseShop"); + await $.wait(10000); + if ($.browseId) { + await getBrowsePrize($.browseId); + } + } +} +function indexInfo(flag = false) { + const options = taskPostUrl(`/khc/index/indexInfo`, {}); + $.hotProductList = []; + $.brandList = []; + $.browseshopList = []; + return new Promise((resolve) => { + $.post(options, async (err, resp, data) => { + try { + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + data = $.toObj(data); + if (data.code === 200) { + $.hotProductList = data["data"]["hotProductList"]; + $.brandList = data["data"]["brandList"]; + $.browseshopList = data["data"]["browseshopList"]; + } else { + console.log(`异常:${JSON.stringify(data)}`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(); + } + }); + }); +} +//获取助力信息 +function supportList() { + const options = taskPostUrl("/khc/index/supportList", {}); + return new Promise((resolve) => { + $.post(options, async (err, resp, data) => { + try { + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + data = JSON.parse(data); + if (data.code === 200) { + console.log(`助力情况:${data["data"]["supportedNums"]}/${data["data"]["supportNeedNums"]}`); + message += `邀请好友助力:${data["data"]["supportedNums"]}/${data["data"]["supportNeedNums"]}\n`; + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(); + } + }); + }); +} +//积分抽奖 +function lottery() { + const options = taskPostUrl("/khc/record/lottery", {}); + return new Promise((resolve) => { + $.post(options, async (err, resp, data) => { + try { + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + data = JSON.parse(data); + if (data.code === 200) { + if (data.data.prizeId !== 8) { + //已中奖 + const url = "https://carnivalcity.m.jd.com/#/integralDetail"; + console.log(`积分抽奖获得:${data.data.prizeName}`); + message += `积分抽奖获得:${data.data.prizeName}\n`; + $.msg($.name, "", `京东账号 ${$.index} ${$.nickName || $.UserName}\n积分抽奖获得:${data.data.prizeName}\n兑换地址:${url}`, { "open-url": url }); + if ($.isNode()) await notify.sendNotify($.name, `京东账号 ${$.index} ${$.nickName || $.UserName}\n积分抽奖获得:${data.data.prizeName}\n兑换地址:${url}`); + } else { + console.log(`积分抽奖结果:${data["data"]["prizeName"]}}`); + } + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(); + } + }); + }); +} +//查询抽奖记录(未兑换的) +function check() { + const options = taskPostUrl("/khc/record/convertRecord", { pageNum: 1 }); + return new Promise((resolve) => { + $.post(options, async (err, resp, data) => { + try { + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + data = JSON.parse(data); + let str = ""; + if (data.code === 200) { + for (let obj of data.data) { + if (obj.hasOwnProperty("fillStatus") && obj.fillStatus !== true) { + str += JSON.stringify(obj); + } + } + } + if (str.length > 0) { + const url = "https://api.m.jd.com/api/#/integralDetail"; + $.msg($.name, "", `京东账号 ${$.index} ${$.nickName || $.UserName}\n积分抽奖获得:${str}\n兑换地址:${url}`, { "open-url": url }); + if ($.isNode()) await notify.sendNotify($.name, `京东账号 ${$.index} ${$.nickName || $.UserName}\n积分抽奖获得:${str}\n兑换地址:${url}`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(); + } + }); + }); +} +function myRank() { + return new Promise((resolve) => { + const options = taskPostUrl("/khc/rank/myPastRanks", {}); + $.post(options, async (err, resp, data) => { + try { + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + data = JSON.parse(data); + if (data.code === 200) { + if (data.data && data.data.length) { + for (let i = 0; i < data.data.length; i++) { + $.date = data.data[i]["date"]; + if (data.data[i].status === "1") { + console.log(`开始领取往期奖励【${data.data[i]["prizeName"]}】`); + let res = await saveJbean($.date); + // console.log('领奖结果', res) + if (res && res.code === 200) { + $.beans += Number(res.data); + console.log(`${data.data[i]["date"]}日 【${res.data}】京豆奖励领取成功`); + } else { + console.log(`往期奖励领取失败:${JSON.stringify(res)}`); + } + await $.wait(500); + } else if (data.data[i].status === "3") { + console.log(`${data.data[i]["date"]}日 【${data.data[i]["prizeName"]}】往期京豆奖励已领取~`); + } else { + console.log(`${data.data[i]["date"]}日 【${data.data[i]["status"]}】往期京豆奖励,今日争取进入前30000名哦~`); + } + } + } + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + }); +} +//领取往期奖励API +function saveJbean(date) { + return new Promise((resolve) => { + const body = "date=" + date; + const options = taskPostUrl("/khc/rank/getRankJingBean", body); + $.post(options, (err, resp, data) => { + try { + // console.log('领取京豆结果', data); + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + data = JSON.parse(data); + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + }); +} +async function doHelp() { + console.log(`\n开始助力好友`); + for (let i in $.newShareCodes) { + let item = $.newShareCodes[i]; + if (!item) continue; + const helpRes = await toHelp(item.trim()); + if (helpRes.data.status === 5) { + console.log(`助力机会已耗尽,跳出助力`); + break; + } else if (helpRes.data.status === 4) { + console.log(`该助力码[${item}]已达上限`); + $.newShareCodes[i] = ""; + } + } +} +//助力API +function toHelp(code = "ca5cb827-4f0d-4133-85cc-9059ef8588e0") { + return new Promise((resolve) => { + const body = { shareId: `${code}` }; + const options = taskPostUrl("/khc/task/doSupport", body); + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + console.log(`助力结果:${data}`); + data = JSON.parse(data); + if (data && data["code"] === 200) { + if (data["data"]["status"] === 6) console.log(`助力成功\n`); + if (data["data"]["jdNums"]) $.beans += data["data"]["jdNums"]; + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + }); +} +//获取邀请码API +function getHelp() { + return new Promise((resolve) => { + const options = taskPostUrl("/khc/task/getSupport", {}); + $.post(options, async (err, resp, data) => { + try { + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + data = JSON.parse(data); + if (data.code === 200) { + console.log(`\n\n${$.name}互助码每天都变化,旧的不可继续使用`); + $.log(`【京东账号${$.index}(${$.UserName})的${$.name}好友互助码】${data.data.shareId}\n\n`); + $.temp.push(data.data.shareId); + } else { + console.log(`获取邀请码失败:${JSON.stringify(data)}`); + if (data.code === 1002) $.blockAccount = true; + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + }); +} +//获取当前活动总京豆数量 +function getListJbean() { + return new Promise((resolve) => { + const body = { + pageNum: ``, + }; + const options = taskPostUrl("/khc/record/jingBeanRecord", body); + $.post(options, async (err, resp, data) => { + try { + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + data = JSON.parse(data); + if (data.code === 200) { + $.jingBeanNum = data.data.jingBeanNum || 0; + message += `累计获得京豆:${$.jingBeanNum}🐶\n`; + } else { + console.log(`jingBeanRecord失败:${JSON.stringify(data)}`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + }); +} +//查询累计获得积分 +function getListIntegral() { + return new Promise((resolve) => { + const body = { + pageNum: ``, + }; + const options = taskPostUrl("/khc/record/integralRecord", body); + $.post(options, async (err, resp, data) => { + try { + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + data = JSON.parse(data); + if (data.code === 200) { + $.integralCount = data.data.integralNum || 0; //累计活动积分 + message += `累计获得积分:${$.integralCount}\n`; + console.log(`开始抽奖,当前积分可抽奖${parseInt($.integralCount / 50)}次\n`); + for (let i = 0; i < parseInt($.integralCount / 50); i++) { + await lottery(); + await $.wait(500); + } + } else { + console.log(`integralRecord失败:${JSON.stringify(data)}`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + }); +} + +//查询今日累计积分与排名 +function getListRank() { + return new Promise((resolve) => { + const options = taskPostUrl("/khc/rank/dayRank", {}); + $.post(options, async (err, resp, data) => { + try { + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + data = JSON.parse(data); + if (data.code === 200) { + if (data.data.myRank) { + $.integer = data.data.myRank.integral; //当前获得积分 + $.num = data.data.myRank.rank; //当前排名 + message += `当前获得积分:${$.integer}\n`; + message += `当前获得排名:${$.num}\n`; + } + if (data.data.lastRank) { + $.lasNum = data.data.lastRank.rank; //当前参加活动人数 + message += `当前参赛人数:${$.lasNum}\n`; + } + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + }); +} + +//格式化助力码 +function shareCodesFormat() { + return new Promise(async (resolve) => { + // console.log(`第${$.index}个京东账号的助力码:::${$.shareCodesArr[$.index - 1]}`) + $.newShareCodes = []; + if ($.shareCodesArr[$.index - 1]) { + $.newShareCodes = $.shareCodesArr[$.index - 1].split("@"); + } else { + // console.log(`由于您第${$.index}个京东账号未提供shareCode,将采纳本脚本自带的助力码\n`) + const tempIndex = $.index > inviteCodes.length ? inviteCodes.length - 1 : $.index - 1; + $.newShareCodes = (inviteCodes[tempIndex] && inviteCodes[tempIndex].split("@")) || []; + if ($.updatePkActivityIdRes && $.updatePkActivityIdRes.length) $.newShareCodes = [...$.updatePkActivityIdRes, ...$.newShareCodes]; + } + resolve(); + }); +} + +function taskPostUrl(a, t = {}) { + const body = $.toStr({ ...t, apiMapping: `${a}` }); + return { + url: `${JD_API_HOST}`, + body: `appid=guardian-starjd&functionId=carnivalcity_jd_prod&body=${body}&t=${Date.now()}&loginType=2`, + headers: { + Accept: "application/json, text/plain, */*", + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "zh-cn", + Connection: "keep-alive", + "Content-Type": "application/x-www-form-urlencoded", + Origin: "https://carnivalcity.m.jd.com", + Referer: "https://carnivalcity.m.jd.com/", + Cookie: cookie, + "User-Agent": $.UA, + }, + }; +} + +async function showMsg() { + if ($.beans) { + allMessage += `京东账号${$.index} ${$.nickName || $.UserName}\n本次运行获得:${ + $.beans + }京豆\n${message}活动地址:https://carnivalcity.m.jd.com/#/home?shareId=ddd345fb-57bb-4ece-968b-7bf4c92be7cc&t=${Date.now()}${$.index !== cookiesArr.length ? "\n\n" : ""}`; + } + $.msg($.name, `京东账号${$.index} ${$.nickName || $.UserName}`, `${message}具体详情点击弹窗跳转后即可查看`, { + "open-url": "https://carnivalcity.m.jd.com/#/home?shareId=ddd345fb-57bb-4ece-968b-7bf4c92be7cc&t=" + Date.now(), + }); +} + +function getUA() { + $.UA = `jdapp;iPhone;10.0.10;14.3;${randomString( + 40 + )};network/wifi;model/iPhone12,1;addressid/4199175193;appBuild/167741;jdSupportDarkMode/0;Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1`; +} +function randomString(e) { + e = e || 32; + let t = "abcdef0123456789", + a = t.length, + n = ""; + for (i = 0; i < e; i++) n += t.charAt(Math.floor(Math.random() * a)); + return n; +} diff --git a/utils/.gitignore b/utils/.gitignore new file mode 100755 index 0000000..4a506e7 --- /dev/null +++ b/utils/.gitignore @@ -0,0 +1,2 @@ +/app.*.js +/main.*.js diff --git a/utils/JDEnv.js b/utils/JDEnv.js new file mode 100755 index 0000000..194d5cc --- /dev/null +++ b/utils/JDEnv.js @@ -0,0 +1,321 @@ +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); +} +exports.env = env; diff --git a/utils/JDHelpers.js b/utils/JDHelpers.js new file mode 100755 index 0000000..ec0359c --- /dev/null +++ b/utils/JDHelpers.js @@ -0,0 +1,25 @@ +function safeGet(data) { + try { + if (typeof JSON.parse(data) == "object") { + return true; + } + } catch (e) { + console.log(e); + console.log(`京东服务器访问数据为空,请检查自身设备网络情况`); + return false; + } +} +function jsonParse(str) { + if (typeof str == "string") { + try { + return JSON.parse(str); + } catch (e) { + console.log(e); + $.msg($.name, '', '请勿随意在BoxJs输入框修改内容\n建议通过脚本去获取cookie') + return []; + } + } +} + +exports.safeGet = safeGet; +exports.jsonParse = jsonParse; \ No newline at end of file diff --git a/utils/JDJRValidator_Pure.js b/utils/JDJRValidator_Pure.js new file mode 100755 index 0000000..1511792 --- /dev/null +++ b/utils/JDJRValidator_Pure.js @@ -0,0 +1,579 @@ +const { + http, + https +} = require('follow-redirects'); +const stream = require('stream'); +const zlib = require('zlib'); +const vm = require('vm'); +const PNG = require('png-js'); +let UA = require('../USER_AGENTS.js').USER_AGENT; +const validatorCount = process.env.JDJR_validator_Count ? process.env.JDJR_validator_Count : 100 + +Math.avg = function average() { + var sum = 0; + var len = this.length; + for (var i = 0; i < len; i++) { + sum += this[i]; + } + return sum / len; +}; + +function sleep(timeout) { + return new Promise((resolve) => setTimeout(resolve, timeout)); +} + +class PNGDecoder extends PNG { + constructor(args) { + super(args); + this.pixels = []; + } + + decodeToPixels() { + return new Promise((resolve) => { + this.decode((pixels) => { + this.pixels = pixels; + resolve(); + }); + }); + } + + getImageData(x, y, w, h) { + const { + pixels + } = this; + const len = w * h * 4; + const startIndex = x * 4 + y * (w * 4); + + return { + data: pixels.slice(startIndex, startIndex + len) + }; + } +} + +const PUZZLE_GAP = 8; +const PUZZLE_PAD = 10; + +class PuzzleRecognizer { + constructor(bg, patch, y) { + // console.log(bg); + const imgBg = new PNGDecoder(Buffer.from(bg, 'base64')); + const imgPatch = new PNGDecoder(Buffer.from(patch, 'base64')); + + // console.log(imgBg); + + this.bg = imgBg; + this.patch = imgPatch; + this.rawBg = bg; + this.rawPatch = patch; + this.y = y; + this.w = imgBg.width; + this.h = imgBg.height; + } + + async run() { + await this.bg.decodeToPixels(); + await this.patch.decodeToPixels(); + + return this.recognize(); + } + + recognize() { + const { + ctx, + w: width, + bg + } = this; + const { + width: patchWidth, + height: patchHeight + } = this.patch; + const posY = this.y + PUZZLE_PAD + ((patchHeight - PUZZLE_PAD) / 2) - (PUZZLE_GAP / 2); + // const cData = ctx.getImageData(0, a.y + 10 + 20 - 4, 360, 8).data; + const cData = bg.getImageData(0, posY, width, PUZZLE_GAP).data; + const lumas = []; + + for (let x = 0; x < width; x++) { + var sum = 0; + + // y xais + for (let y = 0; y < PUZZLE_GAP; y++) { + var idx = x * 4 + y * (width * 4); + var r = cData[idx]; + var g = cData[idx + 1]; + var b = cData[idx + 2]; + var luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; + + sum += luma; + } + + lumas.push(sum / PUZZLE_GAP); + } + + const n = 2; // minium macroscopic image width (px) + const margin = patchWidth - PUZZLE_PAD; + const diff = 20; // macroscopic brightness difference + const radius = PUZZLE_PAD; + for (let i = 0, len = lumas.length - 2 * 4; i < len; i++) { + const left = (lumas[i] + lumas[i + 1]) / n; + const right = (lumas[i + 2] + lumas[i + 3]) / n; + const mi = margin + i; + const mLeft = (lumas[mi] + lumas[mi + 1]) / n; + const mRigth = (lumas[mi + 2] + lumas[mi + 3]) / n; + + if (left - right > diff && mLeft - mRigth < -diff) { + const pieces = lumas.slice(i + 2, margin + i + 2); + const median = pieces.sort((x1, x2) => x1 - x2)[20]; + const avg = Math.avg(pieces); + + // noise reducation + if (median > left || median > mRigth) return; + if (avg > 100) return; + // console.table({left,right,mLeft,mRigth,median}); + // ctx.fillRect(i+n-radius, 0, 1, 360); + // console.log(i+n-radius); + return i + n - radius; + } + } + + // not found + return -1; + } + + runWithCanvas() { + const { + createCanvas, + Image + } = require('canvas'); + const canvas = createCanvas(); + const ctx = canvas.getContext('2d'); + const imgBg = new Image(); + const imgPatch = new Image(); + const prefix = 'data:image/png;base64,'; + + imgBg.src = prefix + this.rawBg; + imgPatch.src = prefix + this.rawPatch; + const { + naturalWidth: w, + naturalHeight: h + } = imgBg; + canvas.width = w; + canvas.height = h; + ctx.clearRect(0, 0, w, h); + ctx.drawImage(imgBg, 0, 0, w, h); + + const width = w; + const { + naturalWidth, + naturalHeight + } = imgPatch; + const posY = this.y + PUZZLE_PAD + ((naturalHeight - PUZZLE_PAD) / 2) - (PUZZLE_GAP / 2); + // const cData = ctx.getImageData(0, a.y + 10 + 20 - 4, 360, 8).data; + const cData = ctx.getImageData(0, posY, width, PUZZLE_GAP).data; + const lumas = []; + + for (let x = 0; x < width; x++) { + var sum = 0; + + // y xais + for (let y = 0; y < PUZZLE_GAP; y++) { + var idx = x * 4 + y * (width * 4); + var r = cData[idx]; + var g = cData[idx + 1]; + var b = cData[idx + 2]; + var luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; + + sum += luma; + } + + lumas.push(sum / PUZZLE_GAP); + } + + const n = 2; // minium macroscopic image width (px) + const margin = naturalWidth - PUZZLE_PAD; + const diff = 20; // macroscopic brightness difference + const radius = PUZZLE_PAD; + for (let i = 0, len = lumas.length - 2 * 4; i < len; i++) { + const left = (lumas[i] + lumas[i + 1]) / n; + const right = (lumas[i + 2] + lumas[i + 3]) / n; + const mi = margin + i; + const mLeft = (lumas[mi] + lumas[mi + 1]) / n; + const mRigth = (lumas[mi + 2] + lumas[mi + 3]) / n; + + if (left - right > diff && mLeft - mRigth < -diff) { + const pieces = lumas.slice(i + 2, margin + i + 2); + const median = pieces.sort((x1, x2) => x1 - x2)[20]; + const avg = Math.avg(pieces); + + // noise reducation + if (median > left || median > mRigth) return; + if (avg > 100) return; + // console.table({left,right,mLeft,mRigth,median}); + // ctx.fillRect(i+n-radius, 0, 1, 360); + // console.log(i+n-radius); + return i + n - radius; + } + } + + // not found + return -1; + } +} + +const DATA = { + "appId": "17839d5db83", + "product": "embed", + "lang": "zh_CN", +}; +const SERVER = 'iv.jd.com'; + +class JDJRValidator { + constructor() { + this.data = {}; + this.x = 0; + this.t = Date.now(); + this.count = 0; + } + + async run(scene = 'cww', eid = '') { + const tryRecognize = async () => { + const x = await this.recognize(scene, eid); + + if (x > 0) { + return x; + } + // retry + return await tryRecognize(); + }; + const puzzleX = await tryRecognize(); + // console.log(puzzleX); + const pos = new MousePosFaker(puzzleX).run(); + const d = getCoordinate(pos); + + // console.log(pos[pos.length-1][2] -Date.now()); + // await sleep(4500); + await sleep(pos[pos.length - 1][2] - Date.now()); + this.count++; + const result = await JDJRValidator.jsonp('/slide/s.html', { + d, + ...this.data + }, scene); + + if (result.message === 'success') { + // console.log(result); + console.log('JDJR验证用时: %fs', (Date.now() - this.t) / 1000); + return result; + } else { + console.log(`验证失败: ${this.count}/${validatorCount}`); + // console.log(JSON.stringify(result)); + if (this.count >= validatorCount) { + console.log("JDJR验证次数已达上限,退出验证"); + return result; + } else { + await sleep(300); + return await this.run(scene, eid); + } + } + } + + async recognize(scene, eid) { + const data = await JDJRValidator.jsonp('/slide/g.html', { + e: eid + }, scene); + const { + bg, + patch, + y + } = data; + // const uri = 'data:image/png;base64,'; + // const re = new PuzzleRecognizer(uri+bg, uri+patch, y); + const re = new PuzzleRecognizer(bg, patch, y); + // console.log(JSON.stringify(re)) + const puzzleX = await re.run(); + + if (puzzleX > 0) { + this.data = { + c: data.challenge, + w: re.w, + e: eid, + s: '', + o: '', + }; + this.x = puzzleX; + } + return puzzleX; + } + + async report(n) { + console.time('PuzzleRecognizer'); + let count = 0; + + for (let i = 0; i < n; i++) { + const x = await this.recognize(); + + if (x > 0) count++; + if (i % 50 === 0) { + // console.log('%f\%', (i / n) * 100); + } + } + + console.log('验证成功: %f\%', (count / n) * 100); + console.clear() + console.timeEnd('PuzzleRecognizer'); + } + + static jsonp(api, data = {}, scene) { + return new Promise((resolve, reject) => { + const fnId = `jsonp_${String(Math.random()).replace('.', '')}`; + const extraData = { + callback: fnId + }; + const query = new URLSearchParams({ + ...DATA, + ...{ + "scene": scene + }, + ...extraData, + ...data + }).toString(); + const url = `https://${SERVER}${api}?${query}`; + const headers = { + 'Accept': '*/*', + 'Accept-Encoding': 'gzip,deflate,br', + 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'Connection': 'keep-alive', + 'Host': "iv.jd.com", + 'Proxy-Connection': 'keep-alive', + 'Referer': 'https://h5.m.jd.com/', + 'User-Agent': UA, + }; + + const req = https.get(url, { + headers + }, (response) => { + let res = response; + if (res.headers['content-encoding'] === 'gzip') { + const unzipStream = new stream.PassThrough(); + stream.pipeline( + response, + zlib.createGunzip(), + unzipStream, + reject, + ); + res = unzipStream; + } + res.setEncoding('utf8'); + + let rawData = ''; + + res.on('data', (chunk) => rawData += chunk); + res.on('end', () => { + try { + const ctx = { + [fnId]: (data) => ctx.data = data, + data: {}, + }; + + vm.createContext(ctx); + vm.runInContext(rawData, ctx); + + // console.log(ctx.data); + res.resume(); + resolve(ctx.data); + } catch (e) { + reject(e); + } + }); + }); + + req.on('error', reject); + req.end(); + }); + } +} + +function getCoordinate(c) { + function string10to64(d) { + var c = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-~".split(""), + b = c.length, + e = +d, + a = []; + do { + mod = e % b; + e = (e - mod) / b; + a.unshift(c[mod]) + } while (e); + return a.join("") + } + + function prefixInteger(a, b) { + return (Array(b).join(0) + a).slice(-b) + } + + function pretreatment(d, c, b) { + var e = string10to64(Math.abs(d)); + var a = ""; + if (!b) { + a += (d > 0 ? "1" : "0") + } + a += prefixInteger(e, c); + return a + } + + var b = new Array(); + for (var e = 0; e < c.length; e++) { + if (e == 0) { + b.push(pretreatment(c[e][0] < 262143 ? c[e][0] : 262143, 3, true)); + b.push(pretreatment(c[e][1] < 16777215 ? c[e][1] : 16777215, 4, true)); + b.push(pretreatment(c[e][2] < 4398046511103 ? c[e][2] : 4398046511103, 7, true)) + } else { + var a = c[e][0] - c[e - 1][0]; + var f = c[e][1] - c[e - 1][1]; + var d = c[e][2] - c[e - 1][2]; + b.push(pretreatment(a < 4095 ? a : 4095, 2, false)); + b.push(pretreatment(f < 4095 ? f : 4095, 2, false)); + b.push(pretreatment(d < 16777215 ? d : 16777215, 4, true)) + } + } + return b.join("") +} + +const HZ = 20; + +class MousePosFaker { + constructor(puzzleX) { + this.x = parseInt(Math.random() * 20 + 20, 10); + this.y = parseInt(Math.random() * 80 + 80, 10); + this.t = Date.now(); + this.pos = [ + [this.x, this.y, this.t] + ]; + this.minDuration = parseInt(1000 / HZ, 10); + // this.puzzleX = puzzleX; + this.puzzleX = puzzleX + parseInt(Math.random() * 2 - 1, 10); + + this.STEP = parseInt(Math.random() * 6 + 5, 10); + this.DURATION = parseInt(Math.random() * 7 + 14, 10) * 100; + // [9,1600] [10,1400] + this.STEP = 9; + // this.DURATION = 2000; + // console.log(this.STEP, this.DURATION); + } + + run() { + const perX = this.puzzleX / this.STEP; + const perDuration = this.DURATION / this.STEP; + const firstPos = [this.x - parseInt(Math.random() * 6, 10), this.y + parseInt(Math.random() * 11, 10), this.t]; + + this.pos.unshift(firstPos); + this.stepPos(perX, perDuration); + this.fixPos(); + + const reactTime = parseInt(60 + Math.random() * 100, 10); + const lastIdx = this.pos.length - 1; + const lastPos = [this.pos[lastIdx][0], this.pos[lastIdx][1], this.pos[lastIdx][2] + reactTime]; + + this.pos.push(lastPos); + return this.pos; + } + + stepPos(x, duration) { + let n = 0; + const sqrt2 = Math.sqrt(2); + for (let i = 1; i <= this.STEP; i++) { + n += 1 / i; + } + for (let i = 0; i < this.STEP; i++) { + x = this.puzzleX / (n * (i + 1)); + const currX = parseInt((Math.random() * 30 - 15) + x, 10); + const currY = parseInt(Math.random() * 7 - 3, 10); + const currDuration = parseInt((Math.random() * 0.4 + 0.8) * duration, 10); + + this.moveToAndCollect({ + x: currX, + y: currY, + duration: currDuration, + }); + } + } + + fixPos() { + const actualX = this.pos[this.pos.length - 1][0] - this.pos[1][0]; + const deviation = this.puzzleX - actualX; + + if (Math.abs(deviation) > 4) { + this.moveToAndCollect({ + x: deviation, + y: parseInt(Math.random() * 8 - 3, 10), + duration: 250, + }); + } + } + + moveToAndCollect({ + x, + y, + duration + }) { + let movedX = 0; + let movedY = 0; + let movedT = 0; + const times = duration / this.minDuration; + let perX = x / times; + let perY = y / times; + let padDuration = 0; + + if (Math.abs(perX) < 1) { + padDuration = duration / Math.abs(x) - this.minDuration; + perX = 1; + perY = y / Math.abs(x); + } + + while (Math.abs(movedX) < Math.abs(x)) { + const rDuration = parseInt(padDuration + Math.random() * 16 - 4, 10); + + movedX += perX + Math.random() * 2 - 1; + movedY += perY; + movedT += this.minDuration + rDuration; + + const currX = parseInt(this.x + movedX, 10); + const currY = parseInt(this.y + movedY, 10); + const currT = this.t + movedT; + + this.pos.push([currX, currY, currT]); + } + + this.x += x; + this.y += y; + this.t += Math.max(duration, movedT); + } +} + +function injectToRequest(fn, scene = 'cww', ua = '') { + if (ua) UA = ua + return (opts, cb) => { + fn(opts, async (err, resp, data) => { + if (err) { + console.error(JSON.stringify(err)); + return; + } + if (data.search('验证') > -1) { + console.log('JDJR验证中......'); + let arr = opts.url.split("&") + let eid = '' + for (let i of arr) { + if (i.indexOf("eid=") > -1) { + eid = i.split("=") && i.split("=")[1] || '' + } + } + const res = await new JDJRValidator().run(scene, eid); + + opts.url += `&validate=${res.validate}`; + fn(opts, cb); + } else { + cb(err, resp, data); + } + }); + }; +} + +exports.injectToRequest = injectToRequest; \ No newline at end of file diff --git a/utils/JDShoppingCart.js b/utils/JDShoppingCart.js new file mode 100755 index 0000000..131f21e --- /dev/null +++ b/utils/JDShoppingCart.js @@ -0,0 +1,184 @@ +function unsubscribeCartsFun() { + return new Promise((resolve) => { + const options = { + url: `https://wq.jd.com/deal/mshopcart/rmvCmdy?sceneval=2&g_login_type=1&g_ty=ajax`, + body: `pingouchannel=0&commlist=${$.commlist}&type=0&checked=0&locationid=${$.areaId}&templete=1®=1&scene=0&version=20190418&traceid=${$.traceId}&tabMenuType=1&sceneval=2`, + headers: { + Accept: "application/json,text/plain, */*", + "Content-Type": "application/x-www-form-urlencoded", + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "zh-cn", + Connection: "keep-alive", + Cookie: cookie, + Referer: "https://p.m.jd.com/", + "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", + }, + }; + $.post(options, (err, resp, data) => { + try { + data = JSON.parse(data); + if (data["errId"] == "0") { + allMessage += `清空结果:\n`; + } else { + allMessage += `清空结果:\n`; + } + } catch (e) { + allMessage += `清空结果:\n`; + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + }); +} + +function getStr(text, start, end) { + var str = text; + var aPos = str.indexOf(start); + if (aPos < 0) { + return null; + } + var bPos = str.indexOf(end, aPos + start.length); + if (bPos < 0) { + return null; + } + var retstr = str.substr(aPos + start.length, text.length - (aPos + start.length) - (text.length - bPos)); + return retstr; +} +function getCarts() { + $.shopsTotalNum = 0; + return new Promise((resolve) => { + const option = { + url: `https://p.m.jd.com/cart/cart.action`, + headers: { + Host: "p.m.jd.com", + Accept: "*/*", + Connection: "keep-alive", + Cookie: cookie, + "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", + "Accept-Language": "zh-cn", + "Accept-Encoding": "gzip, deflate, br", + }, + }; + $.get(option, (err, resp, data) => { + try { + data = JSON.parse(getStr(data, "window.cartData =", "window._PFM_TIMING")); + $.cartsTotalNum = 0; + if (data.errId === "0") { + $.traceId = data["traceId"]; + $.areaId = data["areaId"]; + let itemId, sKuId, index, temp; + $.commlist = ""; + for (let i = 0; i < data["cart"]["venderCart"].length; i++) { + const vender = data["cart"]["venderCart"][i]; + for (let s = 0; s < vender["sortedItems"].length; s++) { + const sorted = vender["sortedItems"][s]; + itemId = sorted["itemId"]; + for (let m = 0; m < sorted["polyItem"]["products"].length; m++) { + const products = sorted["polyItem"]["products"][m]; + if (itemId == products["mainSku"]["id"]) { + sKuId = ""; + index = "1"; + } else { + sKuId = itemId; + index = sorted["polyType"] == "4" ? "13" : "11"; + } + temp = [products["mainSku"]["id"], , "1", products["mainSku"]["id"], index, sKuId, "0", "skuUuid:" + products["skuUuid"] + "@@useUuid:" + products["useUuid"]].join(","); + if ($.commlist.length > 0) { + $.commlist += "$"; + } + $.commlist += temp; + $.cartsTotalNum += 1; + } + } + } + if ($.commlist.length > 0) { + $.commlist = encodeURIComponent($.commlist); + } + console.log(`当前购物车商品数:${$.cartsTotalNum}个\n`); + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + }); +} + +function TotalBean() { + return new Promise(async (resolve) => { + const options = { + url: `https://wq.jd.com/user/info/QueryJDUserInfo?sceneval=2`, + headers: { + Accept: "application/json,text/plain, */*", + "Content-Type": "application/x-www-form-urlencoded", + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "zh-cn", + Connection: "keep-alive", + Cookie: cookie, + Referer: "https://wqs.jd.com/my/jingdou/my.shtml?sceneval=2", + "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", + }, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log(`${JSON.stringify(err)}`); + console.log(`${$.name} API请求失败,请检查网路重试`); + } else { + if (data) { + data = JSON.parse(data); + if (data["retcode"] === 13) { + $.isLogin = false; //cookie过期 + return; + } + if (data["retcode"] === 0) { + $.nickName = (data["base"] && data["base"].nickname) || $.UserName; + } else { + $.nickName = $.UserName; + } + } else { + console.log(`京东服务器返回空数据`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(); + } + }); + }); +} +function jsonParse(str) { + if (typeof str == "string") { + try { + return JSON.parse(str); + } catch (e) { + console.log(e); + $.msg($.name, "", "请勿随意在BoxJs输入框修改内容\n建议通过脚本去获取cookie"); + return []; + } + } +} + +exports.getCarts = getCarts; +exports.unsubscribeCartsFun = unsubscribeCartsFun; diff --git a/utils/MovementFaker.js b/utils/MovementFaker.js new file mode 100755 index 0000000..ba0e915 --- /dev/null +++ b/utils/MovementFaker.js @@ -0,0 +1,139 @@ +const https = require('https'); +const fs = require('fs').promises; +const { R_OK } = require('fs').constants; +const vm = require('vm'); +const UA = require('../USER_AGENTS.js').USER_AGENT; + +const URL = 'https://wbbny.m.jd.com/babelDiy/Zeus/2rtpffK8wqNyPBH6wyUDuBKoAbCt/index.html'; +// const REG_MODULE = /(\d+)\:function\(.*(?=smashUtils\.get_risk_result)/gm; +const SYNTAX_MODULE = '!function(n){var r={};function o(e){if(r[e])'; +const REG_SCRIPT = /