├── README.md ├── jdCookie.js ├── jd_angryKoi_windfgg.py ├── jd_cash_windfgg.js ├── jd_gua_cleancart_windfgg.js ├── jd_insight_windfgg.js ├── jd_red_statistics_windfgg.py ├── jd_wskey_windfgg.py ├── shareCode └── test.json └── utils ├── TS_USER_AGENTS.ts ├── USER_AGENTS.js ├── ql.js ├── sendNotify.js └── sendNotify.py /README.md: -------------------------------------------------------------------------------- 1 | # YunFeng_Repo 2 | ## TG 3 | Channel https://t.me/wind_fgg 4 | 5 | Group https://t.me/windfgg_chart 6 | 7 | Bot https://t.me/FengYun7_bot 8 | ### 环境变量 9 | ``` shell 10 | ## windfgg 接口 11 | export WindfggToken='' 12 | export WindfggHost='api.windfgg.cf' 13 | 14 | ## 锦鲤 15 | export Proxy_Url='' 16 | export WindfggJinliToken='' 17 | export JinLinHost='20.24.232.57' 18 | ``` 19 | ### 拉库命令 20 | 国外 21 | ```shell 22 | ql repo https://github.com/FengYun27/YunFeng_Repo.git "jd_|jx_|jr_|jds_|jdCookie|ql|USER" "" "utils|sendNotify|USER|ql|jdCookie" 23 | 24 | 30 0/15 * * * ? 25 | ``` 26 | 27 | 国内 28 | 29 | ```shell 30 | ql repo https://hub.fastgit.xyz/FengYun27/YunFeng_Repo.git "jd_|jx_|jr_|jds_|jdCookie|ql|USER" "" "utils|sendNotify|USER|ql|jdCookie" 31 | 32 | 30 0/15 * * * ? 33 | ``` 34 | 35 | ### NodeJs 36 | ``` 37 | axios 38 | jsdom 39 | ts-md5 40 | moment 41 | png-js 42 | date-fns 43 | ``` 44 | ### Python 45 | ``` 46 | json5 47 | requests 48 | pycryptodomex 49 | ``` 50 | 51 | # Special statement 52 | * Any unlocking and decryption analysis scripts involved in the Script project released by this warehouse are only used for testing, learning and research, and are forbidden to be used for commercial purposes. Their legality, accuracy, completeness and effectiveness cannot be guaranteed. Please make your own judgment based on the situation. . 53 | 54 | * All resource files in this project are forbidden to be reproduced or published in any form by any official account or self-media. 55 | 56 | * This warehouse is not responsible for any script problems, including but not limited to any loss or damage caused by any script errors. 57 | 58 | * Any user who indirectly uses the script, including but not limited to establishing a VPS or disseminating it when certain actions violate national/regional laws or related regulations, this warehouse is not responsible for any privacy leakage or other consequences caused by this. 59 | 60 | * Do not use any content of the Script project for commercial or illegal purposes, otherwise you will be responsible for the consequences. 61 | 62 | * If any unit or individual believes that the script of the project may be suspected of infringing on their rights, they should promptly notify and provide proof of identity and ownership. We will delete the relevant script after receiving the certification document. 63 | 64 | * Anyone who views this item in any way or directly or indirectly uses any script of the Script item should read this statement carefully. This warehouse reserves the right to change or supplement this disclaimer at any time. Once you have used and copied any relevant scripts or rules of the Script project, you are deemed to have accepted this disclaimer. 65 | 66 | **You must completely delete the above content from your computer or mobile phone within 24 hours after downloading.**
67 | > ***You have used or copied any script made by yourself in this warehouse, it is deemed to have accepted this statement, please read it carefully*** 68 | -------------------------------------------------------------------------------- /jdCookie.js: -------------------------------------------------------------------------------- 1 | /* 2 | ================================================================================ 3 | 魔改自 https://github.com/shufflewzc/faker2/blob/main/jdCookie.js 4 | 修改内容:与task_before.sh配合,由task_before.sh设置要设置要做互助的活动的 ShareCodeConfigName 和 ShareCodeEnvName 环境变量, 5 | 然后在这里实际解析/ql/log/.ShareCode中该活动对应的配置信息(由code.sh生成和维护),注入到nodejs的环境变量中 6 | 修改原因:原先的task_before.sh直接将互助信息注入到shell的env中,在ck超过45以上时,互助码环境变量过大会导致调用一些系统命令 7 | (如date/cat)时报 Argument list too long,而在node中修改环境变量不会受这个限制,也不会影响外部shell环境,确保脚本可以正常运行 8 | 魔改作者:风之凌殇 9 | ================================================================================ 10 | 11 | 此文件为Node.js专用。其他用户请忽略 12 | */ 13 | //此处填写京东账号cookie。 14 | let CookieJDs = [ 15 | ] 16 | // 判断环境变量里面是否有京东ck 17 | if (process.env.JD_COOKIE) { 18 | if (process.env.JD_COOKIE.indexOf('&') > -1) { 19 | CookieJDs = process.env.JD_COOKIE.split('&'); 20 | } else if (process.env.JD_COOKIE.indexOf('\n') > -1) { 21 | CookieJDs = process.env.JD_COOKIE.split('\n'); 22 | } else { 23 | CookieJDs = [process.env.JD_COOKIE]; 24 | } 25 | } 26 | if (JSON.stringify(process.env).indexOf('GITHUB') > -1) { 27 | console.log(`请勿使用github action运行此脚本,无论你是从你自己的私库还是其他哪里拉取的源代码,都会导致我被封号\n`); 28 | !(async () => { 29 | await require('./sendNotify').sendNotify('提醒', `请勿使用github action、滥用github资源会封我仓库以及账号`) 30 | await process.exit(0); 31 | })() 32 | } 33 | CookieJDs = [...new Set(CookieJDs.filter(item => !!item))] 34 | console.log(`\n====================共${CookieJDs.length}个京东账号Cookie=========\n`); 35 | console.log(`==================脚本执行- 北京时间(UTC+8):${new Date(new Date().getTime() + new Date().getTimezoneOffset() * 60 * 1000 + 8 * 60 * 60 * 1000).toLocaleString('zh', { hour12: false }).replace(' 24:', ' 00:')}=====================\n`) 36 | if (process.env.JD_DEBUG && process.env.JD_DEBUG === 'false') console.log = () => { }; 37 | for (let i = 0; i < CookieJDs.length; i++) { 38 | if (!CookieJDs[i].match(/pt_pin=(.+?);/) || !CookieJDs[i].match(/pt_key=(.+?);/)) console.log(`\n提示:京东cookie 【${CookieJDs[i]}】填写不规范,可能会影响部分脚本正常使用。正确格式为: pt_key=xxx;pt_pin=xxx;(分号;不可少)\n`); 39 | const index = (i + 1 === 1) ? '' : (i + 1); 40 | exports['CookieJD' + index] = CookieJDs[i].trim(); 41 | } 42 | 43 | // 以下为注入互助码环境变量(仅nodejs内起效)的代码 44 | function SetShareCodesEnv (nameConfig = "", envName = "") { 45 | let rawCodeConfig = {} 46 | 47 | // 读取互助码 48 | shareCodeLogPath = `${process.env.QL_DIR}/log/.ShareCode/${nameConfig}.log` 49 | let fs = require('fs') 50 | if (fs.existsSync(shareCodeLogPath)) { 51 | // 因为faker2目前没有自带ini,改用已有的dotenv来解析 52 | // // 利用ini模块读取原始互助码和互助组信息 53 | // let ini = require('ini') 54 | // rawCodeConfig = ini.parse(fs.readFileSync(shareCodeLogPath, 'utf-8')) 55 | 56 | // 使用env模块 57 | require('dotenv').config({ path: shareCodeLogPath }) 58 | rawCodeConfig = process.env 59 | } 60 | 61 | // 解析每个用户的互助码 62 | codes = {} 63 | Object.keys(rawCodeConfig).forEach(function (key) { 64 | if (key.startsWith(`My${nameConfig}`)) { 65 | codes[key] = rawCodeConfig[key] 66 | } 67 | }); 68 | 69 | // 解析每个用户要帮助的互助码组,将用户实际的互助码填充进去 70 | let helpOtherCodes = {} 71 | Object.keys(rawCodeConfig).forEach(function (key) { 72 | if (key.startsWith(`ForOther${nameConfig}`)) { 73 | helpCode = rawCodeConfig[key] 74 | for (const [codeEnv, codeVal] of Object.entries(codes)) { 75 | helpCode = helpCode.replace("${" + codeEnv + "}", codeVal) 76 | } 77 | 78 | helpOtherCodes[key] = helpCode 79 | } 80 | }); 81 | 82 | // 按顺序用&拼凑到一起,并放入环境变量,供目标脚本使用 83 | let shareCodes = [] 84 | let totalCodeCount = Object.keys(helpOtherCodes).length 85 | for (let idx = 1; idx <= totalCodeCount; idx++) { 86 | shareCodes.push(helpOtherCodes[`ForOther${nameConfig}${idx}`]) 87 | } 88 | let shareCodesStr = shareCodes.join('&') 89 | process.env[envName] = shareCodesStr 90 | 91 | console.info(`【风之凌殇】 友情提示:为避免ck超过45以上时,互助码环境变量过大而导致调用一些系统命令(如date/cat)时报 Argument list too long,改为在nodejs中设置 ${nameConfig} 的 互助码环境变量 ${envName},共计 ${totalCodeCount} 组互助码,总大小为 ${shareCodesStr.length}`) 92 | } 93 | 94 | // 若在task_before.sh 中设置了要设置互助码环境变量的活动名称和环境变量名称信息,则在nodejs中处理,供活动使用 95 | let nameConfig = process.env.ShareCodeConfigName 96 | let envName = process.env.ShareCodeEnvName 97 | if (nameConfig && envName) { 98 | SetShareCodesEnv(nameConfig, envName) 99 | } else { 100 | console.debug(`FengYun7 友情提示:您的脚本正常运行中`) 101 | } -------------------------------------------------------------------------------- /jd_angryKoi_windfgg.py: -------------------------------------------------------------------------------- 1 | ''' 2 | cron: 5 0 * * * 3 | new Env('安静的锦鲤'); 4 | Version=20220617 5 | by Mad Rabbit 6 | log windfgg 7 | 8 | 入口: 京东首页>领券>锦鲤红包 9 | 变量: JD_COOKIE,kois,WindfggJinliToken,Proxy_Url 10 | export Proxy_Url='代理网址 推荐星空 生成选择txt 一次一个' 11 | export WindfggJinliToken="windfgg 锦鲤 token" 12 | export JD_COOKIE="第1个cookie&第2个cookie" 13 | export kois=" 第1个cookie的pin & 第2个cookie的pin " 14 | 环境变量kois中填入需要助力的pt_pin,有多个请用 '@'或'&'或空格 符号连接,不填默认全部账号内部随机助力 15 | 脚本内或环境变量填写,优先环境变量 16 | ''' 17 | import os 18 | import re 19 | import json 20 | import time 21 | import logging 22 | import requests 23 | import os.path 24 | 25 | if "LOG_DEBUG" in os.environ: # 判断调试模式变量 26 | logging.basicConfig(level=logging.DEBUG, format='%(message)s') # 设置日志为 Debug等级输出 27 | logger = logging.getLogger(__name__) # 主模块 28 | logger.debug("\nDEBUG模式开启!\n") # 消息输出 29 | else: # 判断分支 30 | logging.basicConfig(level=logging.INFO, format='%(message)s') # Info级日志 31 | logger = logging.getLogger(__name__) # 主模块 32 | 33 | requests.packages.urllib3.disable_warnings() 34 | 35 | sceneid = 'JLHBhPageh5' 36 | startLog=0 37 | endLog=0 38 | #获取log 39 | def get_log(functionId,pin): 40 | windfgg_token= os.environ.get("WindfggJinliToken", '') 41 | JinLinHost= os.environ.get("JinLinHost", 'api1.windfgg.cf') 42 | windfgg_url = f"http://{JinLinHost}/jd/jinli?pin={pin}&token={windfgg_token}" 43 | for i in range(5): 44 | try: 45 | res = requests.post(windfgg_url,timeout=20,verify=False) 46 | res = res.json() 47 | if not res["data"]["log"]: 48 | logger.info("获取log失败: ", res["msg"]) 49 | continue 50 | resp = res['data'] 51 | times=res['msg'] 52 | logger.info(f'log剩余次数:{times}次') 53 | return resp["log"], resp["random"], resp["ck"], res['msg'] 54 | except Exception as e: 55 | logger.info(f"获取log出错 等待十秒 {res}") 56 | time.sleep(10) 57 | count=i+1; 58 | logger.info(f"第{count}次重试") 59 | else: 60 | logger.info("5次重试失败,退出程序") 61 | exit() 62 | 63 | #获取代理 64 | def get_proxy(url): 65 | payload={} 66 | headers = {} 67 | for n in range(3): 68 | try: 69 | response = requests.request("GET", url, headers=headers, data=payload,verify=False) 70 | sss=response.text 71 | proxies = { 72 | "http": f"http://{sss}", 73 | 'https': f'http://{sss}' 74 | } 75 | res = requests.get('https://www.baidu.com', proxies=proxies, timeout=10,verify=False) 76 | if res.status_code == 200: 77 | return proxies,sss 78 | except Exception as e: 79 | logger.info(f"代理超时或错误 重新获取") 80 | logger.info(f"第{n}次重试") 81 | 82 | #请求 83 | def taskPostUrl(functionId, body, cookie): 84 | global startLog 85 | global endLog 86 | pt_pin=get_pin(cookie) 87 | pt_key=get_key(cookie) 88 | proxy_url=os.environ.get("Proxy_Url", '') 89 | proxies,sss=get_proxy(proxy_url) 90 | log, randoms, ck, msg = get_log(functionId,pt_pin) 91 | body.update({"log": log, "random": randoms}) 92 | logger.info(f'[{pt_pin}] {functionId} 使用代理:'+sss) 93 | if startLog==0: 94 | startLog=msg 95 | logger.info("Log剩余次数:"+str(msg)) 96 | endLog = msg 97 | cookie=f'pt_pin={pt_pin};pt_key={pt_key};' 98 | url = f'https://api.m.jd.com/api?appid=jinlihongbao&functionId={functionId}&loginType=2&client=jinlihongbao&t={gettimestamp()}&clientVersion=10.1.4&osVersion=-1' 99 | headers = { 100 | 'Cookie': cookie, 101 | 'Host': 'api.m.jd.com', 102 | 'Connection': 'keep-alive', 103 | 'origin': 'https://happy.m.jd.com', 104 | 'referer': 'https://happy.m.jd.com/babelDiy/zjyw/3ugedFa7yA6NhxLN5gw2L3PF9sQC/index.html?channel=9&un_area=4_134_19915_0', 105 | 'Content-Type': 'application/x-www-form-urlencoded', 106 | "User-Agent": 'jdapp;android;10.5.4;;;appBuild/96906;ef/1;ep/%7B%22hdid%22%3A%22JM9F1ywUPwflvMIpYPok0tt5k9kW4ArJEU3lfLhxBqw%3D%22%2C%22ts%22%3A1654650382027%2C%22ridx%22%3A-1%2C%22cipher%22%3A%7B%22sv%22%3A%22EG%3D%3D%22%2C%22ad%22%3A%22CzDuCQGzZNOnEJc5DNS4Dq%3D%3D%22%2C%22od%22%3A%22%22%2C%22ov%22%3A%22Ctq%3D%22%2C%22ud%22%3A%22CzDuCQGzZNOnEJc5DNS4Dq%3D%3D%22%7D%2C%22ciphertype%22%3A5%2C%22version%22%3A%221.2.0%22%2C%22appname%22%3A%22com.jingdong.app.mall%22%7D;jdSupportDarkMode/0;Mozilla/5.0 (Linux; Android 9; SM-G977N Build/LMY48Z; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.0.4389.72 MQQBrowser/6.2 TBS/046010 Mobile Safari/537.36', 107 | 'Accept-Language': 'zh-cn', 108 | 'Accept-Encoding': 'gzip, deflate, br', 109 | } 110 | data = f"body={json.dumps(body)}" 111 | for n in range(3): 112 | try: 113 | res = requests.post(url, headers=headers, proxies=proxies,data=data,verify=False).text 114 | return res 115 | except Exception as e: 116 | if n == 2: 117 | logger.info('API请求失败,请检查网路重试❗\n') 118 | 119 | # 13位时间戳 120 | def gettimestamp(): 121 | return str(int(time.time() * 1000)) 122 | 123 | # 获取pin key 124 | cookie_findall = re.compile(r'pt_pin=(.+?);') 125 | cookie_findall_key = re.compile(r'pt_key=(.+?);') 126 | def get_pin(cookie): 127 | try: 128 | return cookie_findall.findall(cookie)[0] 129 | except: 130 | logger.info('ck格式不正确,请检查') 131 | def get_key(cookie): 132 | try: 133 | return cookie_findall_key.findall(cookie)[0] 134 | except: 135 | logger.info('ck格式不正确,请检查') 136 | 137 | # 开启助力 138 | code_findall = re.compile(r'"code":(.*?),') 139 | def h5launch(cookie): 140 | body = {"followShop": 1, "sceneid": sceneid} 141 | res = taskPostUrl("h5launch",body, cookie) 142 | if not res: 143 | return 144 | Code = code_findall.findall(res) 145 | if Code: 146 | if str(Code[0]) == '0': 147 | logger.info(f"账号 {get_pin(cookie)} 开启助力码成功\n") 148 | else: 149 | logger.info(f"账号 {get_pin(cookie)} 开启助力码失败") 150 | logger.info(res) 151 | else: 152 | logger.info(f"账号 {get_pin(cookie)} 开启助力码失败") 153 | exit() 154 | 155 | # 获取助力码 156 | id_findall = re.compile(r'","id":(.+?),"') 157 | def h5activityIndex(cookie): 158 | h5launch(cookie) 159 | global inviteCode_list 160 | body = {"isjdapp": 1} 161 | res = taskPostUrl("h5activityIndex",body, cookie) 162 | if not res: 163 | return 164 | inviteCode = id_findall.findall(res) 165 | if inviteCode: 166 | inviteCode = inviteCode[0] 167 | # inviteCode_list.append(inviteCode) 168 | logger.info(f"账号 {get_pin(cookie)} 的锦鲤红包助力码为 {inviteCode}\n") 169 | return inviteCode 170 | else: 171 | logger.info(f"账号 {get_pin(cookie)} 获取助力码失败\n") 172 | exit() 173 | 174 | # 助力 175 | statusDesc_findall = re.compile(r',"statusDesc":"(.+?)"') 176 | def jinli_h5assist(cookie, redPacketId): 177 | body = {"redPacketId": redPacketId, "followShop": 0, "sceneid": sceneid} 178 | res = taskPostUrl('jinli_h5assist',body, cookie) 179 | logger.info(f'账号 {get_pin(cookie)} 去助力{redPacketId}') 180 | if not res: 181 | return 182 | statusDesc = statusDesc_findall.findall(res) 183 | if statusDesc: 184 | statusDesc = statusDesc[0] 185 | logger.info(f"{statusDesc}\n") 186 | if "TA的助力已满" in statusDesc: 187 | return True 188 | else: 189 | logger.info(f"错误\n{res}\n") 190 | 191 | # 开红包 192 | biz_msg_findall = re.compile(r'"biz_msg":"(.*?)"') 193 | discount_findall = re.compile(r'"discount":"(.*?)"') 194 | def h5receiveRedpacketAll(cookie): 195 | body = {"sceneid": sceneid} 196 | res = taskPostUrl("h5receiveRedpacketAll", body, cookie) 197 | logger.info(f'账号 {get_pin(cookie)} 开红包') 198 | if not res: 199 | return 200 | try: 201 | biz_msg = biz_msg_findall.findall(res)[0] 202 | except: 203 | logger.info(res) 204 | return 205 | discount = discount_findall.findall(res) 206 | if discount: 207 | discount = discount[0] 208 | logger.info(f"恭喜您,获得红包 {discount}\n") 209 | return h5receiveRedpacketAll(cookie) 210 | else: 211 | logger.info(f"{biz_msg}\n") 212 | 213 | # 读取环境变量 214 | def get_env(env): 215 | try: 216 | if env in os.environ: 217 | a = os.environ[env] 218 | else: 219 | a = "" 220 | except: 221 | a = '' 222 | return a 223 | 224 | def main(): 225 | logger.info('🔔安静的锦鲤,开始!\n') 226 | windfgg_token= os.environ.get("WindfggJinliToken", '') 227 | if not windfgg_token: 228 | logger.info("未配置WindfggJinliToken") 229 | exit() 230 | proxy_url=os.environ.get("Proxy_Url", '') 231 | if not proxy_url: 232 | logger.info("未配置Proxy_Url") 233 | exit() 234 | logger.info(f'WindfggJinliToken: {windfgg_token}') 235 | logger.info(f'Proxy_Url: \n{proxy_url}') 236 | try: 237 | cookie_list = os.environ["JD_COOKIE"].split("&") 238 | except: 239 | with open('cklist.txt', 'r') as f: 240 | cookie_list = f.read().split('\n') 241 | logger.info(f"共:{len(cookie_list)}个CK") 242 | if not cookie_list: 243 | logger.info("没有找到ck") 244 | exit() 245 | logger.info(f'====================共{len(cookie_list)}京东个账号Cookie=========\n') 246 | 247 | debug_pin = get_env('kois') 248 | if debug_pin: 249 | cookie_list_pin = [cookie for cookie in cookie_list if get_pin(cookie) in debug_pin] 250 | else: 251 | cookie_list_pin = cookie_list 252 | logger.info('*******************助力*******************\n') 253 | index = 0 254 | 255 | inviteCode = h5activityIndex(cookie_list_pin[index]) 256 | for cookie in cookie_list: 257 | if cookie.find('app_open')<=0: 258 | logger.info('*******************当前ck不是appck 跳过助力*******************\n') 259 | continue 260 | status = jinli_h5assist(cookie, inviteCode) 261 | if status: 262 | logger.info('*************助力满了 开红包*************\n') 263 | #logger.info('*******************开红包*******************\n') 264 | h5receiveRedpacketAll(cookie_list_pin[index]) 265 | time.sleep(3) 266 | index += 1 267 | if index >= len(cookie_list_pin): 268 | break 269 | for i in range(len(cookie_list_pin[index:])): 270 | index += i 271 | inviteCode = h5activityIndex(cookie_list_pin[index]) 272 | if inviteCode: 273 | break 274 | else: 275 | logger.info('*******************开红包*******************\n') 276 | h5receiveRedpacketAll(cookie_list_pin[index]) 277 | time.sleep(3) 278 | logger.info('没有需要助力的锦鲤红包助力码\n') 279 | 280 | logCount = (startLog+1)-endLog 281 | logger.info(f'运行前[{startLog}]次 运行后[{endLog}]次 本次使用[{logCount}]次') 282 | 283 | if __name__ == '__main__': 284 | main() 285 | -------------------------------------------------------------------------------- /jd_cash_windfgg.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 签到领现金_Windfgg,每日2毛~5毛 3 | * 0 0 6 * * sign_xj.js,tag=签到领现金 4 | * 5 | * 无助力活动 助力码无用 6 | * 活动入口:京东APP搜索领现金进入 7 | * 满30提现 目前有3、8、15、30的红包 8 | */ 9 | const $ = new Env('签到领现金_Windfgg'); 10 | const notify = $.isNode() ? require('./sendNotify') : ''; 11 | //Node.js用户请在jdCookie.js处填写京东ck; 12 | const jdCookieNode = $.isNode() ? require('./jdCookie.js') : ''; 13 | let jdNotify = true;//是否关闭通知,false打开通知推送,true关闭通知推送 14 | //IOS等用户直接用NobyDa的jd cookie 15 | let cookiesArr = [], cookie = '', message; 16 | if ($.isNode()) { 17 | Object.keys(jdCookieNode).forEach((item) => { 18 | cookiesArr.push(jdCookieNode[item]) 19 | }) 20 | if (process.env.JD_DEBUG && process.env.JD_DEBUG === 'false') console.log = () => { }; 21 | } else { 22 | cookiesArr = [$.getdata('CookieJD'), $.getdata('CookieJD2'), ...jsonParse($.getdata('CookiesJD') || "[]").map(item => item.cookie)].filter(item => !!item); 23 | } 24 | const JD_API_HOST = 'https://api.m.jd.com/client.action'; 25 | let allMessage = ''; 26 | 27 | let jdWindfggToken = ''; 28 | let jdWindfggHost='api.windfgg.cf' 29 | 30 | jdWindfggToken = $.isNode() ? (process.env.WindfggToken ? process.env.WindfggToken : `${jdWindfggToken}`) : ($.getdata('WindfggToken') ? $.getdata('WindfggToken') : `${jdWindfggToken}`); 31 | jdWindfggHost = $.isNode() ? (process.env.WindfggHost ? process.env.WindfggHost : `${jdWindfggHost}`) : ($.getdata('WindfggHost') ? $.getdata('WindfggHost') : `${jdWindfggHost}`); 32 | if (!jdWindfggToken) { 33 | console.log('请填写Windfgg获取的Token,变量名是WindfggToken'); 34 | return; 35 | } 36 | 37 | !(async () => { 38 | if (!cookiesArr[0]) { 39 | $.msg($.name, '【提示】请先获取京东账号一cookie\n直接使用NobyDa的京东签到获取', 'https://bean.m.jd.com/bean/signIndex.action', { "open-url": "https://bean.m.jd.com/bean/signIndex.action" }); 40 | return; 41 | } 42 | // await requireConfig() 43 | 44 | for (let i = 0; i < cookiesArr.length; i++) { 45 | if (cookiesArr[i]) { 46 | cookie = cookiesArr[i]; 47 | $.UserName = decodeURIComponent(cookie.match(/pt_pin=([^; ]+)(?=;?)/) && cookie.match(/pt_pin=([^; ]+)(?=;?)/)[1]) 48 | $.index = i + 1; 49 | $.isLogin = true; 50 | $.nickName = ''; 51 | message = ''; 52 | await TotalBean(); 53 | console.log(`\n******开始【京东账号${$.index}】${$.nickName || $.UserName}*********\n`); 54 | if (!$.isLogin) { 55 | $.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" }); 56 | 57 | if ($.isNode()) { 58 | await notify.sendNotify(`${$.name}cookie已失效 - ${$.UserName}`, `京东账号${$.index} ${$.UserName}\n请重新登录获取cookie`); 59 | } 60 | continue 61 | } 62 | await jdCash() 63 | } 64 | } 65 | if (allMessage) { 66 | if ($.isNode() && (process.env.CASH_NOTIFY_CONTROL ? process.env.CASH_NOTIFY_CONTROL === 'false' : !!1)) await notify.sendNotify($.name, allMessage); 67 | $.msg($.name, '', allMessage); 68 | } 69 | })() 70 | .catch((e) => { 71 | $.log('', `❌ ${$.name}, 失败! 原因: ${e}!`, '') 72 | }) 73 | .finally(() => { 74 | $.done(); 75 | }) 76 | async function jdCash() { 77 | $.signMoney = 0; 78 | await mob_sign() 79 | await mob_home() 80 | await appindex() 81 | await index() 82 | 83 | $.exchangeBeanNum = 0; 84 | 85 | await appindex(true) 86 | } 87 | 88 | async function appindex(info = false) { 89 | let functionId = "cash_homePage" 90 | let sign = `body=%7B%7D&build=167968&client=apple&clientVersion=10.4.0&d_brand=apple&d_model=iPhone13%2C3&ef=1&eid=eidI25488122a6s9Uqq6qodtQx6rgQhFlHkaE1KqvCRbzRnPZgP/93P%2BzfeY8nyrCw1FMzlQ1pE4X9JdmFEYKWdd1VxutadX0iJ6xedL%2BVBrSHCeDGV1&ep=%7B%22ciphertype%22%3A5%2C%22cipher%22%3A%7B%22screen%22%3A%22CJO3CMeyDJCy%22%2C%22osVersion%22%3A%22CJUkDK%3D%3D%22%2C%22openudid%22%3A%22CJSmCWU0DNYnYtS0DtGmCJY0YJcmDwCmYJC0DNHwZNc5ZQU2DJc3Zq%3D%3D%22%2C%22area%22%3A%22CJZpCJCmC180ENcnCv80ENc1EK%3D%3D%22%2C%22uuid%22%3A%22aQf1ZRdxb2r4ovZ1EJZhcxYlVNZSZz09%22%7D%2C%22ts%22%3A1648428189%2C%22hdid%22%3A%22JM9F1ywUPwflvMIpYPok0tt5k9kW4ArJEU3lfLhxBqw%3D%22%2C%22version%22%3A%221.0.3%22%2C%22appname%22%3A%22com.360buy.jdmobile%22%2C%22ridx%22%3A-1%7D&ext=%7B%22prstate%22%3A%220%22%2C%22pvcStu%22%3A%221%22%7D&isBackground=N&joycious=104&lang=zh_CN&networkType=3g&networklibtype=JDNetworkBaseAF&partner=apple&rfs=0000&scope=11&sign=98c0ea91318ef1313786d86d832f1d4d&st=1648428208392&sv=101&uemps=0-0&uts=0f31TVRjBSv7E8yLFU2g86XnPdLdKKyuazYDek9RnAdkKCbH50GbhlCSab3I2jwM04d75h5qDPiLMTl0I3dvlb3OFGnqX9NrfHUwDOpTEaxACTwWl6n//EOFSpqtKDhg%2BvlR1wAh0RSZ3J87iAf36Ce6nonmQvQAva7GoJM9Nbtdah0dgzXboUL2m5YqrJ1hWoxhCecLcrUWWbHTyAY3Rw%3D%3D` 91 | return new Promise((resolve) => { 92 | $.post(apptaskUrl(functionId, sign), async (err, resp, data) => { 93 | try { 94 | if (err) { 95 | console.log(`${JSON.stringify(err)}`) 96 | console.log(`appindex API请求失败,请检查网路重试`) 97 | } else { 98 | if (safeGet(data)) { 99 | data = JSON.parse(data); 100 | if (data.code === 0 && data.data.result) { 101 | if (info) { 102 | if (message) { 103 | message += `当前现金:${data.data.result.totalMoney}元`; 104 | allMessage += `京东账号${$.index}${$.nickName}\n${message}${$.index !== cookiesArr.length ? '\n\n' : ''}`; 105 | } 106 | console.log(`\n\n当前现金:${data.data.result.totalMoney}元`); 107 | return 108 | } 109 | $.signMoney = data.data.result.totalMoney; 110 | // console.log(`您的助力码为${data.data.result.invitedCode}`) 111 | //console.log(`\n【京东账号${$.index}(${$.UserName})的好友互助码】${data.data.result.invitedCode}\n`); 112 | let helpInfo = { 113 | 'inviteCode': data.data.result.invitedCode, 114 | 'shareDate': data.data.result.shareDate 115 | } 116 | $.shareDate = data.data.result.shareDate; 117 | // $.log(`shareDate: ${$.shareDate}`) 118 | // console.log(helpInfo) 119 | for (let task of data.data.result.taskInfos) { 120 | if (task.type === 4) { 121 | for (let i = task.doTimes; i < task.times; ++i) { 122 | console.log(`去做${task.name}任务 ${i + 1}/${task.times}`) 123 | await appdoTask(task.type, task.jump.params.skuId) 124 | await $.wait(5000) 125 | } 126 | } else if (task.type === 2) { 127 | for (let i = task.doTimes; i < task.times; ++i) { 128 | console.log(`去做${task.name}任务 ${i + 1}/${task.times}`) 129 | await appdoTask(task.type, task.jump.params.shopId) 130 | await $.wait(5000) 131 | } 132 | } else if (task.type === 30) { 133 | for (let i = task.doTimes; i < task.times; ++i) { 134 | console.log(`去做${task.name}任务 ${i + 1}/${task.times}`) 135 | await appdoTask(task.type, task.jump.params.path) 136 | await $.wait(5000) 137 | } 138 | } else if (task.type === 16 || task.type === 3 || task.type === 5 || task.type === 17 || task.type === 21) { 139 | for (let i = task.doTimes; i < task.times; ++i) { 140 | console.log(`去做${task.name}任务 ${i + 1}/${task.times}`) 141 | await appdoTask(task.type, task.jump.params.url) 142 | await $.wait(5000) 143 | } 144 | } 145 | } 146 | } 147 | } 148 | } 149 | } catch (e) { 150 | $.logErr(e, resp) 151 | } finally { 152 | resolve(data); 153 | } 154 | }) 155 | }) 156 | } 157 | function index() { 158 | return new Promise((resolve) => { 159 | $.get(taskUrl("cash_mob_home"), async (err, resp, data) => { 160 | try { 161 | if (err) { 162 | console.log(`${JSON.stringify(err)}`) 163 | console.log(`index API请求失败,请检查网路重试`) 164 | } else { 165 | if (safeGet(data)) { 166 | data = JSON.parse(data); 167 | if (data.code === 0 && data.data.result) { 168 | for (let task of data.data.result.taskInfos) { 169 | if (task.type === 4) { 170 | for (let i = task.doTimes; i < task.times; ++i) { 171 | console.log(`去做${task.name}任务 ${i + 1}/${task.times}`) 172 | await doTask(task.type, task.jump.params.skuId) 173 | await $.wait(5000) 174 | } 175 | } else if (task.type === 2) { 176 | for (let i = task.doTimes; i < task.times; ++i) { 177 | console.log(`去做${task.name}任务 ${i + 1}/${task.times}`) 178 | await doTask(task.type, task.jump.params.shopId) 179 | await $.wait(5000) 180 | } 181 | } else if (task.type === 31) { 182 | for (let i = task.doTimes; i < task.times; ++i) { 183 | console.log(`去做${task.name}任务 ${i + 1}/${task.times}`) 184 | await doTask(task.type, task.jump.params.path) 185 | await $.wait(5000) 186 | } 187 | } else if (task.type === 16 || task.type === 3 || task.type === 5 || task.type === 17 || task.type === 21) { 188 | for (let i = task.doTimes; i < task.times; ++i) { 189 | console.log(`去做${task.name}任务 ${i + 1}/${task.times}`) 190 | await doTask(task.type, task.jump.params.url) 191 | await $.wait(5000) 192 | } 193 | } 194 | } 195 | } 196 | } 197 | } 198 | } catch (e) { 199 | $.logErr(e, resp) 200 | } finally { 201 | resolve(data); 202 | } 203 | }) 204 | }) 205 | } 206 | async function appdoTask(type, taskInfo) { 207 | let functionId = 'cash_doTask' 208 | let body = { "type": type, "taskInfo": taskInfo } 209 | let sign = await getSignfromPanda(functionId, body) 210 | 211 | return new Promise((resolve) => { 212 | $.post(apptaskUrl(functionId, sign), (err, resp, data) => { 213 | try { 214 | if (err) { 215 | console.log(`${JSON.stringify(err)}`) 216 | console.log(`appdoTask API请求失败,请检查网路重试`) 217 | } else { 218 | if (safeGet(data)) { 219 | data = JSON.parse(data); 220 | if (data.code === 0) { 221 | console.log(`任务完成成功`) 222 | // console.log(data.data.result.taskInfos) 223 | } else { 224 | console.log(JSON.stringify(data)) 225 | } 226 | } 227 | } 228 | } catch (e) { 229 | $.logErr(e, resp) 230 | } finally { 231 | resolve(data); 232 | } 233 | }) 234 | }) 235 | } 236 | function doTask(type, taskInfo) { 237 | return new Promise((resolve) => { 238 | $.get(taskUrl("cash_doTask", { "type": type, "taskInfo": taskInfo }), (err, resp, data) => { 239 | try { 240 | if (err) { 241 | console.log(`${JSON.stringify(err)}`) 242 | console.log(`doTask API请求失败,请检查网路重试`) 243 | } else { 244 | if (safeGet(data)) { 245 | data = JSON.parse(data); 246 | if (data.code === 0) { 247 | console.log(`任务完成成功`) 248 | // console.log(data.data.result.taskInfos) 249 | } else { 250 | console.log(data) 251 | } 252 | } 253 | } 254 | } catch (e) { 255 | $.logErr(e, resp) 256 | } finally { 257 | resolve(data); 258 | } 259 | }) 260 | }) 261 | } 262 | function getSignfromPanda(functionId, body) { 263 | var strsign = ''; 264 | let data = { 265 | "fn": functionId, 266 | "body": body 267 | } 268 | return new Promise((resolve) => { 269 | let url = { 270 | url: `http://${jdWindfggHost}jd/sign`, 271 | body: JSON.stringify(data), 272 | followRedirect: false, 273 | headers: { 274 | 'Accept': '*/*', 275 | "accept-encoding": "gzip, deflate, br", 276 | 'Content-Type': 'application/json', 277 | 'Authorization': 'Bearer ' + jdWindfggToken 278 | }, 279 | timeout: 30000 280 | } 281 | $.post(url, async (err, resp, data) => { 282 | try { 283 | data = JSON.parse(data); 284 | 285 | if (data && data.code == 200) { 286 | lnrequesttimes = data.request_times; 287 | console.log("连接Windfgg服务成功,当前Token使用次数为" + lnrequesttimes); 288 | if (data.data) 289 | strsign = data.data || ''; 290 | if (strsign != '') 291 | resolve(strsign); 292 | }else if(data.code==201){ 293 | console.log("签名获取失败,Token使用次数上限."); 294 | } 295 | } catch (e) { 296 | $.logErr(e,resp) 297 | } finally { 298 | resolve(''); 299 | } 300 | }) 301 | }) 302 | } 303 | function randomString(e) { 304 | e = e || 32; 305 | let t = "abcdefghijklmnopqrstuvwxyz0123456789", a = t.length, n = ""; 306 | for (let i = 0; i < e; i++) 307 | n += t.charAt(Math.floor(Math.random() * a)); 308 | return n 309 | } 310 | function showMsg() { 311 | return new Promise(resolve => { 312 | if (!jdNotify) { 313 | $.msg($.name, '', `${message}`); 314 | } else { 315 | $.log(`京东账号${$.index}${$.nickName}\n${message}`); 316 | } 317 | resolve() 318 | }) 319 | } 320 | function apptaskUrl(functionId = "", body = "") { 321 | return { 322 | url: `${JD_API_HOST}?functionId=${functionId}`, 323 | body, 324 | headers: { 325 | 'Cookie': cookie, 326 | 'Host': 'api.m.jd.com', 327 | 'Connection': 'keep-alive', 328 | 'Content-Type': 'application/x-www-form-urlencoded', 329 | 'Referer': '', 330 | 'User-Agent': 'JD4iPhone/167774 (iPhone; iOS 14.7.1; Scale/3.00)', 331 | 'Accept-Language': 'zh-Hans-CN;q=1', 332 | 'Accept-Encoding': 'gzip, deflate, br', 333 | } 334 | } 335 | } 336 | function taskUrl(functionId, body = {}) { 337 | return { 338 | url: `${JD_API_HOST}?functionId=${functionId}&body=${encodeURIComponent(JSON.stringify(body))}&appid=CashRewardMiniH5Env&appid=9.1.0`, 339 | headers: { 340 | 'Cookie': cookie, 341 | 'Host': 'api.m.jd.com', 342 | 'Connection': 'keep-alive', 343 | 'Content-Type': 'application/json', 344 | 'Referer': 'http://wq.jd.com/wxapp/pages/hd-interaction/index/index', 345 | '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"), 346 | 'Accept-Language': 'zh-cn', 347 | 'Accept-Encoding': 'gzip, deflate, br', 348 | } 349 | } 350 | } 351 | 352 | function getAuthorShareCode(url) { 353 | return new Promise(resolve => { 354 | const options = { 355 | url: `${url}?${new Date()}`, "timeout": 30000, headers: { 356 | "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/87.0.4280.88" 357 | } 358 | }; 359 | if ($.isNode() && process.env.TG_PROXY_HOST && process.env.TG_PROXY_PORT) { 360 | const tunnel = require("tunnel"); 361 | const agent = { 362 | https: tunnel.httpsOverHttp({ 363 | proxy: { 364 | host: process.env.TG_PROXY_HOST, 365 | port: process.env.TG_PROXY_PORT * 1 366 | } 367 | }) 368 | } 369 | Object.assign(options, { agent }) 370 | } 371 | $.get(options, async (err, resp, data) => { 372 | try { 373 | if (err) { 374 | } else { 375 | if (data) data = JSON.parse(data) 376 | } 377 | } catch (e) { 378 | // $.logErr(e, resp) 379 | } finally { 380 | resolve(data); 381 | } 382 | }) 383 | }) 384 | } 385 | function TotalBean() { 386 | return new Promise(async resolve => { 387 | const options = { 388 | "url": `https://wq.jd.com/user/info/QueryJDUserInfo?sceneval=2`, 389 | "headers": { 390 | "Accept": "application/json,text/plain, */*", 391 | "Content-Type": "application/x-www-form-urlencoded", 392 | "Accept-Encoding": "gzip, deflate, br", 393 | "Accept-Language": "zh-cn", 394 | "Connection": "keep-alive", 395 | "Cookie": cookie, 396 | "Referer": "https://wqs.jd.com/my/jingdou/my.shtml?sceneval=2", 397 | "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") 398 | } 399 | } 400 | $.post(options, (err, resp, data) => { 401 | try { 402 | if (err) { 403 | console.log(`${JSON.stringify(err)}`) 404 | console.log(`${$.name} API请求失败,请检查网路重试`) 405 | } else { 406 | if (data) { 407 | data = JSON.parse(data); 408 | if (data['retcode'] === 13) { 409 | $.isLogin = false; //cookie过期 410 | return 411 | } 412 | if (data['retcode'] === 0) { 413 | $.nickName = (data['base'] && data['base'].nickname) || $.UserName; 414 | } else { 415 | $.nickName = $.UserName 416 | } 417 | } else { 418 | console.log(`京东服务器返回空数据`) 419 | } 420 | } 421 | } catch (e) { 422 | $.logErr(e, resp) 423 | } finally { 424 | resolve(); 425 | } 426 | }) 427 | }) 428 | } 429 | function safeGet(data) { 430 | try { 431 | if (typeof JSON.parse(data) == "object") { 432 | return true; 433 | } 434 | } catch (e) { 435 | console.log(e); 436 | console.log(`京东服务器访问数据为空,请检查自身设备网络情况`); 437 | return false; 438 | } 439 | } 440 | function jsonParse(str) { 441 | if (typeof str == "string") { 442 | try { 443 | return JSON.parse(str); 444 | } catch (e) { 445 | console.log(e); 446 | $.msg($.name, '', '请勿随意在BoxJs输入框修改内容\n建议通过脚本去获取cookie') 447 | return []; 448 | } 449 | } 450 | } 451 | 452 | //签到 453 | function mob_sign() { 454 | return new Promise((resolve) => { 455 | $.get(taskUrl("cash_mob_sign", { "breakReward": 1 }), (err, resp, data) => { 456 | try { 457 | if (err) { 458 | console.log(`${JSON.stringify(err)}`) 459 | console.log(`cash_mob_sign API请求失败,请检查网路重试`) 460 | } else { 461 | if (safeGet(data)) { 462 | data = JSON.parse(data); 463 | // console.log(data); 464 | if (data.data.bizCode === 0) { 465 | console.log(`签到${data.data.bizMsg}`) 466 | } else { 467 | console.log(data.data.bizMsg) 468 | } 469 | } 470 | } 471 | } catch (e) { 472 | $.logErr(e, resp) 473 | } finally { 474 | resolve(); 475 | } 476 | }) 477 | }) 478 | } 479 | 480 | //获取任务 481 | function mob_home() { 482 | return new Promise((resolve) => { 483 | $.get(taskUrl("cash_mob_home"), async (err, resp, data) => { 484 | try { 485 | if (err) { 486 | console.log(`${JSON.stringify(err)}`) 487 | console.log(`cash_mob_home API请求失败,请检查网路重试`) 488 | } else { 489 | if (safeGet(data)) { 490 | data = JSON.parse(data); 491 | if (data.code === 0 && data.data.result) { 492 | for (let task of data.data.result.taskInfos) { 493 | if (task.type === 4) { 494 | for (let i = task.doTimes; i < task.times; ++i) { 495 | console.log(`去做${task.name}任务 ${i + 1}/${task.times}`) 496 | await doTask(task.type, task.jump.params.skuId) 497 | await $.wait(5000) 498 | } 499 | } else if (task.type === 2) { 500 | for (let i = task.doTimes; i < task.times; ++i) { 501 | console.log(`去做${task.name}任务 ${i + 1}/${task.times}`) 502 | await doTask(task.type, task.jump.params.shopId) 503 | await $.wait(5000) 504 | } 505 | } else if (task.type === 31) { 506 | for (let i = task.doTimes; i < task.times; ++i) { 507 | console.log(`去做${task.name}任务 ${i + 1}/${task.times}`) 508 | await doTask(task.type, task.jump.params.path) 509 | await $.wait(5000) 510 | } 511 | } else if (task.type === 16 || task.type === 3 || task.type === 5 || task.type === 17 || task.type === 21) { 512 | for (let i = task.doTimes; i < task.times; ++i) { 513 | console.log(`去做${task.name}任务 ${i + 1}/${task.times}`) 514 | await doTask(task.type, task.jump.params.url) 515 | await $.wait(5000) 516 | } 517 | } 518 | } 519 | } 520 | } 521 | } 522 | } catch (e) { 523 | $.logErr(e, resp) 524 | } finally { 525 | resolve(data); 526 | } 527 | }) 528 | }) 529 | } 530 | 531 | // prettier-ignore 532 | 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) } -------------------------------------------------------------------------------- /jd_gua_cleancart_windfgg.js: -------------------------------------------------------------------------------- 1 | /* 2 | 清空购物车_Windfgg接口专用版 3 | 更新时间:2021-10-27 4 | 因其他脚本会加入商品到购物车,故此脚本用来清空购物车 5 | 包括预售 6 | 需要算法支持 7 | 默认:不执行 如需要请添加环境变量 8 | export WindfggToken="" # WindfggToken 9 | export gua_cleancart_Run="true" ## 运行清空购物车脚本 10 | export gua_cleancart_products="*@&@" ##清空去不 11 | —————————————— 12 | 1.@&@ 前面加数字 指定账号pin 13 | 如果有中文请填写中文 14 | 2.|-| 账号之间隔开 15 | 3.英文大小写请填清楚 16 | 4.优先匹配账号再匹配* 17 | 5.定义不清空的[商品]名称支持模糊匹配 18 | 6.pin@&@ 👉 指定账号(后面添加商品 前面账号[pin] *表示所有账号 19 | 7.|-| 👉 账号之间隔开 20 | —————————————— 21 | 22 | 商品名称规则 23 | ——————gua_cleancart_products———————— 24 | pin2@&@商品1,商品2👉该pin这几个商品名不清空 25 | pin5@&@👉该pin全清 26 | pin3@&@不清空👉该pin不清空 27 | *@&@不清空👉所有账号不请空 28 | *@&@👉所有账号清空 29 | 30 | 优先匹配账号再匹配* 31 | |-| 👉 账号之间隔开 32 | 有填帐号pin则*不适配 33 | —————————————— 34 | 如果有不清空的一定要加上"*@&@不清空" 35 | 防止没指定的账号购物车全清空 36 | 37 | */ 38 | let jdWindfggToken = '' 39 | let jdWindfggHost = 'api.windfgg.cf' 40 | let cleancartRun = 'false' 41 | let cleancartProducts = '' 42 | let lnrequesttimes=0 43 | 44 | const $ = new Env('清空购物车_Windfgg'); 45 | const jdCookieNode = $.isNode() ? require('./jdCookie.js') : ''; 46 | const notify = $.isNode() ? require('./sendNotify') : ''; 47 | //IOS等用户直接用NobyDa的jd cookie 48 | let cookiesArr = [], 49 | cookie = ''; 50 | if ($.isNode()) { 51 | Object.keys(jdCookieNode).forEach((item) => { 52 | cookiesArr.push(jdCookieNode[item]) 53 | }) 54 | if (process.env.JD_DEBUG && process.env.JD_DEBUG === 'false') console.log = () => {}; 55 | } else { 56 | cookiesArr = [$.getdata('CookieJD'), $.getdata('CookieJD2'), ...jsonParse($.getdata('CookiesJD') || "[]").map(item => item.cookie)].filter(item => !!item); 57 | } 58 | 59 | message = '' 60 | 61 | jdWindfggToken = $.isNode() ? (process.env.WindfggToken ? process.env.WindfggToken : `${jdWindfggToken}`) : ($.getdata('WindfggToken') ? $.getdata('WindfggToken') : `${jdWindfggToken}`); 62 | jdWindfggHost = $.isNode() ? (process.env.WindfggHost ? process.env.WindfggHost : `${jdWindfggHost}`) : ($.getdata('WindfggHost') ? $.getdata('WindfggHost') : `${jdWindfggHost}`); 63 | 64 | cleancartRun = $.isNode() ? (process.env.gua_cleancart_Run ? process.env.gua_cleancart_Run : `${cleancartRun}`) : ($.getdata('gua_cleancart_Run') ? $.getdata('gua_cleancart_Run') : `${cleancartRun}`); 65 | 66 | cleancartProducts = $.isNode() ? (process.env.gua_cleancart_products ? process.env.gua_cleancart_products : `${cleancartProducts}`) : ($.getdata('gua_cleancart_products') ? $.getdata('gua_cleancart_products') : `${cleancartProducts}`); 67 | 68 | if (!jdWindfggToken) { 69 | console.log('请填写Windfgg获取的Token,变量是WindfggToken'); 70 | return; 71 | } 72 | let productsArr = [] 73 | let cleancartProductsAll = [] 74 | for (let i of cleancartProducts && cleancartProducts.split('|-|')) { 75 | productsArr.push(i) 76 | } 77 | for (let i of cleancartProducts && cleancartProducts.split('|-|')) { 78 | productsArr.push(i) 79 | } 80 | for (let i in productsArr) { 81 | if(productsArr[i].indexOf('@&@') > -1){ 82 | let arr = productsArr[i].split('@&@') 83 | cleancartProductsAll[arr[0]] = arr[1].split(',') 84 | } 85 | } 86 | !(async () => { 87 | if (!cookiesArr[0]) { 88 | $.msg($.name, '【提示】请先获取cookie\n直接使用NobyDa的京东签到获取', 'https://bean.m.jd.com/', { 89 | "open-url": "https://bean.m.jd.com/" 90 | }); 91 | return; 92 | } 93 | if(cleancartRun !== 'true'){ 94 | console.log('脚本停止\n请添加环境变量[gua_cleancart_Run]为"true"') 95 | return 96 | } 97 | if(!cleancartProducts){ 98 | console.log('脚本停止\n请添加环境变量[gua_cleancart_products]\n清空商品\n内容规则看脚本文件') 99 | return 100 | } 101 | $.out = false 102 | for (let i = 0; i < cookiesArr.length; i++) { 103 | cookie = cookiesArr[i]; 104 | if (cookie) { 105 | $.UserName = decodeURIComponent(cookie.match(/pt_pin=([^; ]+)(?=;?)/) && cookie.match(/pt_pin=([^; ]+)(?=;?)/)[1]) 106 | $.index = i + 1; 107 | console.log(`\n\n******开始【京东账号${$.index}】${$.nickName || $.UserName}*********\n`); 108 | if(cleancartProductsAll[$.UserName]){ 109 | $.cleancartProductsArr = cleancartProductsAll[$.UserName] 110 | }else if(cleancartProductsAll["*"]){ 111 | $.cleancartProductsArr = cleancartProductsAll["*"] 112 | }else $.cleancartProductsArr = false 113 | if($.cleancartProductsArr) console.log($.cleancartProductsArr) 114 | await run(); 115 | if($.out) break 116 | } 117 | } 118 | if(message){ 119 | $.msg($.name, ``, `${message}`); 120 | if ($.isNode()){ 121 | await notify.sendNotify(`${$.name}`, `${message}`); 122 | } 123 | } 124 | })() 125 | .catch((e) => $.logErr(e)) 126 | .finally(() => $.done()) 127 | 128 | async function run(){ 129 | try{ 130 | let msg = '' 131 | let signBody = `{"homeWishListUserFlag":"1","userType":"0","updateTag":true,"showPlusEntry":"2","hitNewUIStatus":"1","cvhv":"049591","cartuuid":"hjudwgohxzVu96krv/T6Hg==","adid":""}` 132 | let body = await jdSign('cartClearQuery', signBody) 133 | if($.out) return 134 | if(!body){ 135 | console.log('获取不到算法') 136 | return 137 | } 138 | let data = await jdApi('cartClearQuery',body) 139 | let res = $.toObj(data,data); 140 | if(typeof res == 'object' && res){ 141 | if(res.resultCode == 0){ 142 | if(!res.clearCartInfo || !res.subTitle){ 143 | msg += `${res.mainTitle}\n` 144 | console.log(res.mainTitle) 145 | }else{ 146 | let num = 0 147 | if(res.subTitle){ 148 | num = res.subTitle.match(/共(\d+)件商品/).length > 0 && res.subTitle.match(/共(\d+)件商品/)[1] || 0 149 | msg += res.subTitle + "\n" 150 | console.log(res.subTitle) 151 | } 152 | // console.log(`共${num}件商品`) 153 | if(num != 0){ 154 | let operations = [] 155 | let operNum = 0 156 | for(let a of res.clearCartInfo || {}){ 157 | // console.log(a.groupName) 158 | // if(a.groupName.indexOf('7天前加入购物车') > -1){ 159 | for(let s of a.groupDetails || []){ 160 | if(toSDS(s.name)){ 161 | // console.log(s.unusable,s.skuUuid,s.name) 162 | operNum += s.clearSkus && s.clearSkus.length || 1; 163 | operations.push({ 164 | "itemType": s.itemType+"", 165 | "suitType": s.suitType, 166 | "skuUuid": s.skuUuid+"", 167 | "itemId": s.itemId || s.skuId, 168 | "useUuid": typeof s.useUuid !== 'undefined' && s.useUuid || false 169 | }) 170 | } 171 | } 172 | // } 173 | } 174 | console.log(`准备清空${operNum}件商品`) 175 | if(operations.length == 0){ 176 | console.log(`清空${operNum}件商品|没有找到要清空的商品`) 177 | msg += `清空${operNum}件商品|没有找到要清空的商品\n` 178 | }else{ 179 | let clearBody = `{"homeWishListUserFlag":"1","userType":"0","updateTag":false,"showPlusEntry":"2","hitNewUIStatus":"1","cvhv":"049591","cartuuid":"hjudwgohxzVu96krv/T6Hg==","operations":${$.toStr(operations,operations)},"adid":"","coord_type":"0"}` 180 | clearBody = await jdSign('cartClearRemove', clearBody) 181 | if($.out) return 182 | if(!clearBody){ 183 | console.log('获取不到算法') 184 | }else{ 185 | let clearData = await jdApi('cartClearRemove',clearBody) 186 | let clearRes = $.toObj(clearData,clearData); 187 | if(typeof clearRes == 'object'){ 188 | if(clearRes.resultCode == 0) { 189 | msg += `清空${operNum}件商品|✅\n` 190 | console.log(`清空${operNum}件商品|✅\n`) 191 | }else if(clearRes.mainTitle){ 192 | msg += `清空${operNum}件商品|${clearRes.mainTitle}\n` 193 | console.log(`清空${operNum}件商品|${clearRes.mainTitle}\n`) 194 | }else{ 195 | msg += `清空${operNum}件商品|❌\n` 196 | console.log(`清空${operNum}件商品|❌\n`) 197 | console.log(clearData) 198 | } 199 | }else{ 200 | msg += `清空${operNum}件商品|❌\n` 201 | console.log(`清空${operNum}件商品|❌\n`) 202 | console.log(clearData) 203 | } 204 | } 205 | } 206 | }else if(res.mainTitle){ 207 | msg += `${res.mainTitle}\n` 208 | console.log(res.mainTitle) 209 | }else{ 210 | msg += `未识别到购物车有商品\n` 211 | console.log(data) 212 | } 213 | } 214 | }else{ 215 | console.log(data) 216 | } 217 | }else{ 218 | console.log(data) 219 | } 220 | if(msg){ 221 | message += `【京东账号${$.index}】${$.nickName || $.UserName}\n${msg}\n` 222 | } 223 | await $.wait(parseInt(Math.random() * 2000 + 2000, 10)) 224 | }catch(e){ 225 | console.log(e) 226 | } 227 | } 228 | function toSDS(name){ 229 | let res = true 230 | if($.cleancartProductsArr === false) return false 231 | for(let t of $.cleancartProductsArr || []){ 232 | if(t && name.indexOf(t) > -1 || t == '不清空'){ 233 | res = false 234 | break 235 | } 236 | } 237 | return res 238 | } 239 | function jdApi(functionId,body) { 240 | if(!functionId || !body) return 241 | return new Promise(resolve => { 242 | $.post(taskPostUrl(`/client.action?functionId=${functionId}`, body), async (err, resp, data) => { 243 | try { 244 | if (err) { 245 | console.log(`${$.toStr(err)}`) 246 | console.log(`${$.name} API请求失败,请检查网路重试`) 247 | } else { 248 | // console.log(data) 249 | let res = $.toObj(data,data); 250 | if(typeof res == 'object'){ 251 | if(res.mainTitle) console.log(res.mainTitle) 252 | if(res.resultCode == 0){ 253 | resolve(res); 254 | } 255 | } 256 | } 257 | } catch (e) { 258 | $.logErr(e, resp) 259 | } finally { 260 | resolve(''); 261 | } 262 | }) 263 | }) 264 | } 265 | 266 | function jdSign(fn, body) { 267 | let sign = ''; 268 | let flag = false; 269 | try { 270 | const fs = require('fs'); 271 | if (fs.existsSync('./gua_encryption_sign.js')) { 272 | const encryptionSign = require('./gua_encryption_sign'); 273 | sign = encryptionSign.getSign(fn, body) 274 | } else { 275 | flag = true 276 | } 277 | sign = sign.data && sign.data.sign && sign.data.sign || '' 278 | } catch (e) { 279 | flag = true 280 | } 281 | if (!flag) 282 | return sign 283 | return new Promise((resolve) => { 284 | let url = { 285 | url: `http://${jdWindfggHost}/jd/sign`, 286 | body: `{"fn":"${fn}","body":${body}}`, 287 | followRedirect: false, 288 | headers: { 289 | 'Accept': '*/*', 290 | "accept-encoding": "gzip, deflate, br", 291 | 'Content-Type': 'application/json', 292 | 'Authorization': 'Bearer ' + jdWindfggToken 293 | }, 294 | timeout: 30000 295 | } 296 | $.post(url, async(err, resp, data) => { 297 | try { 298 | data = JSON.parse(data); 299 | if (data && data.code == 200) { 300 | lnrequesttimes = data.request_times; 301 | console.log("连接Windfgg服务成功,当前Token使用次数为" + lnrequesttimes); 302 | if (data.data) 303 | sign = data.data || ''; 304 | if (sign != '') 305 | resolve(sign); 306 | else 307 | console.log("签名获取失败,可能Token使用次数上限或被封."); 308 | } else { 309 | console.log("签名获取失败."); 310 | } 311 | } catch (e) { 312 | $.logErr(e, resp); 313 | } 314 | finally { 315 | resolve('') 316 | } 317 | }) 318 | }) 319 | } 320 | 321 | 322 | function taskPostUrl(url, body) { 323 | return { 324 | url: `https://api.m.jd.com${url}`, 325 | body: body, 326 | headers: { 327 | "Accept": "*/*", 328 | "Accept-Language": "zh-cn", 329 | "Accept-Encoding": "gzip, deflate, br", 330 | "Connection": "keep-alive", 331 | "Content-Type": "application/x-www-form-urlencoded", 332 | 'Cookie': `${cookie}`, 333 | "Host": "api.m.jd.com", 334 | "User-Agent": "JD4iPhone/167853 (iPhone; iOS; Scale/2.00)" , 335 | } 336 | } 337 | } 338 | 339 | function randomString(e) { 340 | e = e || 32; 341 | let t = "abcdef0123456789", a = t.length, n = ""; 342 | for (i = 0; i < e; i++) 343 | n += t.charAt(Math.floor(Math.random() * a)); 344 | return n 345 | } 346 | 347 | function jsonParse(str) { 348 | if (typeof str == "string") { 349 | try { 350 | return JSON.parse(str); 351 | } catch (e) { 352 | console.log(e); 353 | $.msg($.name, '', '请勿随意在BoxJs输入框修改内容\n建议通过脚本去获取cookie') 354 | return []; 355 | } 356 | } 357 | } 358 | 359 | // prettier-ignore 360 | 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)} 361 | 362 | -------------------------------------------------------------------------------- /jd_insight_windfgg.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 京洞察问卷通知 3 | * cron "0 0 9 * *" jd_insight_windfgg.js,tag=京洞察问卷通知 4 | */ 5 | const $ = new Env('京洞察问卷通知'); 6 | const notify = $.isNode() ? require('./sendNotify') : ''; 7 | //Node.js用户请在jdCookie.js处填写京东ck; 8 | const jdCookieNode = $.isNode() ? require('./jdCookie.js') : ''; 9 | //IOS等用户直接用NobyDa的jd cookie 10 | let cookiesArr = [], 11 | cookie = ''; 12 | if ($.isNode()) { 13 | Object.keys(jdCookieNode) 14 | .forEach((item) => { 15 | cookiesArr.push(jdCookieNode[item]) 16 | }) 17 | if (process.env.JD_DEBUG && process.env.JD_DEBUG === 'false') console.log = () => { }; 18 | } else { 19 | cookiesArr = [$.getdata('CookieJD'), $.getdata('CookieJD2'), ...jsonParse($.getdata('CookiesJD') || "[]") 20 | .map(item => item.cookie) 21 | ].filter(item => !!item); 22 | } !(async () => { 23 | if (!cookiesArr[0]) { 24 | $.msg($.name, '【提示】请先获取京东账号一cookie\n直接使用NobyDa的京东签到获取', 'https://bean.m.jd.com/bean/signIndex.action', { 25 | "open-url": "https://bean.m.jd.com/bean/signIndex.action" 26 | }); 27 | return; 28 | } 29 | UUID = getUUID('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); 30 | for (let i = 0; i < cookiesArr.length; i++) { 31 | UA = `jdapp;iPhone;10.0.8;14.6;${UUID};network/wifi;JDEbook/openapp.jdreader;model/iPhone9,2;addressid/2214222493;appBuild/168841;jdSupportDarkMode/0;Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16E158;supportJDSHWK/1`; 32 | if (cookiesArr[i]) { 33 | $.cookie = cookiesArr[i]; 34 | cookie = cookiesArr[i] 35 | $.UserName = decodeURIComponent(cookie.match(/pt_pin=([^; ]+)(?=;?)/) && cookie.match(/pt_pin=([^; ]+)(?=;?)/)[1]) 36 | $.index = i + 1; 37 | $.isLogin = true; 38 | $.nickName = ''; 39 | $.maxPage = '1'; 40 | message = ''; 41 | await TotalBean(); 42 | console.log(`\n******开始【京东账号${$.index}】${$.nickName || $.UserName}*********\n`); 43 | if (!$.isLogin) { 44 | $.msg($.name, `【提示】cookie已失效`, `京东账号${$.index} ${$.nickName || $.UserName}\n请重新登录获取\nhttps://bean.m.jd.com/bean/signIndex.action`, { 45 | "open-url": "https://bean.m.jd.com/bean/signIndex.action" 46 | }); 47 | 48 | if ($.isNode()) { 49 | await notify.sendNotify(`${$.name}cookie已失效 - ${$.UserName}`, `京东账号${$.index} ${$.UserName}\n请重新登录获取cookie`); 50 | } 51 | continue 52 | } 53 | await main() 54 | } 55 | } 56 | })() 57 | .catch((e) => { 58 | $.log('', `❌ ${$.name}, 失败! 原因: ${e}!`, '') 59 | }) 60 | .finally(() => { 61 | $.done(); 62 | }) 63 | 64 | async function main() { 65 | console.log(`开始获取京洞察调研列表...\n`) 66 | let data = await GetSurveyList(); 67 | if (data.result == true) { 68 | let list = data.messages.list 69 | if (list.length > 0) { 70 | let msg = `共${list.length}个类型调查问卷\n`; 71 | for (let index = 0; index < list.length; index++) { 72 | const item = list[index].surveyList; 73 | msg += `类型:${list[index].type}\n`; 74 | for (let index = 0; index < item.length; index++) { 75 | let surveyItem = item[index]; 76 | let title = surveyItem.title 77 | let subTitle = surveyItem.subTitle 78 | let answerUrl = surveyItem.answerUrl 79 | msg += `${index+1}.【${title}】 ${subTitle}\n${answerUrl}\n\n` 80 | } 81 | } 82 | $.log(msg) 83 | await notify.sendNotify(`${$.nickName || $.UserName} 京东问卷调查得京豆`, msg); 84 | } else { 85 | $.log('当前账户没有京调研问卷') 86 | } 87 | } else { 88 | $.log('京洞察调研列表请求错误 返回结果为空'+JSON.stringify(data)) 89 | } 90 | } 91 | 92 | function random(min, max) { 93 | return parseInt((max - min) * Math.random()); 94 | } 95 | 96 | function getUUID(x = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", t = 0) { 97 | return x.replace(/[xy]/g, function (x) { 98 | var r = 16 * Math.random() | 0, 99 | n = "x" == x ? r : 3 & r | 8; 100 | return uuid = t ? n.toString(36) 101 | .toUpperCase() : n.toString(36), uuid 102 | }) 103 | } 104 | 105 | function GetSurveyList() { 106 | const options = { 107 | "url": 'https://answer.jd.com/community/survey/list', 108 | "headers": { 109 | "Cookie": $.cookie, 110 | "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Mobile/15E148 Safari/604.1" 111 | } 112 | }; 113 | return new Promise(resolve => { 114 | $.get(options, async (err, resp, data) => { 115 | try { 116 | if (err) { 117 | console.log(err); 118 | console.log(`${$.name} API请求失败,请检查网路重试`) 119 | } else { 120 | if (data) { 121 | data = JSON.parse(data); 122 | } else { 123 | console.log("没有返回数据") 124 | } 125 | } 126 | } catch (e) { 127 | $.logErr(e, resp) 128 | } finally { 129 | resolve(data); 130 | } 131 | }) 132 | }) 133 | } 134 | 135 | function TotalBean() { 136 | return new Promise(async e => { 137 | const n = { 138 | url: "https://wq.jd.com/user_new/info/GetJDUserInfoUnion?sceneval=2", 139 | headers: { 140 | Host: "wq.jd.com", 141 | Accept: "*/*", 142 | Connection: "keep-alive", 143 | Cookie: cookie, 144 | "User-Agent": UA, 145 | "Accept-Language": "zh-cn", 146 | Referer: "https://home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&", 147 | "Accept-Encoding": "gzip, deflate, br" 148 | } 149 | }; 150 | $.get(n, (n, o, a) => { 151 | try { 152 | if (n) $.logErr(n); 153 | else if (a) { 154 | if (1001 === (a = JSON.parse(a))["retcode"]) return void ($.isLogin = !1); 155 | 0 === a["retcode"] && a.data && a.data.hasOwnProperty("userInfo") && ($.nickName = a.data.userInfo.baseInfo.nickname), 0 === a["retcode"] && a.data && a.data["assetInfo"] && ($.beanCount = a.data && a.data["assetInfo"]["beanNum"]) 156 | } else console.log("京东服务器返回空数据") 157 | } catch (e) { 158 | $.logErr(e) 159 | } finally { 160 | e() 161 | } 162 | }) 163 | }) 164 | } 165 | 166 | // prettier-ignore 167 | 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) } 168 | -------------------------------------------------------------------------------- /jd_red_statistics_windfgg.py: -------------------------------------------------------------------------------- 1 | """ 2 | const $ = new Env("历史红包统计"); 3 | 历史红包统计 4 | """ 5 | 6 | import requests 7 | import sys 8 | import re 9 | import time 10 | import os 11 | 12 | 13 | def gettimestamp(): 14 | return str(int(time.time() * 1000)) 15 | 16 | 17 | def printf(text): 18 | print(text) 19 | sys.stdout.flush() 20 | 21 | 22 | def getinfo(ck): 23 | isNext = True 24 | page = 1 25 | sum = 0 26 | usedsum = 0 27 | jxsum = 0 28 | usedjx = 0 29 | litesum = 0 30 | usedlite = 0 31 | healthsum = 0 32 | usedhealth = 0 33 | jdsum = 0 34 | usedjd = 0 35 | tysum = 0 36 | usedty = 0 37 | count = 0 38 | while isNext: 39 | url = "https://wq.jd.com/user/info/QueryUserRedEnvelopesV2?type=2&orgFlag=JD_PinGou_New&page=%s&cashRedType=1&redBalanceFlag=0&channel=3&_=%s&sceneval=2&g_login_type=1&g_ty=ls" % ( 40 | page, gettimestamp()) 41 | headers = { 42 | 'accept': '*/*', 43 | 'accept-encoding': 'gzip, deflate, br', 44 | 'accept-language': 'zh-CN,zh;q=0.9', 45 | 'dnt': '1', 46 | 'referer': 'https://wqs.jd.com/', 47 | 'sec-fetch-dest': 'script', 48 | 'sec-fetch-mode': 'no-cors', 49 | 'sec-fetch-site': 'same-site', 50 | 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1', 51 | 'cookie': ck 52 | } 53 | r = requests.get(url, headers=headers).json() 54 | if r['data']['unUseRedInfo']['redList'] == None: 55 | print('\n【六个月红包总数】', count, '\n【累计红包总额】%.2f' % sum, '\n【已用红包总额】%.2f' % usedsum) 56 | print( 57 | '\n ↓↓↓↓↓↓明细↓↓↓↓↓↓\n【京东】总额: %.2f, 已用: %.2f\n【京喜】总额: %.2f, 已用: %.2f\n【极速】总额: %.2f, 已用: %.2f\n【健康】总额: %.2f, 已用: %.2f\n【通用】总额: %.2f, 已用: %.2f\n' % ( 58 | jdsum, usedjd, jxsum, usedjx, litesum, usedlite, healthsum, usedhealth, tysum, usedty)) 59 | isNext = False 60 | else: 61 | page += 1 62 | count = r['data']['unUseRedInfo']['count'] 63 | for i in r['data']['unUseRedInfo']['redList']: 64 | sum += float(i['discount']) 65 | usedsum += (float(i['discount']) - float(i['balance'])) 66 | if "京喜" in i['orgLimitStr']: 67 | jxsum += float(i['discount']) 68 | usedjx += (float(i['discount']) - float(i['balance'])) 69 | elif "极速" in i['orgLimitStr']: 70 | litesum += float(i['discount']) 71 | usedlite += (float(i['discount']) - float(i['balance'])) 72 | elif "健康" in i['orgLimitStr']: 73 | healthsum += float(i['discount']) 74 | usedhealth += (float(i['discount']) - float(i['balance'])) 75 | elif "京东商城" in i['orgLimitStr']: 76 | jdsum += float(i['discount']) 77 | usedjd += (float(i['discount']) - float(i['balance'])) 78 | else: 79 | tysum += float(i['discount']) 80 | usedty += (float(i['discount']) - float(i['balance'])) 81 | 82 | 83 | if __name__ == '__main__': 84 | printf('🔔历史红包统计, 开始!\n') 85 | try: 86 | cks = os.environ["JD_COOKIE"].split("&") 87 | except: 88 | f = open("/jd/config/config.sh", "r", encoding='utf-8') 89 | cks = re.findall(r'Cookie[0-9]*="(pt_key=.*?;pt_pin=.*?;)"', f.read()) 90 | f.close() 91 | for ck in cks: 92 | ptpin = re.findall(r"pt_pin=(.*?);", ck)[0] 93 | printf("********开始京东账号" + ptpin + "********") 94 | try: 95 | getinfo(ck) 96 | except: 97 | print("发生异常错误") 98 | -------------------------------------------------------------------------------- /jd_wskey_windfgg.py: -------------------------------------------------------------------------------- 1 | """ 2 | new Env('更新wsck_windfgg'); 3 | 接口:Windfgg 4 | """ 5 | 6 | import requests 7 | import time 8 | import json 9 | import re 10 | import uuid 11 | import os 12 | 13 | token = "" 14 | username = "" 15 | password = "" 16 | try: 17 | host = os.environ['WindfggHost'] 18 | except: 19 | host='api.windfgg.cf' 20 | 21 | wdtoken = os.environ['WindfggToken'] 22 | if username == "" or password == "": 23 | f = open("/ql/config/auth.json") 24 | auth = f.read() 25 | auth = json.loads(auth) 26 | username = auth["username"] 27 | password = auth["password"] 28 | token = auth["token"] 29 | f.close() 30 | 31 | 32 | def gettimestamp(): 33 | return str(int(time.time() * 1000)) 34 | 35 | 36 | def login(username, password): 37 | url = "http://127.0.0.1:5700/api/login?t=%s" % gettimestamp() 38 | data = {"username": username, "password": password} 39 | r = s.post(url, data) 40 | if r.status_code==401: 41 | print('用户名或密码错误') 42 | s.headers.update({"authorization": "Bearer " + json.loads(r.text)["data"]["token"]}) 43 | 44 | 45 | def getitem(key): 46 | url = "http://127.0.0.1:5700/api/envs?searchValue=%s&t=%s" % (key, gettimestamp()) 47 | r = s.get(url) 48 | item = json.loads(r.text)["data"] 49 | return item 50 | 51 | 52 | def getckitem(key): 53 | url = "http://127.0.0.1:5700/api/envs?searchValue=JD_COOKIE&t=%s" % gettimestamp() 54 | r = s.get(url) 55 | for i in json.loads(r.text)["data"]: 56 | if key in i["value"]: 57 | return i 58 | return [] 59 | 60 | 61 | def genToken(wsCookie): 62 | url=f'http://{host}/jd/sign' 63 | body = { 64 | "fn":"genToken", 65 | "body":{ 66 | "action": "to", 67 | "to": "https%3A%2F%2Fplogin.m.jd.com%2Fcgi-bin%2Fm%2Fthirdapp_auth_page%3Ftoken%3DAAEAIEijIw6wxF2s3bNKF0bmGsI8xfw6hkQT6Ui2QVP7z1Xg%26client_type%3Dandroid%26appid%3D879%26appup_type%3D1" 68 | } 69 | } 70 | headers = { 71 | 'Content-Type': 'application/json', 72 | 'Authorization': 'Bearer '+ wdtoken, 73 | } 74 | data = json.dumps(body) 75 | r = requests.post(url, headers=headers, data=data) 76 | #print(r) 77 | if r.status_code!=200: 78 | print('状态码:'+r.status_code+'签名获取失败'+'(401是未授权或可能被拉黑,521是服务器宕机)') 79 | return '' 80 | r = json.loads(r.text) 81 | request_time = r["request_times"] 82 | print("Windfgg接口访问次数:%s" % (request_time)) 83 | sign=r["data"] 84 | url = "https://api.m.jd.com/client.action?" 85 | headers = { 86 | "content-type": "application/x-www-form-urlencoded", 87 | "host": "api.m.jd.com", 88 | "user-agent": "okhttp/3.12.1;jdmall;android;version/10.1.2;build/89753;screen/1080x2136;os/10;network/4g", 89 | "cookie": wsCookie 90 | } 91 | body = { 92 | "action": "to", 93 | "to": "https%3A%2F%2Fplogin.m.jd.com%2Fcgi-bin%2Fm%2Fthirdapp_auth_page%3Ftoken%3DAAEAIEijIw6wxF2s3bNKF0bmGsI8xfw6hkQT6Ui2QVP7z1Xg%26client_type%3Dandroid%26appid%3D879%26appup_type%3D1" 94 | } 95 | res = requests.post(url + sign, headers=headers) 96 | token = res.json()["tokenKey"] 97 | return token 98 | 99 | def getJDCookie(tokenKey): 100 | headers2 = { 101 | "content-type": "application/x-www-form-urlencoded", 102 | "host": "un.m.jd.com", 103 | "user-agent": "okhttp/3.12.1;jdmall;android;version/10.1.2;build/89753;screen/1080x2136;os/10;network/4g", 104 | } 105 | params = { 106 | 'tokenKey': tokenKey, 107 | 'to': 'https://wbbny.m.jd.com/babelDiy/Zeus/2fUope8TDN3dUJfNzQswkBLc7uE8/index.html?babelChannel=syfc&from=home' 108 | } 109 | res2 = requests.get("https://un.m.jd.com/cgi-bin/app/appjmp", headers=headers2, params=params, 110 | allow_redirects=False) 111 | pt_key = res2.cookies.get("pt_key") 112 | pt_pin = res2.cookies.get("pt_pin") 113 | print(f"pt_key={pt_key};pt_pin={pt_pin};") 114 | return f"pt_key={pt_key};pt_pin={pt_pin};" 115 | 116 | 117 | 118 | def wstopt(wskey): 119 | try: 120 | token = genToken(wskey) 121 | r = getJDCookie(token) 122 | return r 123 | except: 124 | return "error" 125 | 126 | 127 | def update(text, qlid): 128 | url = "http://127.0.0.1:5700/api/envs?t=%s" % gettimestamp() 129 | s.headers.update({"Content-Type": "application/json;charset=UTF-8"}) 130 | data = { 131 | "name": "JD_COOKIE", 132 | "value": text, 133 | "_id": qlid 134 | } 135 | r = s.put(url, data=json.dumps(data)) 136 | if json.loads(r.text)["code"] == 200: 137 | return True 138 | else: 139 | return False 140 | 141 | 142 | def insert(text): 143 | url = "http://127.0.0.1:5700/api/envs?t=%s" % gettimestamp() 144 | s.headers.update({"Content-Type": "application/json;charset=UTF-8"}) 145 | data = [] 146 | data_json = { 147 | "value": text, 148 | "name": "JD_COOKIE" 149 | } 150 | data.append(data_json) 151 | r = s.post(url, json.dumps(data)) 152 | if json.loads(r.text)["code"] == 200: 153 | return True 154 | else: 155 | return False 156 | 157 | 158 | if __name__ == '__main__': 159 | s = requests.session() 160 | if token == "": 161 | login(username, password) 162 | else: 163 | s.headers.update({"Authorization": "Bearer " + token}) 164 | wskeys = getitem("JD_WSCK") 165 | print(f'WindfggHost {host}\n') 166 | print('获取wsck成功 当前数量:'+str(len(wskeys))) 167 | print('\r\n') 168 | count = 1 169 | for i in wskeys: 170 | if i["status"] == 0: 171 | r = wstopt(i["value"]) 172 | if r == "error": 173 | print("api请求错误") 174 | else: 175 | ptck = r 176 | try: 177 | wspin = re.findall(r"pin=(.*?);", i["value"])[0] 178 | if ptck == "wskey错误": 179 | print("第%s个wskey可能过期了,pin为%s" % (count, wspin)) 180 | elif ptck == "未知错误" or ptck == "error": 181 | print("第%s个wskey发生了未知错误,pin为%s" % (count, wspin)) 182 | elif "" in ptck: 183 | print("你的ip被cloudflare拦截") 184 | else: 185 | ptpin = re.findall(r"pt_pin=(.*?);", ptck)[0] 186 | item = getckitem("pt_pin=" + ptpin) 187 | if item != []: 188 | qlid = item["_id"] 189 | if update(ptck, qlid): 190 | print("第%s个wskey更新成功,pin为%s" % (count, wspin)) 191 | print('\r\n') 192 | else: 193 | print("第%s个wskey更新失败,pin为%s" % (count, wspin)) 194 | else: 195 | if insert(ptck): 196 | print("第%s个wskey添加成功" % count) 197 | else: 198 | print("第%s个wskey添加失败" % count) 199 | except: 200 | print("第%s个wskey出现异常错误" % count) 201 | count += 1 202 | else: 203 | print("有一个wskey被禁用了") -------------------------------------------------------------------------------- /shareCode/test.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengYun27/YunFeng_Repo/3d7616c669968c26446f7d7555cc27d60abc359e/shareCode/test.json -------------------------------------------------------------------------------- /utils/TS_USER_AGENTS.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios" 2 | import { Md5 } from "ts-md5" 3 | import * as dotenv from "dotenv" 4 | import { existsSync, readFileSync } from "fs" 5 | import { sendNotify } from './sendNotify' 6 | 7 | dotenv.config() 8 | 9 | let fingerprint: string | number, token: string = '', enCryptMethodJD: any 10 | 11 | const USER_AGENTS: Array = [ 12 | "jdapp;android;10.0.2;10;network/wifi;Mozilla/5.0 (Linux; Android 10; ONEPLUS A5010 Build/QKQ1.191014.012; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045230 Mobile Safari/537.36", 13 | "jdapp;iPhone;10.0.2;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", 14 | "jdapp;android;10.0.2;9;network/4g;Mozilla/5.0 (Linux; Android 9; Mi Note 3 Build/PKQ1.181007.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/045131 Mobile Safari/537.36", 15 | "jdapp;android;10.0.2;10;network/wifi;Mozilla/5.0 (Linux; Android 10; GM1910 Build/QKQ1.190716.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045230 Mobile Safari/537.36", 16 | "jdapp;android;10.0.2;9;network/wifi;Mozilla/5.0 (Linux; Android 9; 16T Build/PKQ1.190616.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/044942 Mobile Safari/537.36", 17 | "jdapp;iPhone;10.0.2;13.6;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 13_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 18 | "jdapp;iPhone;10.0.2;13.6;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 13_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 19 | "jdapp;iPhone;10.0.2;13.5;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 13_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 20 | "jdapp;iPhone;10.0.2;14.1;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 21 | "jdapp;iPhone;10.0.2;13.3;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 22 | "jdapp;iPhone;10.0.2;13.7;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 13_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 23 | "jdapp;iPhone;10.0.2;14.1;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 24 | "jdapp;iPhone;10.0.2;13.3;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 25 | "jdapp;iPhone;10.0.2;13.4;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 13_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 26 | "jdapp;iPhone;10.0.2;14.3;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 27 | "jdapp;android;10.0.2;9;network/wifi;Mozilla/5.0 (Linux; Android 9; MI 6 Build/PKQ1.190118.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/044942 Mobile Safari/537.36", 28 | "jdapp;android;10.0.2;11;network/wifi;Mozilla/5.0 (Linux; Android 11; Redmi K30 5G Build/RKQ1.200826.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045511 Mobile Safari/537.36", 29 | "jdapp;iPhone;10.0.2;11.4;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 11_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15F79", 30 | "jdapp;android;10.0.2;10;;network/wifi;Mozilla/5.0 (Linux; Android 10; M2006J10C Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045230 Mobile Safari/537.36", 31 | "jdapp;android;10.0.2;10;network/wifi;Mozilla/5.0 (Linux; Android 10; M2006J10C Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045230 Mobile Safari/537.36", 32 | "jdapp;android;10.0.2;10;network/wifi;Mozilla/5.0 (Linux; Android 10; ONEPLUS A6000 Build/QKQ1.190716.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045224 Mobile Safari/537.36", 33 | "jdapp;android;10.0.2;9;network/wifi;Mozilla/5.0 (Linux; Android 9; MHA-AL00 Build/HUAWEIMHA-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/044942 Mobile Safari/537.36", 34 | "jdapp;android;10.0.2;8.1.0;network/wifi;Mozilla/5.0 (Linux; Android 8.1.0; 16 X Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/044942 Mobile Safari/537.36", 35 | "jdapp;android;10.0.2;8.0.0;network/wifi;Mozilla/5.0 (Linux; Android 8.0.0; HTC U-3w Build/OPR6.170623.013; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/044942 Mobile Safari/537.36", 36 | "jdapp;iPhone;10.0.2;14.0.1;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 37 | "jdapp;android;10.0.2;10;network/wifi;Mozilla/5.0 (Linux; Android 10; LYA-AL00 Build/HUAWEILYA-AL00L; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045230 Mobile Safari/537.36", 38 | "jdapp;iPhone;10.0.2;14.2;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 39 | "jdapp;iPhone;10.0.2;14.3;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 40 | "jdapp;iPhone;10.0.2;14.2;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 41 | "jdapp;android;10.0.2;8.1.0;network/wifi;Mozilla/5.0 (Linux; Android 8.1.0; MI 8 Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/045131 Mobile Safari/537.36", 42 | "jdapp;android;10.0.2;10;network/wifi;Mozilla/5.0 (Linux; Android 10; Redmi K20 Pro Premium Edition Build/QKQ1.190825.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045227 Mobile Safari/537.36", 43 | "jdapp;iPhone;10.0.2;14.3;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 44 | "jdapp;iPhone;10.0.2;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", 45 | "jdapp;android;10.0.2;11;network/wifi;Mozilla/5.0 (Linux; Android 11; Redmi K20 Pro Premium Edition Build/RKQ1.200826.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045513 Mobile Safari/537.36", 46 | "jdapp;android;10.0.2;10;network/wifi;Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045227 Mobile Safari/537.36", 47 | "jdapp;iPhone;10.0.2;14.1;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 48 | ] 49 | 50 | function TotalBean(cookie: string) { 51 | return { 52 | cookie: cookie, 53 | isLogin: true, 54 | nickName: '' 55 | } 56 | } 57 | 58 | function getRandomNumberByRange(start: number, end: number) { 59 | return Math.floor(Math.random() * (end - start) + start) 60 | } 61 | 62 | let USER_AGENT = USER_AGENTS[getRandomNumberByRange(0, USER_AGENTS.length)] 63 | 64 | async function getBeanShareCode(cookie: string) { 65 | let { data }: any = await axios.post('https://api.m.jd.com/client.action', 66 | `functionId=plantBeanIndex&body=${encodeURIComponent( 67 | JSON.stringify({ version: "9.0.0.1", "monitor_source": "plant_app_plant_index", "monitor_refer": "" }) 68 | )}&appid=ld&client=apple&area=5_274_49707_49973&build=167283&clientVersion=9.1.0`, { 69 | headers: { 70 | Cookie: cookie, 71 | Host: "api.m.jd.com", 72 | Accept: "*/*", 73 | Connection: "keep-alive", 74 | "User-Agent": USER_AGENT 75 | } 76 | }) 77 | if (data.data?.jwordShareInfo?.shareUrl) 78 | return data.data.jwordShareInfo.shareUrl.split('Uuid=')![1] 79 | else 80 | return '' 81 | } 82 | 83 | async function getFarmShareCode(cookie: string) { 84 | let { data }: any = await axios.post('https://api.m.jd.com/client.action?functionId=initForFarm', `body=${encodeURIComponent(JSON.stringify({ "version": 4 }))}&appid=wh5&clientVersion=9.1.0`, { 85 | headers: { 86 | "cookie": cookie, 87 | "origin": "https://home.m.jd.com", 88 | "referer": "https://home.m.jd.com/myJd/newhome.action", 89 | "User-Agent": USER_AGENT, 90 | "Content-Type": "application/x-www-form-urlencoded" 91 | } 92 | }) 93 | 94 | if (data.farmUserPro) 95 | return data.farmUserPro.shareCode 96 | else 97 | return '' 98 | } 99 | 100 | async function requireConfig(check: boolean = false): Promise { 101 | let cookiesArr: string[] = [] 102 | const jdCookieNode = require('./jdCookie.js') 103 | let keys: string[] = Object.keys(jdCookieNode) 104 | for (let i = 0; i < keys.length; i++) { 105 | let cookie = jdCookieNode[keys[i]] 106 | if (!check) { 107 | cookiesArr.push(cookie) 108 | } else { 109 | if (await checkCookie(cookie)) { 110 | cookiesArr.push(cookie) 111 | } else { 112 | let username = decodeURIComponent(jdCookieNode[keys[i]].match(/pt_pin=([^;]*)/)![1]) 113 | console.log('Cookie失效', username) 114 | await sendNotify('Cookie失效', '【京东账号】' + username) 115 | } 116 | } 117 | } 118 | console.log(`共${cookiesArr.length}个京东账号\n`) 119 | return cookiesArr 120 | } 121 | 122 | async function checkCookie(cookie) { 123 | await wait(1000) 124 | try { 125 | let { data }: any = await axios.get(`https://api.m.jd.com/client.action?functionId=GetJDUserInfoUnion&appid=jd-cphdeveloper-m&body=${encodeURIComponent(JSON.stringify({ "orgFlag": "JD_PinGou_New", "callSource": "mainorder", "channel": 4, "isHomewhite": 0, "sceneval": 2 }))}&loginType=2&_=${Date.now()}&sceneval=2&g_login_type=1&callback=GetJDUserInfoUnion&g_ty=ls`, { 126 | headers: { 127 | 'authority': 'api.m.jd.com', 128 | 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1', 129 | 'referer': 'https://home.m.jd.com/', 130 | 'cookie': cookie 131 | } 132 | }) 133 | data = JSON.parse(data.match(/GetJDUserInfoUnion\((.*)\)/)[1]) 134 | return data.retcode === '0'; 135 | } catch (e) { 136 | return false 137 | } 138 | } 139 | 140 | function wait(timeout: number) { 141 | return new Promise(resolve => { 142 | setTimeout(resolve, timeout) 143 | }) 144 | } 145 | 146 | async function requestAlgo(appId: number = 10032) { 147 | fingerprint = generateFp() 148 | return new Promise(async resolve => { 149 | let { data }: any = await axios.post('https://cactus.jd.com/request_algo?g_ty=ajax', { 150 | "version": "1.0", 151 | "fp": fingerprint, 152 | "appId": appId, 153 | "timestamp": Date.now(), 154 | "platform": "web", 155 | "expandParams": "" 156 | }, { 157 | "headers": { 158 | 'Authority': 'cactus.jd.com', 159 | 'Pragma': 'no-cache', 160 | 'Cache-Control': 'no-cache', 161 | 'Accept': 'application/json', 162 | 'User-Agent': USER_AGENT, 163 | 'Content-Type': 'application/json', 164 | 'Origin': 'https://st.jingxi.com', 165 | 'Sec-Fetch-Site': 'cross-site', 166 | 'Sec-Fetch-Mode': 'cors', 167 | 'Sec-Fetch-Dest': 'empty', 168 | 'Referer': 'https://st.jingxi.com/', 169 | 'Accept-Language': 'zh-CN,zh;q=0.9,zh-TW;q=0.8,en;q=0.7' 170 | }, 171 | }) 172 | if (data['status'] === 200) { 173 | token = data.data.result.tk 174 | let enCryptMethodJDString = data.data.result.algo 175 | if (enCryptMethodJDString) enCryptMethodJD = new Function(`return ${enCryptMethodJDString}`)() 176 | } else { 177 | console.log(`fp: ${fingerprint}`) 178 | console.log('request_algo 签名参数API请求失败:') 179 | } 180 | resolve() 181 | }) 182 | } 183 | 184 | function generateFp() { 185 | let e = "0123456789" 186 | let a = 13 187 | let i = '' 188 | for (; a--;) 189 | i += e[Math.random() * e.length | 0] 190 | return (i + Date.now()).slice(0, 16) 191 | } 192 | 193 | function getJxToken(cookie: string, phoneId: string = '') { 194 | function generateStr(input: number) { 195 | let src = 'abcdefghijklmnopqrstuvwxyz1234567890' 196 | let res = '' 197 | for (let i = 0; i < input; i++) { 198 | res += src[Math.floor(src.length * Math.random())] 199 | } 200 | return res 201 | } 202 | 203 | if (!phoneId) 204 | phoneId = generateStr(40) 205 | let timestamp = Date.now().toString() 206 | let nickname = cookie.match(/pt_pin=([^;]*)/)![1] 207 | let jstoken = Md5.hashStr('' + decodeURIComponent(nickname) + timestamp + phoneId + 'tPOamqCuk9NLgVPAljUyIHcPRmKlVxDy') 208 | return { 209 | 'strPgtimestamp': timestamp, 210 | 'strPhoneID': phoneId, 211 | 'strPgUUNum': jstoken 212 | } 213 | } 214 | 215 | function exceptCookie(filename: string = 'x.ts') { 216 | let except: any = [] 217 | if (existsSync('./utils/exceptCookie.json')) { 218 | try { 219 | except = JSON.parse(readFileSync('./utils/exceptCookie.json').toString() || '{}')[filename] || [] 220 | } catch (e) { 221 | console.log('./utils/exceptCookie.json JSON格式错误') 222 | } 223 | } 224 | return except 225 | } 226 | 227 | function randomString(e: number, word?: number) { 228 | e = e || 32 229 | let t = word === 26 ? "012345678abcdefghijklmnopqrstuvwxyz" : "0123456789abcdef", a = t.length, n = "" 230 | for (let i = 0; i < e; i++) 231 | n += t.charAt(Math.floor(Math.random() * a)) 232 | return n 233 | } 234 | 235 | function o2s(arr: object, title: string = '') { 236 | title ? console.log(title, JSON.stringify(arr)) : console.log(JSON.stringify(arr)) 237 | } 238 | 239 | function randomNumString(e: number) { 240 | e = e || 32 241 | let t = '0123456789', a = t.length, n = "" 242 | for (let i = 0; i < e; i++) 243 | n += t.charAt(Math.floor(Math.random() * a)) 244 | return n 245 | } 246 | 247 | function randomWord(n: number = 1) { 248 | let t = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', a = t.length 249 | let rnd: string = '' 250 | for (let i = 0; i < n; i++) { 251 | rnd += t.charAt(Math.floor(Math.random() * a)) 252 | } 253 | return rnd 254 | } 255 | 256 | async function getshareCodeHW(key: string) { 257 | let shareCodeHW: string[] = [] 258 | for (let i = 0; i < 5; i++) { 259 | try { 260 | let { data }: any = await axios.get('https://api.jdsharecode.xyz/api/HW_CODES') 261 | shareCodeHW = data[key] || [] 262 | if (shareCodeHW.length !== 0) { 263 | break 264 | } 265 | } catch (e) { 266 | console.log("getshareCodeHW Error, Retry...") 267 | await wait(getRandomNumberByRange(2000, 6000)) 268 | } 269 | } 270 | return shareCodeHW 271 | } 272 | 273 | async function getShareCodePool(key: string, num: number) { 274 | let shareCode: string[] = [] 275 | for (let i = 0; i < 2; i++) { 276 | try { 277 | let { data }: any = await axios.get(`https://api.jdsharecode.xyz/api/${key}/${num}`) 278 | shareCode = data.data || [] 279 | console.log(`随机获取${num}个${key}成功:${JSON.stringify(shareCode)}`) 280 | if (shareCode.length !== 0) { 281 | break 282 | } 283 | } catch (e) { 284 | console.log("getShareCodePool Error, Retry...") 285 | await wait(getRandomNumberByRange(2000, 6000)) 286 | } 287 | } 288 | return shareCode 289 | } 290 | 291 | /*async function wechat_app_msg(title: string, content: string, user: string) { 292 | let corpid: string = "", corpsecret: string = "" 293 | let {data: gettoken} = await axios.get(`https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${corpid}&corpsecret=${corpsecret}`) 294 | let access_token: string = gettoken.access_token 295 | 296 | let {data: send} = await axios.post(`https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${access_token}`, { 297 | "touser": user, 298 | "msgtype": "text", 299 | "agentid": 1000002, 300 | "text": { 301 | "content": `${title}\n\n${content}` 302 | }, 303 | "safe": 0 304 | }) 305 | if (send.errcode === 0) { 306 | console.log('企业微信应用消息发送成功') 307 | } else { 308 | console.log('企业微信应用消息发送失败', send) 309 | } 310 | }*/ 311 | 312 | function obj2str(obj: object) { 313 | return JSON.stringify(obj) 314 | } 315 | 316 | async function getDevice() { 317 | let { data } = await axios.get('https://betahub.cn/api/apple/devices/iPhone', { 318 | headers: { 319 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36' 320 | } 321 | }) 322 | data = data[getRandomNumberByRange(0, 16)] 323 | return data.identifier 324 | } 325 | 326 | async function getVersion(device: string) { 327 | let { data } = await axios.get(`https://betahub.cn/api/apple/firmwares/${device}`, { 328 | headers: { 329 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36' 330 | } 331 | }) 332 | data = data[getRandomNumberByRange(0, data.length)] 333 | return data.firmware_info.version 334 | } 335 | 336 | async function jdpingou() { 337 | let device: string, version: string; 338 | device = await getDevice(); 339 | version = await getVersion(device); 340 | return `jdpingou;iPhone;5.19.0;${version};${randomString(40)};network/wifi;model/${device};appBuild/100833;ADID/;supportApplePay/1;hasUPPay/0;pushNoticeIsOpen/0;hasOCPay/0;supportBestPay/0;session/${getRandomNumberByRange(10, 90)};pap/JA2019_3111789;brand/apple;supportJDSHWK/1;Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148` 341 | } 342 | 343 | function get(url: string, prarms?: string, headers?: any) { 344 | return axios.get(url, { 345 | params: prarms, 346 | headers: headers 347 | }) 348 | .then(res => { 349 | if (typeof res.data === 'string' && res.data.match(/^jsonpCBK/)) { 350 | return JSON.parse(res.data.match(/jsonpCBK.?\(([\w\W]*)\);/)[1]) 351 | } else { 352 | return res.data 353 | } 354 | }) 355 | .catch(err => { 356 | console.log(err?.response?.status, err?.response?.statusText) 357 | }); 358 | } 359 | 360 | function post(url: string, prarms?: string | object, headers?: any): Promise { 361 | return axios.post(url, prarms, { 362 | headers: headers 363 | }) 364 | .then(res => res.data) 365 | .catch(err => { 366 | console.log(err?.response?.status, err?.response?.statusText) 367 | }); 368 | } 369 | 370 | export default USER_AGENT 371 | export { 372 | TotalBean, 373 | getBeanShareCode, 374 | getFarmShareCode, 375 | requireConfig, 376 | wait, 377 | getRandomNumberByRange, 378 | requestAlgo, 379 | getJxToken, 380 | exceptCookie, 381 | randomString, 382 | o2s, 383 | randomNumString, 384 | getshareCodeHW, 385 | getShareCodePool, 386 | randomWord, 387 | obj2str, 388 | jdpingou, 389 | get, 390 | post 391 | } -------------------------------------------------------------------------------- /utils/USER_AGENTS.js: -------------------------------------------------------------------------------- 1 | const USER_AGENTS = [ 2 | "jdapp;android;10.1.0;10;network/wifi;Mozilla/5.0 (Linux; Android 10; ONEPLUS A5010 Build/QKQ1.191014.012; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045230 Mobile Safari/537.36", 3 | "jdapp;iPhone;10.1.0;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", 4 | "jdapp;android;10.1.0;9;network/4g;Mozilla/5.0 (Linux; Android 9; Mi Note 3 Build/PKQ1.181007.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/045131 Mobile Safari/537.36", 5 | "jdapp;android;10.1.0;10;network/wifi;Mozilla/5.0 (Linux; Android 10; GM1910 Build/QKQ1.190716.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045230 Mobile Safari/537.36", 6 | "jdapp;android;10.1.0;9;network/wifi;Mozilla/5.0 (Linux; Android 9; 16T Build/PKQ1.190616.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/044942 Mobile Safari/537.36", 7 | "jdapp;iPhone;10.1.0;13.6;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 13_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 8 | "jdapp;iPhone;10.1.0;13.6;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 13_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 9 | "jdapp;iPhone;10.1.0;13.5;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 13_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 10 | "jdapp;iPhone;10.1.0;14.1;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 11 | "jdapp;iPhone;10.1.0;13.3;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 12 | "jdapp;iPhone;10.1.0;13.7;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 13_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 13 | "jdapp;iPhone;10.1.0;14.1;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 14 | "jdapp;iPhone;10.1.0;13.3;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 15 | "jdapp;iPhone;10.1.0;13.4;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 13_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 16 | "jdapp;iPhone;10.1.0;14.3;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 17 | "jdapp;android;10.1.0;9;network/wifi;Mozilla/5.0 (Linux; Android 9; MI 6 Build/PKQ1.190118.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/044942 Mobile Safari/537.36", 18 | "jdapp;android;10.1.0;11;network/wifi;Mozilla/5.0 (Linux; Android 11; Redmi K30 5G Build/RKQ1.200826.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045511 Mobile Safari/537.36", 19 | "jdapp;iPhone;10.1.0;11.4;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 11_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15F79", 20 | "jdapp;android;10.1.0;10;;network/wifi;Mozilla/5.0 (Linux; Android 10; M2006J10C Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045230 Mobile Safari/537.36", 21 | "jdapp;android;10.1.0;10;network/wifi;Mozilla/5.0 (Linux; Android 10; M2006J10C Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045230 Mobile Safari/537.36", 22 | "jdapp;android;10.1.0;10;network/wifi;Mozilla/5.0 (Linux; Android 10; ONEPLUS A6000 Build/QKQ1.190716.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045224 Mobile Safari/537.36", 23 | "jdapp;android;10.1.0;9;network/wifi;Mozilla/5.0 (Linux; Android 9; MHA-AL00 Build/HUAWEIMHA-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/044942 Mobile Safari/537.36", 24 | "jdapp;android;10.1.0;8.1.0;network/wifi;Mozilla/5.0 (Linux; Android 8.1.0; 16 X Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/044942 Mobile Safari/537.36", 25 | "jdapp;android;10.1.0;8.0.0;network/wifi;Mozilla/5.0 (Linux; Android 8.0.0; HTC U-3w Build/OPR6.170623.013; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/044942 Mobile Safari/537.36", 26 | "jdapp;iPhone;10.1.0;14.0.1;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 27 | "jdapp;android;10.1.0;10;network/wifi;Mozilla/5.0 (Linux; Android 10; LYA-AL00 Build/HUAWEILYA-AL00L; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045230 Mobile Safari/537.36", 28 | "jdapp;iPhone;10.1.0;14.2;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 29 | "jdapp;iPhone;10.1.0;14.3;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 30 | "jdapp;iPhone;10.1.0;14.2;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 31 | "jdapp;android;10.1.0;8.1.0;network/wifi;Mozilla/5.0 (Linux; Android 8.1.0; MI 8 Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/045131 Mobile Safari/537.36", 32 | "jdapp;android;10.1.0;10;network/wifi;Mozilla/5.0 (Linux; Android 10; Redmi K20 Pro Premium Edition Build/QKQ1.190825.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045227 Mobile Safari/537.36", 33 | "jdapp;iPhone;10.1.0;14.3;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 34 | "jdapp;iPhone;10.1.0;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", 35 | "jdapp;android;10.1.0;11;network/wifi;Mozilla/5.0 (Linux; Android 11; Redmi K20 Pro Premium Edition Build/RKQ1.200826.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045513 Mobile Safari/537.36", 36 | "jdapp;android;10.1.0;10;network/wifi;Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045227 Mobile Safari/537.36", 37 | "jdapp;iPhone;10.1.0;14.1;network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 14_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1", 38 | ] 39 | /** 40 | * 生成随机数字 41 | * @param {number} min 最小值(包含) 42 | * @param {number} max 最大值(不包含) 43 | */ 44 | function randomNumber (min = 0, max = 100) { 45 | return Math.min(Math.floor(min + Math.random() * (max - min)), max); 46 | } 47 | const USER_AGENT = USER_AGENTS[randomNumber(0, USER_AGENTS.length)]; 48 | 49 | module.exports = { 50 | USER_AGENT 51 | } 52 | -------------------------------------------------------------------------------- /utils/ql.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const got = require('got'); 4 | require('dotenv').config(); 5 | const { readFile } = require('fs/promises'); 6 | const path = require('path'); 7 | 8 | const qlDir = '/ql'; 9 | const fs = require('fs'); 10 | let Fileexists = fs.existsSync('/ql/data/config/auth.json'); 11 | let authFile=""; 12 | if (Fileexists) 13 | authFile="/ql/data/config/auth.json" 14 | else 15 | authFile="/ql/config/auth.json" 16 | //const authFile = path.join(qlDir, 'config/auth.json'); 17 | 18 | const api = got.extend({ 19 | prefixUrl: 'http://127.0.0.1:5600', 20 | retry: { limit: 0 }, 21 | }); 22 | 23 | async function getToken() { 24 | const authConfig = JSON.parse(await readFile(authFile)); 25 | return authConfig.token; 26 | } 27 | 28 | module.exports.getEnvs = async () => { 29 | const token = await getToken(); 30 | const body = await api({ 31 | url: 'api/envs', 32 | searchParams: { 33 | searchValue: 'JD_COOKIE', 34 | t: Date.now(), 35 | }, 36 | headers: { 37 | Accept: 'application/json', 38 | authorization: `Bearer ${token}`, 39 | }, 40 | }).json(); 41 | return body.data; 42 | }; 43 | 44 | module.exports.getEnvsCount = async () => { 45 | const data = await this.getEnvs(); 46 | return data.length; 47 | }; 48 | 49 | module.exports.addEnv = async (cookie, remarks) => { 50 | const token = await getToken(); 51 | const body = await api({ 52 | method: 'post', 53 | url: 'api/envs', 54 | params: { t: Date.now() }, 55 | json: [{ 56 | name: 'JD_COOKIE', 57 | value: cookie, 58 | remarks, 59 | }], 60 | headers: { 61 | Accept: 'application/json', 62 | authorization: `Bearer ${token}`, 63 | 'Content-Type': 'application/json;charset=UTF-8', 64 | }, 65 | }).json(); 66 | return body; 67 | }; 68 | 69 | module.exports.updateEnv = async (cookie, eid, remarks) => { 70 | const token = await getToken(); 71 | const body = await api({ 72 | method: 'put', 73 | url: 'api/envs', 74 | params: { t: Date.now() }, 75 | json: { 76 | name: 'JD_COOKIE', 77 | value: cookie, 78 | _id: eid, 79 | remarks, 80 | }, 81 | headers: { 82 | Accept: 'application/json', 83 | authorization: `Bearer ${token}`, 84 | 'Content-Type': 'application/json;charset=UTF-8', 85 | }, 86 | }).json(); 87 | return body; 88 | }; 89 | 90 | module.exports.updateEnv11 = async (cookie, eid, remarks) => { 91 | const token = await getToken(); 92 | const body = await api({ 93 | method: 'put', 94 | url: 'api/envs', 95 | params: { t: Date.now() }, 96 | json: { 97 | name: 'JD_COOKIE', 98 | value: cookie, 99 | id: eid, 100 | remarks, 101 | }, 102 | headers: { 103 | Accept: 'application/json', 104 | authorization: `Bearer ${token}`, 105 | 'Content-Type': 'application/json;charset=UTF-8', 106 | }, 107 | }).json(); 108 | return body; 109 | }; 110 | 111 | module.exports.DisableCk = async (eid) => { 112 | const token = await getToken(); 113 | const body = await api({ 114 | method: 'put', 115 | url: 'api/envs/disable', 116 | params: { t: Date.now() }, 117 | body: JSON.stringify([eid]), 118 | headers: { 119 | Accept: 'application/json', 120 | authorization: `Bearer ${token}`, 121 | 'Content-Type': 'application/json;charset=UTF-8', 122 | }, 123 | }).json(); 124 | return body; 125 | }; 126 | 127 | module.exports.EnableCk = async (eid) => { 128 | const token = await getToken(); 129 | const body = await api({ 130 | method: 'put', 131 | url: 'api/envs/enable', 132 | params: { t: Date.now() }, 133 | body: JSON.stringify([eid]), 134 | headers: { 135 | Accept: 'application/json', 136 | authorization: `Bearer ${token}`, 137 | 'Content-Type': 'application/json;charset=UTF-8', 138 | }, 139 | }).json(); 140 | return body; 141 | }; 142 | 143 | module.exports.getstatus = async(eid) => { 144 | const envs = await this.getEnvs(); 145 | var tempid = 0; 146 | for (let i = 0; i < envs.length; i++) { 147 | tempid = 0; 148 | if (envs[i]._id) { 149 | tempid = envs[i]._id; 150 | } 151 | if (envs[i].id) { 152 | tempid = envs[i].id; 153 | } 154 | if (tempid == eid) { 155 | return envs[i].status; 156 | } 157 | } 158 | return 99; 159 | }; 160 | 161 | module.exports.getEnvById = async(eid) => { 162 | const envs = await this.getEnvs(); 163 | var tempid = 0; 164 | for (let i = 0; i < envs.length; i++) { 165 | tempid = 0; 166 | if (envs[i]._id) { 167 | tempid = envs[i]._id; 168 | } 169 | if (envs[i].id) { 170 | tempid = envs[i].id; 171 | } 172 | if (tempid == eid) { 173 | return envs[i].value; 174 | } 175 | } 176 | return ""; 177 | }; 178 | 179 | module.exports.getEnvByPtPin = async (Ptpin) => { 180 | const envs = await this.getEnvs(); 181 | for (let i = 0; i < envs.length; i++) { 182 | var tempptpin = decodeURIComponent(envs[i].value.match(/pt_pin=([^; ]+)(?=;?)/) && envs[i].value.match(/pt_pin=([^; ]+)(?=;?)/)[1]); 183 | if(tempptpin==Ptpin){ 184 | return envs[i]; 185 | } 186 | } 187 | return ""; 188 | }; 189 | 190 | module.exports.delEnv = async (eid) => { 191 | const token = await getToken(); 192 | const body = await api({ 193 | method: 'delete', 194 | url: 'api/envs', 195 | params: { t: Date.now() }, 196 | body: JSON.stringify([eid]), 197 | headers: { 198 | Accept: 'application/json', 199 | authorization: `Bearer ${token}`, 200 | 'Content-Type': 'application/json;charset=UTF-8', 201 | }, 202 | }).json(); 203 | return body; 204 | }; -------------------------------------------------------------------------------- /utils/sendNotify.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # _*_ coding:utf-8 _*_ 3 | import base64 4 | import hashlib 5 | import hmac 6 | import json 7 | import os 8 | import re 9 | import threading 10 | import time 11 | import urllib.parse 12 | 13 | import requests 14 | 15 | # 原先的 print 函数和主线程的锁 16 | _print = print 17 | mutex = threading.Lock() 18 | 19 | 20 | # 定义新的 print 函数 21 | def print(text, *args, **kw): 22 | """ 23 | 使输出有序进行,不出现多线程同一时间输出导致错乱的问题。 24 | """ 25 | with mutex: 26 | _print(text, *args, **kw) 27 | 28 | 29 | # 通知服务 30 | # fmt: off 31 | push_config = { 32 | 'HITOKOTO': False, # 启用一言(随机句子) 33 | 34 | 'BARK_PUSH': '', # bark IP 或设备码,例:https://api.day.app/DxHcxxxxxRxxxxxxcm/ 35 | 'BARK_ARCHIVE': '', # bark 推送是否存档 36 | 'BARK_GROUP': '', # bark 推送分组 37 | 'BARK_SOUND': '', # bark 推送声音 38 | 39 | 'CONSOLE': True, # 控制台输出 40 | 41 | 'DD_BOT_SECRET': '', # 钉钉机器人的 DD_BOT_SECRET 42 | 'DD_BOT_TOKEN': '', # 钉钉机器人的 DD_BOT_TOKEN 43 | 44 | 'FSKEY': '', # 飞书机器人的 FSKEY 45 | 46 | 'GOBOT_URL': '', # go-cqhttp 47 | # 推送到个人QQ:http://127.0.0.1/send_private_msg 48 | # 群:http://127.0.0.1/send_group_msg 49 | 'GOBOT_QQ': '', # go-cqhttp 的推送群或用户 50 | # GOBOT_URL 设置 /send_private_msg 时填入 user_id=个人QQ 51 | # /send_group_msg 时填入 group_id=QQ群 52 | 'GOBOT_TOKEN': '', # go-cqhttp 的 access_token 53 | 54 | 'GOTIFY_URL': '', # gotify地址,如https://push.example.de:8080 55 | 'GOTIFY_TOKEN': '', # gotify的消息应用token 56 | 'GOTIFY_PRIORITY': 0, # 推送消息优先级,默认为0 57 | 58 | 'IGOT_PUSH_KEY': '', # iGot 聚合推送的 IGOT_PUSH_KEY 59 | 60 | 'PUSH_KEY': '', # server 酱的 PUSH_KEY,兼容旧版与 Turbo 版 61 | 62 | 'PUSH_PLUS_TOKEN': '', # push+ 微信推送的用户令牌 63 | 'PUSH_PLUS_USER': '', # push+ 微信推送的群组编码 64 | 65 | 'QMSG_KEY': '', # qmsg 酱的 QMSG_KEY 66 | 'QMSG_TYPE': '', # qmsg 酱的 QMSG_TYPE 67 | 68 | 'QYWX_AM': '', # 企业微信应用 69 | 70 | 'QYWX_KEY': '', # 企业微信机器人 71 | 72 | 'TG_BOT_TOKEN': '', # tg 机器人的 TG_BOT_TOKEN,例:1407203283:AAG9rt-6RDaaX0HBLZQq0laNOh898iFYaRQ 73 | 'TG_USER_ID': '', # tg 机器人的 TG_USER_ID,例:1434078534 74 | 'TG_API_HOST': '', # tg 代理 api 75 | 'TG_PROXY_AUTH': '', # tg 代理认证参数 76 | 'TG_PROXY_HOST': '', # tg 机器人的 TG_PROXY_HOST 77 | 'TG_PROXY_PORT': '', # tg 机器人的 TG_PROXY_PORT 78 | } 79 | notify_function = [] 80 | # fmt: on 81 | 82 | # 首先读取 面板变量 或者 github action 运行变量 83 | for k in push_config: 84 | if os.getenv(k): 85 | v = os.getenv(k) 86 | push_config[k] = v 87 | 88 | 89 | def bark(title: str, content: str) -> None: 90 | """ 91 | 使用 bark 推送消息。 92 | """ 93 | if not push_config.get("BARK_PUSH"): 94 | print("bark 服务的 BARK_PUSH 未设置!!\n取消推送") 95 | return 96 | print("bark 服务启动") 97 | 98 | if push_config.get("BARK_PUSH").startswith("http"): 99 | url = f'{push_config.get("BARK_PUSH")}/{urllib.parse.quote_plus(title)}/{urllib.parse.quote_plus(content)}' 100 | else: 101 | url = f'https://api.day.app/{push_config.get("BARK_PUSH")}/{urllib.parse.quote_plus(title)}/{urllib.parse.quote_plus(content)}' 102 | 103 | bark_params = { 104 | "BARK_ARCHIVE": "isArchive", 105 | "BARK_GROUP": "group", 106 | "BARK_SOUND": "sound", 107 | } 108 | params = "" 109 | for pair in filter( 110 | lambda pairs: pairs[0].startswith("BARK_") 111 | and pairs[0] != "BARK_PUSH" 112 | and pairs[1] 113 | and bark_params.get(pairs[0]), 114 | push_config.items(), 115 | ): 116 | params += f"{bark_params.get(pair[0])}={pair[1]}&" 117 | if params: 118 | url = url + "?" + params.rstrip("&") 119 | response = requests.get(url).json() 120 | 121 | if response["code"] == 200: 122 | print("bark 推送成功!") 123 | else: 124 | print("bark 推送失败!") 125 | 126 | 127 | def console(title: str, content: str) -> None: 128 | """ 129 | 使用 控制台 推送消息。 130 | """ 131 | print(f"{title}\n\n{content}") 132 | 133 | 134 | def dingding_bot(title: str, content: str) -> None: 135 | """ 136 | 使用 钉钉机器人 推送消息。 137 | """ 138 | if not push_config.get("DD_BOT_SECRET") or not push_config.get("DD_BOT_TOKEN"): 139 | print("钉钉机器人 服务的 DD_BOT_SECRET 或者 DD_BOT_TOKEN 未设置!!\n取消推送") 140 | return 141 | print("钉钉机器人 服务启动") 142 | 143 | timestamp = str(round(time.time() * 1000)) 144 | secret_enc = push_config.get("DD_BOT_SECRET").encode("utf-8") 145 | string_to_sign = "{}\n{}".format(timestamp, push_config.get("DD_BOT_SECRET")) 146 | string_to_sign_enc = string_to_sign.encode("utf-8") 147 | hmac_code = hmac.new( 148 | secret_enc, string_to_sign_enc, digestmod=hashlib.sha256 149 | ).digest() 150 | sign = urllib.parse.quote_plus(base64.b64encode(hmac_code)) 151 | url = f'https://oapi.dingtalk.com/robot/send?access_token={push_config.get("DD_BOT_TOKEN")}×tamp={timestamp}&sign={sign}' 152 | headers = {"Content-Type": "application/json;charset=utf-8"} 153 | data = {"msgtype": "text", "text": {"content": f"{title}\n\n{content}"}} 154 | response = requests.post( 155 | url=url, data=json.dumps(data), headers=headers, timeout=15 156 | ).json() 157 | 158 | if not response["errcode"]: 159 | print("钉钉机器人 推送成功!") 160 | else: 161 | print("钉钉机器人 推送失败!") 162 | 163 | 164 | def feishu_bot(title: str, content: str) -> None: 165 | """ 166 | 使用 飞书机器人 推送消息。 167 | """ 168 | if not push_config.get("FSKEY"): 169 | print("飞书 服务的 FSKEY 未设置!!\n取消推送") 170 | return 171 | print("飞书 服务启动") 172 | 173 | url = f'https://open.feishu.cn/open-apis/bot/v2/hook/{push_config.get("FSKEY")}' 174 | data = {"msg_type": "text", "content": {"text": f"{title}\n\n{content}"}} 175 | response = requests.post(url, data=json.dumps(data)).json() 176 | 177 | if response.get("StatusCode") == 0: 178 | print("飞书 推送成功!") 179 | else: 180 | print("飞书 推送失败!错误信息如下:\n", response) 181 | 182 | 183 | def go_cqhttp(title: str, content: str) -> None: 184 | """ 185 | 使用 go_cqhttp 推送消息。 186 | """ 187 | if not push_config.get("GOBOT_URL") or not push_config.get("GOBOT_QQ"): 188 | print("go-cqhttp 服务的 GOBOT_URL 或 GOBOT_QQ 未设置!!\n取消推送") 189 | return 190 | print("go-cqhttp 服务启动") 191 | 192 | url = f'{push_config.get("GOBOT_URL")}?access_token={push_config.get("GOBOT_TOKEN")}&{push_config.get("GOBOT_QQ")}&message=标题:{title}\n内容:{content}' 193 | response = requests.get(url).json() 194 | 195 | if response["status"] == "ok": 196 | print("go-cqhttp 推送成功!") 197 | else: 198 | print("go-cqhttp 推送失败!") 199 | 200 | 201 | def gotify(title:str,content:str) -> None: 202 | """ 203 | 使用 gotify 推送消息。 204 | """ 205 | if not push_config.get("GOTIFY_URL") or not push_config.get("GOTIFY_TOKEN"): 206 | print("gotify 服务的 GOTIFY_URL 或 GOTIFY_TOKEN 未设置!!\n取消推送") 207 | return 208 | print("gotify 服务启动") 209 | 210 | url = f'{push_config.get("GOTIFY_URL")}/message?token={push_config.get("GOTIFY_TOKEN")}' 211 | data = {"title": title,"message": content,"priority": push_config.get("GOTIFY_PRIORITY")} 212 | response = requests.post(url,data=data).json() 213 | 214 | if response.get("id"): 215 | print("gotify 推送成功!") 216 | else: 217 | print("gotify 推送失败!") 218 | 219 | 220 | def iGot(title: str, content: str) -> None: 221 | """ 222 | 使用 iGot 推送消息。 223 | """ 224 | if not push_config.get("IGOT_PUSH_KEY"): 225 | print("iGot 服务的 IGOT_PUSH_KEY 未设置!!\n取消推送") 226 | return 227 | print("iGot 服务启动") 228 | 229 | url = f'https://push.hellyw.com/{push_config.get("IGOT_PUSH_KEY")}' 230 | data = {"title": title, "content": content} 231 | headers = {"Content-Type": "application/x-www-form-urlencoded"} 232 | response = requests.post(url, data=data, headers=headers).json() 233 | 234 | if response["ret"] == 0: 235 | print("iGot 推送成功!") 236 | else: 237 | print(f'iGot 推送失败!{response["errMsg"]}') 238 | 239 | 240 | def serverJ(title: str, content: str) -> None: 241 | """ 242 | 通过 serverJ 推送消息。 243 | """ 244 | if not push_config.get("PUSH_KEY"): 245 | print("serverJ 服务的 PUSH_KEY 未设置!!\n取消推送") 246 | return 247 | print("serverJ 服务启动") 248 | 249 | data = {"text": title, "desp": content.replace("\n", "\n\n")} 250 | if push_config.get("PUSH_KEY").index("SCT") != -1: 251 | url = f'https://sctapi.ftqq.com/{push_config.get("PUSH_KEY")}.send' 252 | else: 253 | url = f'https://sc.ftqq.com/${push_config.get("PUSH_KEY")}.send' 254 | response = requests.post(url, data=data).json() 255 | 256 | if response.get("errno") == 0 or response.get("code") == 0: 257 | print("serverJ 推送成功!") 258 | else: 259 | print(f'serverJ 推送失败!错误码:{response["message"]}') 260 | 261 | 262 | def pushplus_bot(title: str, content: str) -> None: 263 | """ 264 | 通过 push+ 推送消息。 265 | """ 266 | if not push_config.get("PUSH_PLUS_TOKEN"): 267 | print("PUSHPLUS 服务的 PUSH_PLUS_TOKEN 未设置!!\n取消推送") 268 | return 269 | print("PUSHPLUS 服务启动") 270 | 271 | url = "http://www.pushplus.plus/send" 272 | data = { 273 | "token": push_config.get("PUSH_PLUS_TOKEN"), 274 | "title": title, 275 | "content": content, 276 | "topic": push_config.get("PUSH_PLUS_USER"), 277 | } 278 | body = json.dumps(data).encode(encoding="utf-8") 279 | headers = {"Content-Type": "application/json"} 280 | response = requests.post(url=url, data=body, headers=headers).json() 281 | 282 | if response["code"] == 200: 283 | print("PUSHPLUS 推送成功!") 284 | 285 | else: 286 | 287 | url_old = "http://pushplus.hxtrip.com/send" 288 | headers["Accept"] = "application/json" 289 | response = requests.post(url=url_old, data=body, headers=headers).json() 290 | 291 | if response["code"] == 200: 292 | print("PUSHPLUS(hxtrip) 推送成功!") 293 | 294 | else: 295 | print("PUSHPLUS 推送失败!") 296 | 297 | 298 | def qmsg_bot(title: str, content: str) -> None: 299 | """ 300 | 使用 qmsg 推送消息。 301 | """ 302 | if not push_config.get("QMSG_KEY") or not push_config.get("QMSG_TYPE"): 303 | print("qmsg 的 QMSG_KEY 或者 QMSG_TYPE 未设置!!\n取消推送") 304 | return 305 | print("qmsg 服务启动") 306 | 307 | url = f'https://qmsg.zendee.cn/{push_config.get("QMSG_TYPE")}/{push_config.get("QMSG_KEY")}' 308 | payload = {"msg": f'{title}\n\n{content.replace("----", "-")}'.encode("utf-8")} 309 | response = requests.post(url=url, params=payload).json() 310 | 311 | if response["code"] == 0: 312 | print("qmsg 推送成功!") 313 | else: 314 | print(f'qmsg 推送失败!{response["reason"]}') 315 | 316 | 317 | def wecom_app(title: str, content: str) -> None: 318 | """ 319 | 通过 企业微信 APP 推送消息。 320 | """ 321 | if not push_config.get("QYWX_AM"): 322 | print("QYWX_AM 未设置!!\n取消推送") 323 | return 324 | QYWX_AM_AY = re.split(",", push_config.get("QYWX_AM")) 325 | if 4 < len(QYWX_AM_AY) > 5: 326 | print("QYWX_AM 设置错误!!\n取消推送") 327 | return 328 | print("企业微信 APP 服务启动") 329 | 330 | corpid = QYWX_AM_AY[0] 331 | corpsecret = QYWX_AM_AY[1] 332 | touser = QYWX_AM_AY[2] 333 | agentid = QYWX_AM_AY[3] 334 | try: 335 | media_id = QYWX_AM_AY[4] 336 | except IndexError: 337 | media_id = "" 338 | wx = WeCom(corpid, corpsecret, agentid) 339 | # 如果没有配置 media_id 默认就以 text 方式发送 340 | if not media_id: 341 | message = title + "\n\n" + content 342 | response = wx.send_text(message, touser) 343 | else: 344 | response = wx.send_mpnews(title, content, media_id, touser) 345 | 346 | if response == "ok": 347 | print("企业微信推送成功!") 348 | else: 349 | print("企业微信推送失败!错误信息如下:\n", response) 350 | 351 | 352 | class WeCom: 353 | def __init__(self, corpid, corpsecret, agentid): 354 | self.CORPID = corpid 355 | self.CORPSECRET = corpsecret 356 | self.AGENTID = agentid 357 | 358 | def get_access_token(self): 359 | url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken" 360 | values = { 361 | "corpid": self.CORPID, 362 | "corpsecret": self.CORPSECRET, 363 | } 364 | req = requests.post(url, params=values) 365 | data = json.loads(req.text) 366 | return data["access_token"] 367 | 368 | def send_text(self, message, touser="@all"): 369 | send_url = ( 370 | "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" 371 | + self.get_access_token() 372 | ) 373 | send_values = { 374 | "touser": touser, 375 | "msgtype": "text", 376 | "agentid": self.AGENTID, 377 | "text": {"content": message}, 378 | "safe": "0", 379 | } 380 | send_msges = bytes(json.dumps(send_values), "utf-8") 381 | respone = requests.post(send_url, send_msges) 382 | respone = respone.json() 383 | return respone["errmsg"] 384 | 385 | def send_mpnews(self, title, message, media_id, touser="@all"): 386 | send_url = ( 387 | "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" 388 | + self.get_access_token() 389 | ) 390 | send_values = { 391 | "touser": touser, 392 | "msgtype": "mpnews", 393 | "agentid": self.AGENTID, 394 | "mpnews": { 395 | "articles": [ 396 | { 397 | "title": title, 398 | "thumb_media_id": media_id, 399 | "author": "Author", 400 | "content_source_url": "", 401 | "content": message.replace("\n", "
"), 402 | "digest": message, 403 | } 404 | ] 405 | }, 406 | } 407 | send_msges = bytes(json.dumps(send_values), "utf-8") 408 | respone = requests.post(send_url, send_msges) 409 | respone = respone.json() 410 | return respone["errmsg"] 411 | 412 | 413 | def wecom_bot(title: str, content: str) -> None: 414 | """ 415 | 通过 企业微信机器人 推送消息。 416 | """ 417 | if not push_config.get("QYWX_KEY"): 418 | print("企业微信机器人 服务的 QYWX_KEY 未设置!!\n取消推送") 419 | return 420 | print("企业微信机器人服务启动") 421 | 422 | url = f"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={push_config.get('QYWX_KEY')}" 423 | headers = {"Content-Type": "application/json;charset=utf-8"} 424 | data = {"msgtype": "text", "text": {"content": f"{title}\n\n{content}"}} 425 | response = requests.post( 426 | url=url, data=json.dumps(data), headers=headers, timeout=15 427 | ).json() 428 | 429 | if response["errcode"] == 0: 430 | print("企业微信机器人推送成功!") 431 | else: 432 | print("企业微信机器人推送失败!") 433 | 434 | 435 | def telegram_bot(title: str, content: str) -> None: 436 | """ 437 | 使用 telegram 机器人 推送消息。 438 | """ 439 | if not push_config.get("TG_BOT_TOKEN") or not push_config.get("TG_USER_ID"): 440 | print("tg 服务的 bot_token 或者 user_id 未设置!!\n取消推送") 441 | return 442 | print("tg 服务启动") 443 | 444 | if push_config.get("TG_API_HOST"): 445 | url = f"https://{push_config.get('TG_API_HOST')}/bot{push_config.get('TG_BOT_TOKEN')}/sendMessage" 446 | else: 447 | url = ( 448 | f"https://api.telegram.org/bot{push_config.get('TG_BOT_TOKEN')}/sendMessage" 449 | ) 450 | headers = {"Content-Type": "application/x-www-form-urlencoded"} 451 | payload = { 452 | "chat_id": str(push_config.get("TG_USER_ID")), 453 | "text": f"{title}\n\n{content}", 454 | "disable_web_page_preview": "true", 455 | } 456 | proxies = None 457 | if push_config.get("TG_PROXY_HOST") and push_config.get("TG_PROXY_PORT"): 458 | if push_config.get("TG_PROXY_AUTH") is not None and "@" not in push_config.get( 459 | "TG_PROXY_HOST" 460 | ): 461 | push_config["TG_PROXY_HOST"] = ( 462 | push_config.get("TG_PROXY_AUTH") 463 | + "@" 464 | + push_config.get("TG_PROXY_HOST") 465 | ) 466 | proxyStr = "http://{}:{}".format( 467 | push_config.get("TG_PROXY_HOST"), push_config.get("TG_PROXY_PORT") 468 | ) 469 | proxies = {"http": proxyStr, "https": proxyStr} 470 | response = requests.post( 471 | url=url, headers=headers, params=payload, proxies=proxies 472 | ).json() 473 | 474 | if response["ok"]: 475 | print("tg 推送成功!") 476 | else: 477 | print("tg 推送失败!") 478 | 479 | 480 | def one() -> str: 481 | """ 482 | 获取一条一言。 483 | :return: 484 | """ 485 | url = "https://v1.hitokoto.cn/" 486 | res = requests.get(url).json() 487 | return res["hitokoto"] + " ----" + res["from"] 488 | 489 | 490 | if push_config.get("BARK_PUSH"): 491 | notify_function.append(bark) 492 | if push_config.get("CONSOLE"): 493 | notify_function.append(console) 494 | if push_config.get("DD_BOT_TOKEN") and push_config.get("DD_BOT_SECRET"): 495 | notify_function.append(dingding_bot) 496 | if push_config.get("FSKEY"): 497 | notify_function.append(feishu_bot) 498 | if push_config.get("GOBOT_URL") and push_config.get("GOBOT_QQ"): 499 | notify_function.append(go_cqhttp) 500 | if push_config.get("GOTIFY_URL") and push_config.get("GOTIFY_TOKEN"): 501 | notify_function.append(gotify) 502 | if push_config.get("IGOT_PUSH_KEY"): 503 | notify_function.append(iGot) 504 | if push_config.get("PUSH_KEY"): 505 | notify_function.append(serverJ) 506 | if push_config.get("PUSH_PLUS_TOKEN"): 507 | notify_function.append(pushplus_bot) 508 | if push_config.get("QMSG_KEY") and push_config.get("QMSG_TYPE"): 509 | notify_function.append(qmsg_bot) 510 | if push_config.get("QYWX_AM"): 511 | notify_function.append(wecom_app) 512 | if push_config.get("QYWX_KEY"): 513 | notify_function.append(wecom_bot) 514 | if push_config.get("TG_BOT_TOKEN") and push_config.get("TG_USER_ID"): 515 | notify_function.append(telegram_bot) 516 | 517 | 518 | def send(title: str, content: str) -> None: 519 | if not content: 520 | print(f"{title} 推送内容为空!") 521 | return 522 | 523 | hitokoto = push_config.get("HITOKOTO") 524 | 525 | text = one() if hitokoto else "" 526 | content += "\n\n" + text 527 | 528 | ts = [ 529 | threading.Thread(target=mode, args=(title, content), name=mode.__name__) 530 | for mode in notify_function 531 | ] 532 | [t.start() for t in ts] 533 | [t.join() for t in ts] 534 | 535 | 536 | def main(): 537 | send("title", "content") 538 | 539 | 540 | if __name__ == "__main__": 541 | main() 542 | --------------------------------------------------------------------------------