From e0914c5caf7b5384a77457db83b3968c462b56fd Mon Sep 17 00:00:00 2001
From: Faker <Faker@apple.com>
Date: Fri, 6 May 2022 10:56:11 +0800
Subject: [PATCH] update

---
 jd_19_5.js                 |    2 +-
 jd_dpqd.js                 |   16 +-
 jd_m_sign.js               |    5 +-
 jd_wskey.py                |   76 +--
 m_jd_farm_automation.js    |   79 +++
 m_jd_follow_shop.js        |  125 +++++
 m_jd_pet_automation.js     |   64 +++
 m_jd_wx_addCart.js         |  182 +++++++
 m_jd_wx_collectCard.js     |  241 +++++++++
 m_jd_wx_luckDraw.js        |  231 +++++++++
 m_jx_factory_automation.js |  326 ++++++++++++
 m_jx_factory_commodity.js  |   97 ++++
 magic.js                   | 1002 ++++++++++++++++++++++++++++++++++++
 magic.json                 |   15 +
 magic.py                   |  191 +++++++
 mount.sh                   |    8 +
 test.js                    |   34 ++
 17 files changed, 2648 insertions(+), 46 deletions(-)
 create mode 100644 m_jd_farm_automation.js
 create mode 100644 m_jd_follow_shop.js
 create mode 100644 m_jd_pet_automation.js
 create mode 100644 m_jd_wx_addCart.js
 create mode 100644 m_jd_wx_collectCard.js
 create mode 100644 m_jd_wx_luckDraw.js
 create mode 100644 m_jx_factory_automation.js
 create mode 100644 m_jx_factory_commodity.js
 create mode 100644 magic.js
 create mode 100644 magic.json
 create mode 100644 magic.py
 create mode 100644 mount.sh
 create mode 100644 test.js

diff --git a/jd_19_5.js b/jd_19_5.js
index 9ef001a..832e68a 100644
--- a/jd_19_5.js
+++ b/jd_19_5.js
@@ -20,7 +20,7 @@ const notify = $.isNode() ? require('./sendNotify') : '';
 //Node.js用户请在jdCookie.js处填写京东ck;
 const jdCookieNode = $.isNode() ? require('./jdCookie.js') : '';
 let jdNotify = true;//是否关闭通知,false打开通知推送,true关闭通知推送
-const randomCount = $.isNode() ? 30 : 5;
+const randomCount = $.isNode() ? 20 : 5;
 //IOS等用户直接用NobyDa的jd cookie
 let cookiesArr = [], cookie = '', message;
 if ($.isNode()) {
diff --git a/jd_dpqd.js b/jd_dpqd.js
index 66aff27..7bc0297 100644
--- a/jd_dpqd.js
+++ b/jd_dpqd.js
@@ -26,13 +26,13 @@ let num=0
 let shopname=''
 const token = [
   "80E78A5F090820E5B1754E17E1485D3F",
-  "B3E1665D2154B1CCF6FA036F53D28707",
+  "2DACD1FEDEB92BEEDBD54E6B926798B1",
   "02BC0ECE5C47F27DD21BEBB0B0DFDB88",
   "A0D5832C2A4A942DBFBC0816BA6691C8",
   "7127A3861F6478043B1BF112803B9A25",
   "7C513EAE76DCB43D86E0C64762719976",
   "D88BAFF737E9C4295F973732214F5DE5",
-  "3C40932565A6F6E69237E17773D907AA",
+  "A36F8FDDB5C64DE89061B7DA331E4874",
   "63F7C22BEBF3EB981821C9188C8EB8EE",
   "FE30AB00038CFFEF00DA9E9B8E932721",
   "F0C24D7588D90922393B423C6623F31A",
@@ -44,7 +44,17 @@ const token = [
   "37C465E26FCFFCFC72B991036CBC6A79",
   "7C071F9A6D11D5F26B83CF6BB91D2E89",
   "3D2F9CF0C806133D3C64949F06CD4A80",
-  "19FC5C93948E015ED82F4740299F95FD"
+  "19FC5C93948E015ED82F4740299F95FD",
+  "868B5F6062E5DD77D3F024EDA1AA94E0",
+  "F26AB04CFB9DA6CC14F40A355E1709DE",
+  "902F208E5868474EE70F3C40BB16F4A2",
+  "CFE83CA731BB8B8395C1016BE7498F7A",
+  "C857A8790C474AB23764165EA056A20E",
+  "351154FDCFF09CD4406A0A9D6FF8B216",
+  "306D23886F4C74F3A44897D06AAEBE2C",
+  "1DF38A60E4FCB9C461B7B68548C75EC1",
+  "99B695DFEF69DD31BB78B58D61B9C6A2",
+  "EBC07F65183699ABACF313CA67B444E4"
 ]
 
 if ($.isNode()) {
diff --git a/jd_m_sign.js b/jd_m_sign.js
index 638ba6d..fd2f1e5 100644
--- a/jd_m_sign.js
+++ b/jd_m_sign.js
@@ -67,12 +67,9 @@ async function jdsign() {
     await $.wait(2000)
     await getInfo("https://pro.m.jd.com/mall/active/kPM3Xedz1PBiGQjY4ZYGmeVvrts/index.html");//陪伴
     await $.wait(2000)
-    //await getInfo("https://pro.m.jd.com/mall/active/3SC6rw5iBg66qrXPGmZMqFDwcyXi/index.html");//京东图书
-    //await $.wait(2000)
-    await getInfo("https://prodev.m.jd.com/mall/active/hPJiMgUQmc34bamrApLUBRUy82W/index.html");//4.3结束   
+    await getInfo("https://prodev.m.jd.com/mall/active/2BspupMr6qenk9JUWpbAnepLHjwy/index.html");//女装馆6.30
     await $.wait(2000)
     await getInfo("https://prodev.m.jd.com/mall/active/2FzVtkSfUtvU8YoiTeALkJ68PxAs/index.html");//医疗馆 12.31结束	
-//     await getInfo("https://pro.m.jd.com/mall/active/ZrH7gGAcEkY2gH8wXqyAPoQgk6t/index.html");//箱包签到
 //     await $.wait(1000)
 //     await getInfo("https://pro.m.jd.com/mall/active/4RXyb1W4Y986LJW8ToqMK14BdTD/index.html");//鞋靴馆签到
 
diff --git a/jd_wskey.py b/jd_wskey.py
index af6e88e..3518ab3 100644
--- a/jd_wskey.py
+++ b/jd_wskey.py
@@ -32,7 +32,15 @@ except Exception as err:  # 异常捕捉
     logger.debug(str(err))  # 调试日志输出
     logger.info("无推送文件")  # 标准日志输出
 
-ver = 20413  # 版本号
+ver = 20505  # 版本号
+
+
+def ql_send(text):
+    try:  # 异常捕捉
+        send('WSKEY转换', text)  # 消息发送
+    except Exception as err:  # 异常捕捉
+        logger.debug(str(err))  # Debug日志输出
+        logger.info("通知发送失败")  # 标准日志输出
 
 
 # 登录青龙 返回值 token
@@ -50,7 +58,13 @@ def get_qltoken(username, password):  # 方法 用于获取青龙 Token
     }  # HTTP请求头 设置为 Json格式
     try:  # 异常捕捉
         res = requests.post(url=url, headers=headers, data=payload)  # 使用 requests模块进行 HTTP POST请求
-        token = json.loads(res.text)["data"]['token']  # 从 res.text 返回值中 取出 Token值
+        if res.status_code == 200 and res.json()["code"] == 200:
+            token = res.json()["data"]['token']  # 从 res.text 返回值中 取出 Token值
+            return token
+        else:
+            logger.info("暂未兼容两步验证")
+            ql_send("青龙登录失败, 请检查是否开启两步验证 脚本暂未兼容两步验证")
+            sys.exit(1)  # 脚本退出
     except Exception as err:
         logger.debug(str(err))  # Debug日志输出
         logger.info("使用旧版青龙登录接口")
@@ -70,17 +84,12 @@ def get_qltoken(username, password):  # 方法 用于获取青龙 Token
         except Exception as err:  # 异常捕捉
             logger.debug(str(err))  # Debug日志输出
             logger.info("青龙登录失败, 请检查面板状态!")  # 标准日志输出
-            text = '青龙面板WSKEY转换登陆面板失败, 请检查面板状态.'  # 设置推送内容
-            try:  # 异常捕捉
-                send('WSKEY转换', text)  # 消息发送
-            except Exception as err:  # 异常捕捉
-                logger.debug(str(err))  # Debug日志输出
-                logger.info("通知发送失败")  # 标准日志输出
+            ql_send('青龙登陆失败, 请检查面板状态.')
             sys.exit(1)  # 脚本退出
         else:  # 无异常执行分支
             return token  # 返回 token值
-    else:  # 无异常执行分支
-        return token  # 返回 token值
+    # else:  # 无异常执行分支
+    #     return token  # 返回 token值
 
 
 # 返回值 Token
@@ -137,7 +146,7 @@ def get_ck():  # 方法 获取 JD_COOKIE值 [系统变量传递] <! 此方法未
         else:  # 判断分支
             logger.info("JD_COOKIE变量未启用")  # 标准日志输出
             sys.exit(1)  # 脚本退出
-    else:   # 判断分支
+    else:  # 判断分支
         logger.info("未添加JD_COOKIE变量")  # 标准日志输出
         sys.exit(0)  # 脚本退出
 
@@ -156,7 +165,7 @@ def check_ck(ck):  # 方法 检查 Cookie有效性 使用变量传递 单次调
         nowTime = time.time()  # 获取时间戳 赋值
         updatedAt = 0.0  # 赋值
         searchObj = re.search(r'__time=([^;\s]+)', ck, re.M | re.I)  # 正则检索 [__time=]
-        if searchObj:   # 真值判断
+        if searchObj:  # 真值判断
             updatedAt = float(searchObj.group(1))  # 取值 [float]类型
         if nowTime - updatedAt >= (updateHour * 60 * 60) - (10 * 60):  # 判断时间操作
             logger.info(str(pin) + ";即将到期或已过期\n")  # 标准日志输出
@@ -182,7 +191,7 @@ def check_ck(ck):  # 方法 检查 Cookie有效性 使用变量传递 单次调
         except Exception as err:  # 异常捕捉
             logger.debug(str(err))  # 调试日志输出
             logger.info("JD接口错误 请重试或者更换IP")  # 标准日志输出
-            return False   # 返回 Bool类型 False
+            return False  # 返回 Bool类型 False
         else:  # 判断分支
             if res.status_code == 200:  # 判断 JD_API 接口是否为 200 [HTTP_OK]
                 code = int(json.loads(res.text)['retcode'])  # 使用 Json模块对返回数据取值 int([retcode])
@@ -217,13 +226,14 @@ def getToken(wskey):  # 方法 获取 Wskey转换使用的 Token 由 JD_API 返
     url = 'https://api.m.jd.com/client.action'  # 设置 URL地址
     data = 'body=%7B%22to%22%3A%22https%253a%252f%252fplogin.m.jd.com%252fjd-mlogin%252fstatic%252fhtml%252fappjmp_blank.html%22%7D&'  # 设置 POST 载荷
     try:  # 异常捕捉
-        res = requests.post(url=url, params=params, headers=headers, data=data, verify=False, timeout=10)  # HTTP请求 [POST] 超时 10秒
+        res = requests.post(url=url, params=params, headers=headers, data=data, verify=False,
+                            timeout=10)  # HTTP请求 [POST] 超时 10秒
         res_json = json.loads(res.text)  # Json模块 取值
         tokenKey = res_json['tokenKey']  # 取出TokenKey
     except Exception as err:  # 异常捕捉
         logger.info("JD_WSKEY接口抛出错误 尝试重试 更换IP")  # 标准日志输出
         logger.info(str(err))  # 标注日志输出
-        return False, wskey   # 返回 -> False[Bool], Wskey
+        return False, wskey  # 返回 -> False[Bool], Wskey
     else:  # 判断分支
         return appjmp(wskey, tokenKey)  # 传递 wskey, Tokenkey 执行方法 [appjmp]
 
@@ -245,7 +255,8 @@ def appjmp(wskey, tokenKey):  # 方法 传递 wskey & tokenKey
     }  # 设置 HTTP_URL 参数
     url = 'https://un.m.jd.com/cgi-bin/app/appjmp'  # 设置 URL地址
     try:  # 异常捕捉
-        res = requests.get(url=url, headers=headers, params=params, verify=False, allow_redirects=False, timeout=20)  # HTTP请求 [GET] 阻止跳转 超时 20秒
+        res = requests.get(url=url, headers=headers, params=params, verify=False, allow_redirects=False,
+                           timeout=20)  # HTTP请求 [GET] 阻止跳转 超时 20秒
     except Exception as err:  # 异常捕捉
         logger.info("JD_appjmp 接口错误 请重试或者更换IP\n")  # 标准日志输出
         logger.info(str(err))  # 标准日志输出
@@ -273,20 +284,16 @@ def appjmp(wskey, tokenKey):  # 方法 传递 wskey & tokenKey
 
 
 def update():  # 方法 脚本更新模块
-    up_ver = int(cloud_arg['update'])   # 云端参数取值 [int]
+    up_ver = int(cloud_arg['update'])  # 云端参数取值 [int]
     if ver >= up_ver:  # 判断版本号大小
         logger.info("当前脚本版本: " + str(ver))  # 标准日志输出
         logger.info("--------------------\n")  # 标准日志输出
     else:  # 判断分支
-        logger.info("当前脚本版本: " + str(ver) + "新版本: " + str(up_ver))   # 标准日志输出
+        logger.info("当前脚本版本: " + str(ver) + "新版本: " + str(up_ver))  # 标准日志输出
         logger.info("存在新版本, 请更新脚本后执行")  # 标准日志输出
         logger.info("--------------------\n")  # 标准日志输出
         text = '当前脚本版本: {0}新版本: {1}, 请更新脚本~!'.format(ver, up_ver)  # 设置发送内容
-        try:  # 异常捕捉
-            send('WSKEY转换', text)  # 推送消息
-        except Exception as err:  # 异常捕捉
-            logger.debug(str(err))  # 调试日志输出
-            logger.info("通知发送失败")  # 标准日志输出
+        ql_send(text)
         # sys.exit(0)  # 退出脚本 [未启用]
 
 
@@ -386,7 +393,7 @@ def ql_disable(e_id):  # 方法 青龙变量禁用 传递 eid
 
 
 def ql_insert(i_ck):  # 方法 插入新变量
-    data = [{"value": i_ck, "name": "JD_COOKIE"}]    # POST数据载荷组合
+    data = [{"value": i_ck, "name": "JD_COOKIE"}]  # POST数据载荷组合
     data = json.dumps(data)  # Json格式化数据
     url = 'http://127.0.0.1:{0}/api/envs'.format(port)  # 设置 URL地址
     s.post(url=url, data=data)  # HTTP[POST]请求 使用session
@@ -404,7 +411,7 @@ def cloud_info():  # 方法 云端信息
             time.sleep(1)  # 休眠 1秒
             continue  # 循环继续
         except requests.exceptions.ReadTimeout:  # 异常捕捉
-            logger.info("\n获取云端参数超时, 正在重试!" + str(i))   # 标准日志输出
+            logger.info("\n获取云端参数超时, 正在重试!" + str(i))  # 标准日志输出
             time.sleep(1)  # 休眠 1秒
             continue  # 循环继续
         except Exception as err:  # 异常捕捉
@@ -423,7 +430,8 @@ def cloud_info():  # 方法 云端信息
 
 
 def check_cloud():  # 方法 云端地址检查
-    url_list = ['aHR0cDovLzQzLjEzNS45MC4yMy8=', 'aHR0cHM6Ly9zaGl6dWt1Lm1sLw==', 'aHR0cHM6Ly9jZi5zaGl6dWt1Lm1sLw==']  # URL list Encode
+    url_list = ['aHR0cDovLzQzLjEzNS45MC4yMy8=', 'aHR0cHM6Ly9zaGl6dWt1Lm1sLw==',
+                'aHR0cHM6Ly9jZi5zaGl6dWt1Lm1sLw==']  # URL list Encode
     for i in url_list:  # for循环 url_list
         url = str(base64.b64decode(i).decode())  # 设置 url地址 [str]
         try:  # 异常捕捉
@@ -436,11 +444,7 @@ def check_cloud():  # 方法 云端地址检查
             logger.info(str(info[url_list.index(i)]) + " Server Check OK\n--------------------\n")  # 标准日志输出
             return i  # 返回 ->i
     logger.info("\n云端地址全部失效, 请检查网络!")  # 标准日志输出
-    try:  # 异常捕捉
-        send('WSKEY转换', '云端地址失效. 请联系作者或者检查网络.')  # 推送消息
-    except Exception as err:  # 异常捕捉
-        logger.debug(str(err))  # 调试日志输出
-        logger.info("通知发送失败")  # 标准日志输出
+    ql_send('云端地址失效. 请联系作者或者检查网络.')  # 推送消息
     sys.exit(1)  # 脚本退出
 
 
@@ -465,7 +469,7 @@ def check_port():  # 方法 检查变量传递端口
         return port  # 返回->port
 
 
-if __name__ == '__main__':   # Python主函数执行入口
+if __name__ == '__main__':  # Python主函数执行入口
     port = check_port()  # 调用方法 [check_port]  并赋值 [port]
     token = ql_login()  # 调用方法 [ql_login]  并赋值 [token]
     s = requests.session()  # 设置 request session方法
@@ -505,7 +509,7 @@ if __name__ == '__main__':   # Python主函数执行入口
                     if return_ws[0]:  # 判断 [return_ws]返回值 Bool类型
                         nt_key = str(return_ws[1])  # 从 return_ws[1] 取出 -> nt_key
                         # logger.info("wskey转pt_key成功", nt_key)  # 标准日志输出 [未启用]
-                        logger.info("wskey转换成功")   # 标准日志输出
+                        logger.info("wskey转换成功")  # 标准日志输出
                         eid = return_serch[2]  # 从 return_serch 拿到 eid
                         ql_update(eid, nt_key)  # 函数 ql_update 参数 eid JD_COOKIE
                     else:  # 判断分支
@@ -517,11 +521,7 @@ if __name__ == '__main__':   # Python主函数执行入口
                             logger.info(str(wspin) + "账号禁用")  # 标准日志输出
                             ql_disable(eid)  # 执行方法[ql_disable] 传递 eid
                             text = "账号: {0} WsKey疑似失效, 已禁用Cookie".format(wspin)  # 设置推送内容
-                        try:  # 异常捕捉
-                            send('WsKey转换脚本', text)  # 推送消息
-                        except Exception as err:  # 异常捕捉
-                            logger.debug(str(err))  # 调试日志输出
-                            logger.info("通知发送失败")  # 标准日志输出
+                            ql_send(text)
                 else:  # 判断分支
                     logger.info(str(wspin) + "账号有效")  # 标准日志输出
                     eid = return_serch[2]  # 读取 return_serch[2] -> eid
diff --git a/m_jd_farm_automation.js b/m_jd_farm_automation.js
new file mode 100644
index 0000000..cb15171
--- /dev/null
+++ b/m_jd_farm_automation.js
@@ -0,0 +1,79 @@
+//20 5,12,21 * * * m_jd_farm_automation.js
+//问题反馈:https://t.me/Wall_E_Channel
+const {Env} = require('./magic');
+const $ = new Env('M农场自动化');
+let level = process.env.M_JD_FARM_LEVEL ? process.env.M_JD_FARM_LEVEL * 1 : 2
+$.log('默认种植2级种子,自行配置请配置 M_JD_FARM_LEVEL')
+$.logic = async function () {
+    let info = await api('initForFarm',
+        {"version": 11, "channel": 3, "babelChannel": 0});
+    $.log(JSON.stringify(info));
+    if (!info?.farmUserPro?.treeState) {
+        $.log('可能没玩农场')
+    }
+    if (info.farmUserPro.treeState === 1) {
+        return
+    }
+    if (info.farmUserPro.treeState === 2) {
+        await $.wait(1000, 3000)
+        $.log(`${info.farmUserPro.name},种植时间:${$.formatDate(
+            info.farmUserPro.createTime)}`);
+        //成熟了
+        let coupon = await api('gotCouponForFarm',
+            {"version": 11, "channel": 3, "babelChannel": 0});
+        $.log(coupon)
+        info = await api('initForFarm',
+            {"version": 11, "channel": 3, "babelChannel": 0});
+    }
+    if (info.farmUserPro.treeState !== 3) {
+        return
+    }
+    let hongBao = info.myHongBaoInfo.hongBao;
+    $.putMsg(`${hongBao.discount}红包,${$.formatDate(hongBao.endTime)}过期`)
+    let element = info.farmLevelWinGoods[level][0];
+    await $.wait(1000, 3000)
+    info = await api('choiceGoodsForFarm', {
+        "imageUrl": '',
+        "nickName": '',
+        "shareCode": '',
+        "goodsType": element.type,
+        "type": "0",
+        "version": 11,
+        "channel": 3,
+        "babelChannel": 0
+    });
+    if (info.code * 1 === 0) {
+        $.putMsg(`已种【${info.farmUserPro.name}】`)
+    }
+    await api('gotStageAwardForFarm',
+        {"type": "4", "version": 11, "channel": 3, "babelChannel": 0});
+    await api('waterGoodForFarm',
+        {"type": "", "version": 11, "channel": 3, "babelChannel": 0});
+    await api('gotStageAwardForFarm',
+        {"type": "1", "version": 11, "channel": 3, "babelChannel": 0});
+};
+
+$.run({
+    wait: [20000, 30000], whitelist: ['1-15']
+}).catch(
+    reason => $.log(reason));
+
+// noinspection DuplicatedCode
+async function api(fn, body) {
+    let url = `https://api.m.jd.com/client.action?functionId=${fn}&body=${JSON.stringify(
+        body)}&client=apple&clientVersion=10.0.4&osVersion=13.7&appid=wh5&loginType=2&loginWQBiz=interact`
+//↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓请求头↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
+    let headers = {
+        "Cookie": $.cookie,
+        "Connection": "keep-alive",
+        "Accept": "*/*",
+        "Host": "api.m.jd.com",
+        'User-Agent': `Mozilla/5.0 (iPhone; CPU iPhone OS 14_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.4(0x1800042c) NetType/4G Language/zh_CN miniProgram`,
+        "Accept-Encoding": "gzip, deflate, br",
+        "Accept-Language": "zh-cn"
+    }
+    let {data} = await $.request(url, headers)
+    await $.wait(1000, 3000)
+    return data;
+}
+
diff --git a/m_jd_follow_shop.js b/m_jd_follow_shop.js
new file mode 100644
index 0000000..8475aa3
--- /dev/null
+++ b/m_jd_follow_shop.js
@@ -0,0 +1,125 @@
+/*
+7 7 7 7 7 m_jd_follow_shop.js
+*/
+let mode = __dirname.includes('magic')
+const {Env} = mode ? require('./magic') : require('./magic')
+const $ = new Env('M关注有礼');
+$.followShopArgv = process.env.M_FOLLOW_SHOP_ARGV
+    ? process.env.M_FOLLOW_SHOP_ARGV
+    : '';
+if (mode) {
+    $.followShopArgv = '1000104168_1000104168'
+}
+$.logic = async function () {
+    let argv = $?.followShopArgv?.split('_');
+    $.shopId = argv?.[0];
+    $.venderId = argv?.[1];
+    if (!$.shopId || !$.venderId) {
+        $.log(`无效的参数${$.followShopArgv}`)
+        $.expire = true;
+        return
+    }
+    let actInfo = await getShopHomeActivityInfo();
+    if (actInfo?.code !== '0') {
+        $.log(JSON.stringify(actInfo))
+        if (actInfo?.message.includes('不匹配')) {
+            $.expire = true;
+        }
+        return
+    }
+    let actInfoData = actInfo?.result;
+
+    if (actInfoData?.shopGifts?.filter(o => o.rearWord.includes('京豆')).length
+        > 0) {
+        $.activityId = actInfoData?.activityId?.toString();
+        let gift = await drawShopGift();
+        if (gift?.code !== '0') {
+            $.log(JSON.stringify(gift))
+            return
+        }
+        let giftData = gift?.result;
+        $.log(giftData)
+        for (let ele of
+        giftData?.alreadyReceivedGifts?.filter(o => o.prizeType === 4) || []) {
+            $.putMsg(`${ele.redWord}${ele.rearWord}`);
+        }
+    } else {
+        $.putMsg(`没有豆子`);
+    }
+};
+let kv = {'jd': '京豆', 'jf': '积分', 'dq': 'q券'}
+$.after = async function () {
+    $.msg.push(`\n${(await $.getShopInfo()).shopName}`);
+    if ($?.content) {
+        let message = `\n`;
+        for (let ele of $.content || []) {
+            message += `    ${ele.takeNum || ele.discount} ${kv[ele?.type]}\n`
+        }
+        $.msg.push(message)
+        $.msg.push($.activityUrl);
+    }
+}
+$.run({whitelist: ['1-5'], wait: [1000, 3000]}).catch(reason => $.log(reason))
+
+async function drawShopGift() {
+    $.log('店铺信息', $.shopId, $.venderId, $.activityId)
+    let sb = {
+        "follow": 0,
+        "shopId": $.shopId,
+        "activityId": $.activityId,
+        "sourceRpc": "shop_app_home_window",
+        "venderId": $.venderId
+    };
+    let newVar = await $.sign('drawShopGift', sb);
+
+    let headers = {
+        'J-E-H': '',
+        'Connection': 'keep-alive',
+        'Accept-Encoding': 'gzip, deflate, br',
+        'Content-Type': 'application/x-www-form-urlencoded',
+        'Host': 'api.m.jd.com',
+        'Referer': '',
+        'J-E-C': '',
+        'Accept-Language': 'zh-Hans-CN;q=1, en-CN;q=0.9',
+        'Accept': '*/*',
+        'User-Agent': 'JD4iPhone/167841 (iPhone; iOS; Scale/3.00)'
+    }
+    // noinspection DuplicatedCode
+    headers['Cookie'] = $.cookie
+    let url = `https://api.m.jd.com/client.action?functionId=` + newVar.fn
+    let {status, data} = await $.request(url, headers, newVar.sign);
+    return data;
+}
+
+async function getShopHomeActivityInfo() {
+    let sb = {
+        "shopId": $.shopId,
+        "source": "app-shop",
+        "latWs": "0",
+        "lngWs": "0",
+        "displayWidth": "1098.000000",
+        "sourceRpc": "shop_app_home_home",
+        "lng": "0",
+        "lat": "0",
+        "venderId": $.venderId
+    }
+    let newVar = await $.sign('getShopHomeActivityInfo', sb);
+    let headers = {
+        'J-E-H': '',
+        'Connection': 'keep-alive',
+        'Accept-Encoding': 'gzip, deflate, br',
+        'Content-Type': 'application/x-www-form-urlencoded',
+        'Host': 'api.m.jd.com',
+        'Referer': '',
+        'J-E-C': '',
+        'Accept-Language': 'zh-Hans-CN;q=1, en-CN;q=0.9',
+        'Accept': '*/*',
+        'User-Agent': 'JD4iPhone/167841 (iPhone; iOS; Scale/3.00)'
+    }
+    // noinspection DuplicatedCode
+    headers['Cookie'] = $.cookie
+    let url = `https://api.m.jd.com/client.action?functionId=` + newVar.fn
+    let {status, data} = await $.request(url, headers, newVar.sign);
+    return data;
+}
+
diff --git a/m_jd_pet_automation.js b/m_jd_pet_automation.js
new file mode 100644
index 0000000..1640c0f
--- /dev/null
+++ b/m_jd_pet_automation.js
@@ -0,0 +1,64 @@
+//40 5,12,21 * * * m_jd_pet_automation.js
+//问题反馈:https://t.me/Wall_E_Channel
+const {Env} = require('./magic');
+const $ = new Env('M萌宠自动化');
+let commodityName = process.env.M_JD_PET_COMMODITY
+    ? process.env.M_JD_PET_COMMODITY
+    : ''
+$.log('默认4级商品,生产指定商品请自行配置 M_JD_PET_COMMODITY')
+$.logic = async function () {
+    let info = await api('initPetTown', {"version": 1});
+    $.log(JSON.stringify(info));
+    debugger
+    if (info?.result?.petStatus < 5) {
+        return
+    }
+    if (info?.result?.petStatus === 5) {
+        $.log(info?.result?.goodsInfo);
+        let activityId = info?.result?.goodsInfo.activityId;
+        let activityIds = info?.result?.goodsInfo.activityIds;
+        let data = await api('redPacketExchange',
+            {"activityId": activityId, "activityIds": activityIds});
+        $.putMsg(`${info?.result?.goodsInfo.exchangeMedalNum === 4 ? '12'
+            : '25'}红包,${$.formatDate(
+            $.timestamp() + data.result.pastDays * 24 * 60 * 60 * 1000)}过期`)
+        info = await api('initPetTown', {"version": 1});
+    }
+    if (info?.result?.petStatus === 6) {
+        info = await api('goodsInfoList', {"type": 2})
+        let goods = commodityName ? info.result.goodsList.filter(
+            o => o.goodsName.includes(commodityName))[0]
+            : info.result.goodsList.filter(o => o.exchangeMedalNum === 4)[0];
+        if (!goods) {
+            $.putMsg(`没找到你要生产的 ${commodityName}`)
+            return
+        }
+        info = await api('goodsInfoUpdate', {"goodsId": goods.goodsId})
+        $.putMsg(`生产【${info.result.goodsInfo.goodsName}】成功`)
+    }
+};
+
+$.run({
+    wait: [2000, 3000], whitelist: ['1-15']
+}).catch(
+    reason => $.log(reason));
+
+// noinspection DuplicatedCode
+async function api(fn, body) {
+    let url = `https://api.m.jd.com/client.action?functionId=${fn}&body=${JSON.stringify(
+        body)}&client=apple&clientVersion=10.0.4&osVersion=13.7&appid=wh5&loginType=2&loginWQBiz=pet-town`
+//↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓请求头↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
+    let headers = {
+        "Cookie": $.cookie,
+        "Connection": "keep-alive",
+        "Accept": "*/*",
+        "Host": "api.m.jd.com",
+        'User-Agent': `Mozilla/5.0 (iPhone; CPU iPhone OS 14_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.4(0x1800042c) NetType/4G Language/zh_CN miniProgram`,
+        "Accept-Encoding": "gzip, deflate, br",
+        "Accept-Language": "zh-cn"
+    }
+    let {data} = await $.request(url, headers)
+    await $.wait(1000, 3000)
+    return data;
+}
+
diff --git a/m_jd_wx_addCart.js b/m_jd_wx_addCart.js
new file mode 100644
index 0000000..308e91b
--- /dev/null
+++ b/m_jd_wx_addCart.js
@@ -0,0 +1,182 @@
+//问题反馈:https://t.me/Wall_E_Channel
+/*
+7 7 7 7 7 m_jd_wx_addCart.js
+*/
+let mode = __dirname.includes('magic')
+const {Env} = mode ? require('./magic') : require('./magic')
+const $ = new Env('M加购有礼');
+$.activityUrl = process.env.M_WX_ADD_CART_URL
+    ? process.env.M_WX_ADD_CART_URL
+    : '';
+if (mode) {
+    $.activityUrl = 'https://lzkj-isv.isvjcloud.com/wxCollectionActivity/activity2/507a016fb7cc46acb51f792cbbbd9903?activityId=507a016fb7cc46acb51f792cbbbd9903&shopid=1000003005'
+}
+$.activityUrl = $.match(
+    /(https?:\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|])/,
+    $.activityUrl)
+$.domain = $.match(/https?:\/\/([^/]+)/, $.activityUrl)
+$.activityId = $.getQueryString($.activityUrl, 'activityId')
+$.activityContent = ''
+$.logic = async function () {
+    if (!$.activityId || !$.activityUrl) {
+        $.expire = true;
+        $.putMsg(`activityId|activityUrl不存在`);
+        return
+    }
+    $.log(`活动地址: ${$.activityUrl}`)
+    $.UA = $.ua();
+
+    let token = await $.isvObfuscator();
+    if (token.code !== '0') {
+        $.putMsg(`获取Token失败`);
+        return
+    }
+    $.Token = token?.token
+
+    let actInfo = await $.api('customer/getSimpleActInfoVo',
+        `activityId=${$.activityId}`);
+    if (!actInfo.result) {
+        $.expire = true;
+        $.putMsg(`获取活动信息失败`);
+        return
+    }
+    $.venderId = actInfo.data.venderId;
+    $.shopId = actInfo.data.shopId;
+    $.activityType = actInfo.data.activityType;
+
+    let myPing = await $.api('customer/getMyPing',
+        `userId=${$.venderId}&token=${$.Token}&fromType=APP`)
+    if (!myPing.result) {
+        $.putMsg(`获取pin失败`);
+        return
+    }
+    $.Pin = $.domain.includes('cjhy') ? encodeURIComponent(
+        encodeURIComponent(myPing.data.secretPin)) : encodeURIComponent(
+        myPing.data.secretPin);
+
+    await $.api(
+        `common/${$.domain.includes('cjhy') ? 'accessLog' : 'accessLogWithAD'}`,
+        `venderId=${$.venderId}&code=${$.activityType}&pin=${$.Pin}&activityId=${$.activityId}&pageUrl=${encodeURIComponent(
+            $.activityUrl)}&subType=app&adSource=`);
+    let activityContent = await $.api('wxCollectionActivity/activityContent',
+        `activityId=${$.activityId}&pin=${$.Pin}`);
+
+    if (!activityContent.result || !activityContent.data) {
+        $.putMsg(activityContent.errorMessage || '活动可能已结束')
+        return
+    }
+
+    $.activityContent = activityContent;
+    let content = activityContent.data;
+    if (![6, 7, 9, 13, 14, 15, 16].includes(
+        activityContent.data.drawInfo.drawInfoType)) {
+        $.putMsg(`垃圾活动不跑了`)
+        $.expire = true
+        return
+    }
+    if (1 > 2) {
+        let memberInfo = await $.api($.domain.includes('cjhy')
+            ? 'mc/new/brandCard/common/shopAndBrand/getOpenCardInfo'
+            : 'wxCommonInfo/getActMemberInfo',
+            $.domain.includes('cjhy')
+                ? `venderId=${$.venderId}&buyerPin=${$.Pin}&activityType=${$.activityType}`
+                :
+                `venderId=${$.venderId}&activityId=${$.activityId}&pin=${$.Pin}`);
+        // 没开卡需要开卡
+        if ($.domain.includes('cjhy')) {
+            if (memberInfo.result && !memberInfo.data?.openCard
+                && memberInfo.data?.openCardLink) {
+                $.putMsg('需要开卡,跳过')
+                return
+            }
+        } else {
+            if (memberInfo.result && !memberInfo.data?.openCard
+                && memberInfo.data?.actMemberStatus === 1) {
+                $.putMsg('需要开卡,跳过')
+                return
+            }
+        }
+        await $.api('wxActionCommon/getUserInfo', `pin=${$.Pin}`)
+        if (content.needFollow && !content.hasFollow) {
+            let followShop = await $.api(`wxActionCommon/followShop`,
+                `userId=${$.venderId}&activityId=${$.activityId}&buyerNick=${$.Pin}&activityType=${$.activityType}`);
+            await $.wait(1300, 1500)
+            if (!followShop.result) {
+                $.putMsg(followShop.errorMessage)
+                return;
+            }
+        }
+    }
+
+    let needCollectionSize = content.needCollectionSize || 1;
+    let hasCollectionSize = content.hasCollectionSize;
+    let oneKeyAddCart = content.oneKeyAddCart * 1 === 1;
+    $.log('drawInfo', JSON.stringify(content.drawInfo));
+    if (hasCollectionSize < needCollectionSize) {
+        let productIds = [];
+        a:for (let cpvo of content.cpvos) {
+            if (oneKeyAddCart) {
+                productIds.push(cpvo.skuId)
+                continue
+            }
+            for (let i = 0; i < 2; i++) {
+                try {
+                    let carInfo = await $.api(`wxCollectionActivity/addCart`,
+                        `activityId=${$.activityId}&pin=${$.Pin}&productId=${cpvo.skuId}`)
+                    if (carInfo.result) {
+                        if (carInfo.data.hasAddCartSize >= needCollectionSize) {
+                            $.log(`加购完成,本次加购${carInfo.data.hasAddCartSize}个商品`)
+                            break a
+                        }
+                        break;
+                    } else {
+                        await $.wxStop(carInfo.errorMessage) ? $.expire = true
+                            : ''
+                        $.putMsg(`${carInfo.errorMessage || '未知'}`);
+                        break a
+                    }
+                } catch (e) {
+                    $.log(e)
+                } finally {
+                    await $.wait(1300, 1500)
+                }
+            }
+        }
+        if (oneKeyAddCart) {
+            let carInfo = await $.api('wxCollectionActivity/oneKeyAddCart',
+                `activityId=${$.activityId}&pin=${$.Pin}&productIds=${encodeURIComponent(
+                    JSON.stringify(productIds))}`)
+            if (carInfo.result && carInfo.data) {
+                $.log(`加购完成,本次加购${carInfo.data.hasAddCartSize}个商品`)
+            } else {
+                await $.wxStop(carInfo.errorMessage) ? $.expire = true : ''
+                $.putMsg(`${carInfo.errorMessage || '未知'}`);
+                return
+            }
+        }
+    }
+    if ($.expire) {
+        return
+    }
+    let prize = await $.api('wxCollectionActivity/getPrize',
+        `activityId=${$.activityId}&pin=${$.Pin}`);
+    if (prize.result) {
+        let msg = prize.data.drawOk ? prize.data.name : prize.data.errorMessage
+            || '空气';
+        await $.wxStop(prize.data.errorMessage) ? $.expire = true : ''
+        $.putMsg(msg);
+    } else {
+        await $.wxStop(prize.errorMessage) ? $.expire = true : ''
+        $.putMsg(`${prize.errorMessage || '未知'}`);
+    }
+    await $.unfollow()
+}
+$.after = async function () {
+    $.msg.push(`\n${(await $.getShopInfo()).shopName}`)
+    $.msg.push(
+        `\n加购${$.activityContent?.data?.needCollectionSize}件,${$.activityContent.data.drawInfo?.name
+        || ''}\n`);
+    $.msg.push($.activityUrl)
+}
+$.run({whitelist: ['1-5'], wait: [3000, 5000]}).catch(
+    reason => $.log(reason));
diff --git a/m_jd_wx_collectCard.js b/m_jd_wx_collectCard.js
new file mode 100644
index 0000000..20e9b4b
--- /dev/null
+++ b/m_jd_wx_collectCard.js
@@ -0,0 +1,241 @@
+//问题反馈:https://t.me/Wall_E_Channel
+/*
+7 7 7 7 7 m_jd_wx_collectCard.js
+*/
+let mode = __dirname.includes('magic')
+const {Env} = mode ? require('./magic') : require('./magic')
+const $ = new Env('M集卡抽奖');
+$.activityUrl = process.env.M_WX_COLLECT_CARD_URL
+    ? process.env.M_WX_COLLECT_CARD_URL
+    : '';
+//最多几个集卡的,其余只助力
+let leaders = process.env.M_WX_COLLECT_CARD_LEADERS
+    ? process.env.M_WX_COLLECT_CARD_LEADERS * 1
+    : 5;
+if (mode) {
+    $.activityUrl = 'https://lzkjdz-isv.isvjcloud.com/wxCollectCard/activity/1193422?activityId=cb4d9c7ca992427db5a52ec1c0bcc42e'
+    $.activityUrl = 'https://lzkjdz-isv.isvjcloud.com/wxCollectCard/activity/3839759?activityId=2a47604ff73b47b5b432a06dc2226b70'
+}
+
+$.activityUrl = $.match(
+    /(https?:\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|])/,
+    $.activityUrl)
+$.domain = $.match(/https?:\/\/([^/]+)/, $.activityUrl)
+$.activityId = $.getQueryString($.activityUrl, 'activityId')
+$.shareUuid = ''
+let stop = false;
+let shopInfo = ''
+const all = new Set();
+
+$.logic = async function () {
+    if (stop) {
+        return;
+    }
+    if (!$.activityId || !$.activityUrl) {
+        stop = true;
+        $.putMsg(`activityId|activityUrl不存在`);
+        return
+    }
+    $.log(`活动url: ${$.activityUrl} ${await $._algo() || ""}`)
+    $.UA = $.ua();
+    let token = await $.isvObfuscator();
+    if (token.code !== '0') {
+        $.putMsg(`获取Token失败`);
+        return
+    }
+    $.Token = token?.token
+
+    let actInfo = await $.api('customer/getSimpleActInfoVo',
+        `activityId=${$.activityId}`);
+    if (!actInfo.result || !actInfo.data) {
+        $.log(`获取活动信息失败`);
+        return
+    }
+    $.venderId = actInfo.data.venderId;
+    $.shopId = actInfo.data.shopId;
+    $.activityType = actInfo.data.activityType;
+
+    let myPing = await $.api('customer/getMyPing',
+        `userId=${$.venderId}&token=${$.Token}&fromType=APP`)
+    if (!myPing.result) {
+        $.putMsg(`获取pin失败`);
+        return
+    }
+    $.Pin = $.domain.includes('cjhy') ? encodeURIComponent(
+        encodeURIComponent(myPing.data.secretPin)) : encodeURIComponent(
+        myPing.data.secretPin);
+
+    shopInfo = await $.api(`wxCollectCard/shopInfo`,
+        `activityId=${$.activityId}`);
+    if (!shopInfo.result) {
+        $.putMsg('获取不到店铺信息,结束运行')
+        return
+    }
+    $.shopName = shopInfo?.data?.shopName
+
+    await $.api(
+        `common/${$.domain.includes('cjhy') ? 'accessLog' : 'accessLogWithAD'}`,
+        `venderId=${$.venderId}&code=${$.activityType}&pin=${
+            $.Pin}&activityId=${$.activityId}&pageUrl=${encodeURIComponent(
+            $.activityUrl)}&subType=app&adSource=`);
+
+    $.index > 1 ? $.log(`去助力${$.shareUuid}`) : ''
+    let activityContent = await $.api(
+        'wxCollectCard/activityContent',
+        `activityId=${$.activityId}&pin=${
+            $.Pin}&uuid=${$.shareUuid}`);
+    if (!activityContent.result && !activityContent.data) {
+        $.putMsg(activityContent.errorMessage || '活动可能已结束')
+        return
+    }
+
+    let drawCount = $.match(/每人每天可获得(\d+)次/, activityContent.data.rule)
+        && $.match(/每人每天可获得(\d+)次/, activityContent.data.rule) * 1 || 5
+    console.log('openCard', activityContent.data.openCard);
+    $.shareUuid = $.shareUuid || activityContent.data.uuid
+    if ($.index % 5 === 0) {
+        $.log('执行可持续发展之道')
+        await $.wait(1000, 6000)
+    }
+    let drawContent = await $.api('wxCollectCard/drawContent',
+        `activityId=${$.activityId}`);
+    if (drawContent.result && drawContent.data) {
+        $.content = drawContent.data.content || []
+    }
+    let memberInfo = await $.api($.domain.includes('cjhy')
+        ? 'mc/new/brandCard/common/shopAndBrand/getOpenCardInfo'
+        : 'wxCommonInfo/getActMemberInfo',
+        $.domain.includes('cjhy')
+            ? `venderId=${$.venderId}&buyerPin=${$.Pin}&activityType=${$.activityType}`
+            :
+            `venderId=${$.venderId}&activityId=${$.activityId}&pin=${
+                $.Pin}`);
+    //没开卡 需要开卡
+    if ($.domain.includes('cjhy')) {
+        //没开卡 需要开卡
+        if (memberInfo.result && !memberInfo.data?.openCard
+            && memberInfo.data?.openCardLink) {
+            $.putMsg('需要开卡,跳过')
+            return
+        }
+    } else {
+        if (memberInfo.result && !memberInfo.data?.openCard
+            && memberInfo.data?.actMemberStatus === 1) {
+            $.putMsg('需要开卡,跳过')
+            return
+        }
+    }
+    $.shareUuid = $.shareUuid || activityContent.data.uuid
+    let userInfo = await $.api('wxActionCommon/getUserInfo',
+        `pin=${$.Pin}`);
+    if (!userInfo.result || !userInfo.data) {
+        $.putMsg(`获取getUserInfo失败`);
+        return
+    }
+    $.nickname = userInfo.data.nickname;
+    $.attrTouXiang = userInfo.data.yunMidImageUrl
+        || 'https://img10.360buyimg.com/imgzone/jfs/t1/21383/2/6633/3879/5c5138d8E0967ccf2/91da57c5e2166005.jpg'
+
+    await $.api('crm/pageVisit/insertCrmPageVisit',
+        `venderId=${$.venderId}&elementId=${encodeURIComponent(
+            '邀请')}&pageId=${$.activityId}&pin=${$.Pin}`);
+
+    await $.api('wxCollectCard/drawCard',
+        `sourceId=${$.shareUuid}&activityId=${$.activityId}&type=1&pinImg=${encodeURIComponent(
+            $.attrTouXiang)}&pin=${$.Pin}&jdNick=${encodeURIComponent(
+            $.nickname)}`);
+    if ($.index > leaders) {
+        return
+    }
+    let saveSource = await $.api('wxCollectCard/saveSource',
+        `activityId=${$.activityId}&pinImg=${encodeURIComponent(
+            $.attrTouXiang)}&pin=${
+            $.Pin}&jdNick=${encodeURIComponent($.nickname)}`);
+    if (!saveSource.result || !saveSource.data) {
+        $.putMsg(`初始化shareuuid失败`);
+        return
+    }
+    $.shareUuid = $.shareUuid || saveSource.data
+
+    for (let i = 0; i < drawCount; i++) {
+        let prize = await $.api(`wxCollectCard/drawCard`,
+            `sourceId=${saveSource.data}&activityId=${$.activityId}&type=0`);
+        $.log(JSON.stringify(prize))
+        if (prize.result) {
+            // $.putMsg(prize.data.reward.cardName);
+        } else {
+            if (prize.errorMessage.includes('上限')) {
+                $.putMsg('上限');
+                break;
+            } else if (prize.errorMessage.includes('来晚了')
+                || prize.errorMessage.includes('已发完')
+                || prize.errorMessage.includes('活动已结束')) {
+                stop = true;
+                break
+            }
+            $.log(`${prize}`);
+        }
+        await $.api('crm/pageVisit/insertCrmPageVisit',
+            `venderId=${$.venderId}&elementId=${encodeURIComponent(
+                '抽卡')}&pageId=${$.activityId}&pin=${
+                $.Pin}`);
+        await $.wait(1000, 2000)
+    }
+    activityContent = await $.api(
+        'wxCollectCard/activityContent',
+        `activityId=${$.activityId}&pin=${
+            $.Pin}&uuid=${$.shareUuid}`);
+    if (!activityContent.result || !activityContent.data) {
+        $.putMsg(activityContent.errorMessage || '活动可能已结束')
+        return
+    }
+
+    if (activityContent.data.canDraw) {
+        let prize = await $.api(`wxCollectCard/getPrize`,
+            `activityId=${$.activityId}&pin=${$.Pin}`);
+        $.log(JSON.stringify(prize))
+        if (!prize.result) {
+            let msg = prize.data.drawOk ? prize.data.name
+                : prize.data.errorMessage || '空气';
+            $.log(msg);
+        } else {
+            $.putMsg(`${prize.errorMessage}`);
+            if (prize.errorMessage.includes('来晚了')
+                || prize.errorMessage.includes('已发完')
+                || prize.errorMessage.includes('活动已结束')) {
+                stop = true;
+            }
+        }
+    } else {
+        activityContent = await $.api(
+            'wxCollectCard/activityContent',
+            `activityId=${$.activityId}&pin=${
+                $.Pin}&uuid=${$.shareUuid}`);
+        if (!activityContent.result || !activityContent.data) {
+            $.putMsg(activityContent.errorMessage || '活动可能已结束')
+            return
+        }
+        const has = new Set();
+        for (const ele of activityContent.data.cardList) {
+            all.add(ele.cardName)
+            ele.count > 0 ? has.add(ele.cardName) : ''
+        }
+        $.putMsg(Array.from(has).join(','))
+    }
+}
+$.after = async function () {
+    if ($.msg.length > 0) {
+        let message = `\n${$.shopName || ''}\n`;
+        message += `\n${Array.from(all).join(",")}\n`;
+        for (let ele of $.content || []) {
+            if (ele.name.includes('谢谢') || ele.name.includes('再来')) {
+                continue;
+            }
+            message += `    ${ele.name}${ele?.type === 8 ? '专享价' : ''}\n`
+        }
+        $.msg.push(message)
+        $.msg.push($.activityUrl);
+    }
+}
+$.run({whitelist: ['1-5'], wait: [1000, 3000]}).catch(
+    reason => $.log(reason));
diff --git a/m_jd_wx_luckDraw.js b/m_jd_wx_luckDraw.js
new file mode 100644
index 0000000..2768045
--- /dev/null
+++ b/m_jd_wx_luckDraw.js
@@ -0,0 +1,231 @@
+//问题反馈:https://t.me/Wall_E_Channel
+/*
+7 7 7 7 7 m_jd_wx_luckDraw.js
+*/
+let mode = __dirname.includes('magic')
+const {Env} = mode ? require('./magic') : require('./magic')
+const $ = new Env('M幸运抽奖');
+$.activityUrl = process.env.M_WX_LUCK_DRAW_URL
+    ? process.env.M_WX_LUCK_DRAW_URL
+    : '';
+$.notLuckDrawList = process.env.M_WX_NOT_LUCK_DRAW_LIST
+    ? process.env.M_WX_NOT_LUCK_DRAW_LIST.split('@')
+    : 'test'.split('@');
+if (mode) {
+    $.activityUrl = 'https://lzkj-isv.isvjcloud.com/lzclient/1648724528320/cjwx/common/entry.html?activityId=9cf424654f2d4821a229f73043987968&gameType=wxTurnTable&shopid=11743182'
+}
+$.activityUrl = $.match(
+    /(https?:\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|])/,
+    $.activityUrl)
+$.domain = $.match(/https?:\/\/([^/]+)/, $.activityUrl)
+$.activityId = $.getQueryString($.activityUrl, 'activityId')
+let shopInfo = ''
+$.logic = async function () {
+    if (!$.activityId || !$.activityUrl) {
+        $.expire = true;
+        $.putMsg(`activityId|activityUrl不存在`, $.activityUrl, $.activityId);
+        return
+    }
+    $.log(`活动id: ${$.activityId}`, `活动url: ${$.activityUrl}`)
+    $.UA = $.ua();
+
+    let token = await $.isvObfuscator();
+    if (token.code !== '0') {
+        $.putMsg(`获取Token失败`);
+        return
+    }
+    $.Token = token?.token
+    if ($.domain.includes("gzsl")) {
+        let activityContent = await $.api(
+            `wuxian/user/getLottery/${$.activityId}`,
+            {'id': $.activityId, 'token': $.Token, 'source': "01"});
+        $.log(activityContent)
+        if (activityContent.status !== '1') {
+            $.putMsg(`获取活动信息失败`);
+            return;
+        }
+        $.shopName = activityContent.activity.shopName
+        $.activityType = activityContent.activity.activityType
+        $.shopId = activityContent.activity.shopId;
+        $.content = activityContent.activity.prizes
+        if (activityContent.leftTime === 0) {
+            $.putMsg("抽奖次数为0")
+        }
+        while (activityContent.leftTime-- > 0) {
+            await $.wait(3000, 5000)
+            let data = await $.api(
+                `wuxian/user/draw/${$.activityId}`,
+                {'id': $.activityId, 'token': $.Token, 'source': "01"});
+            if (data.status !== "1") {
+                if (data.status === "-14") {
+                    $.putMsg("开卡入会后参与活动")
+                    break;
+                }
+                if (data.status === "-2") {
+                    $.putMsg("已结束")
+                    $.expire = true;
+                    break;
+                }
+                $.putMsg(data.msg)
+                continue
+            }
+            if (data?.winId) {
+                if (data.data.source === "0") {
+                    activityContent.leftTime++
+                }
+                $.putMsg(data.data.name)
+            } else {
+                $.putMsg("空气")
+            }
+        }
+    } else {
+        let actInfo = await $.api('customer/getSimpleActInfoVo',
+            `activityId=${$.activityId}`);
+        if (!actInfo.result || !actInfo.data) {
+            $.log(`获取活动信息失败`);
+            return
+        }
+        $.venderId = actInfo.data.venderId;
+        $.shopId = actInfo.data.shopId;
+        $.activityType = actInfo.data.activityType;
+
+        let myPing = await $.api('customer/getMyPing',
+            `userId=${$.venderId}&token=${$.Token}&fromType=APP`)
+        if (!myPing.result) {
+            $.putMsg(`获取pin失败`);
+            return
+        }
+        $.Pin = $.domain.includes('cjhy') ? encodeURIComponent(
+            encodeURIComponent(myPing.data.secretPin)) : encodeURIComponent(
+            myPing.data.secretPin);
+
+        shopInfo = await $.api('wxDrawActivity/shopInfo',
+            `activityId=${$.activityId}`);
+        if (!shopInfo.result) {
+            $.putMsg('获取不到店铺信息,结束运行')
+            return
+        }
+        $.shopName = shopInfo?.data?.shopName
+
+        for (let ele of $.notLuckDrawList) {
+            if ($.shopName.includes(ele)) {
+                $.expire = true
+                $.putMsg('已屏蔽')
+                return
+            }
+        }
+        await $.api(
+            `common/${$.domain.includes('cjhy') ? 'accessLog'
+                : 'accessLogWithAD'}`,
+            `venderId=${$.venderId}&code=${$.activityType}&pin=${$.Pin}&activityId=${$.activityId}&pageUrl=${encodeURIComponent(
+                $.activityUrl)}&subType=app&adSource=`);
+        let activityContent = await $.api(
+            `${$.activityType === 26 ? 'wxPointDrawActivity'
+                : 'wxDrawActivity'}/activityContent`,
+            `activityId=${$.activityId}&pin=${$.Pin}`);
+        if (!activityContent.result || !activityContent.data) {
+            $.putMsg(activityContent.errorMessage || '活动可能已结束')
+            return
+        }
+        debugger
+        $.hasFollow = activityContent.data.hasFollow || ''
+        $.needFollow = activityContent.data.needFollow || false
+        $.canDrawTimes = activityContent.data.canDrawTimes || 1
+        $.content = activityContent.data.content || []
+        $.drawConsume = activityContent.data.drawConsume || 0
+        $.canDrawTimes === 0 ? $.canDrawTimes = 1 : ''
+        debugger
+        let memberInfo = await $.api($.domain.includes('cjhy')
+            ? 'mc/new/brandCard/common/shopAndBrand/getOpenCardInfo'
+            : 'wxCommonInfo/getActMemberInfo',
+            $.domain.includes('cjhy')
+                ? `venderId=${$.venderId}&buyerPin=${$.Pin}&activityType=${$.activityType}`
+                :
+                `venderId=${$.venderId}&activityId=${$.activityId}&pin=${$.Pin}`);
+        //没开卡 需要开卡
+        if ($.domain.includes('cjhy')) {
+            //没开卡 需要开卡
+            if (memberInfo.result && !memberInfo.data?.openCard
+                && memberInfo.data?.openCardLink) {
+                $.putMsg('需要开卡,跳过')
+                return
+            }
+        } else {
+            if (memberInfo.result && !memberInfo.data?.openCard
+                && memberInfo.data?.actMemberStatus === 1) {
+                $.putMsg('需要开卡,跳过')
+                return
+            }
+        }
+
+        if ($.needFollow && !$.hasFollow) {
+            let followShop = await $.api($.domain.includes('cjhy')
+                ? 'wxActionCommon/newFollowShop'
+                : 'wxActionCommon/followShop',
+                $.domain.includes('cjhy')
+                    ? `venderId=${$.venderId}&activityId=${$.activityId}&buyerPin=${$.Pin}&activityType=${$.activityType}`
+                    : `userId=${$.venderId}&activityId=${$.activityId}&buyerNick=${$.Pin}&activityType=${$.activityType}`);
+            if (!followShop.result) {
+                $.putMsg(followShop.errorMessage)
+                return;
+            }
+            await $.wait(1000);
+        }
+        for (let m = 1; $.canDrawTimes--; m++) {
+            let prize = await $.api(
+                `${$.activityType === 26 ? 'wxPointDrawActivity'
+                    : 'wxDrawActivity'}/start`,
+                $.domain.includes('cjhy')
+                    ? `activityId=${$.activityId}&pin=${$.Pin}`
+                    : `activityId=${$.activityId}&pin=${$.Pin}`);
+            if (prize.result) {
+                $.canDrawTimes = prize.data.canDrawTimes
+                let msg = prize.data.drawOk ? prize.data.name
+                    : prize.data.errorMessage || '空气';
+                $.putMsg(msg)
+            } else {
+                if (prize.errorMessage) {
+                    $.putMsg(`${prize.errorMessage}`);
+                    if (prize.errorMessage.includes('来晚了')
+                        || prize.errorMessage.includes('已发完')
+                        || prize.errorMessage.includes('活动已结束')) {
+                        $.expire = true;
+                    }
+                }
+                break
+            }
+            await $.wait(parseInt(Math.random() * 500 + 1500, 10));
+        }
+    }
+    await $.unfollow($.shopId)
+}
+let kv = {
+    3: '幸运九宫格',
+    4: '转盘抽奖',
+    11: '扭蛋抽奖',
+    12: '九宫格抽奖',
+    13: '转盘抽奖',
+    26: '积分抽奖'
+}
+let kv2 = {'0': '再来一次', '1': '京豆', '2': '券', '3': '实物', '4': '积分'}
+
+$.after = async function () {
+    let message = `\n${$.shopName || ''} ${kv[$.activityType]
+    || $.activityType}\n`;
+    for (let ele of $.content || []) {
+        if (ele.name.includes('谢谢') || ele.name.includes('再来')) {
+            continue;
+        }
+        if ($.domain.includes('lzkj') || $.domain.includes('cjhy')) {
+            message += `\n    ${ele.name} ${ele?.type === 8 ? '专享价' : ''}`
+        } else {
+            message += `    ${ele.name} ${kv2[ele?.source]
+            || ele?.source}\n`
+        }
+    }
+    $.msg.push(message)
+    $.msg.push($.activityUrl);
+}
+$.run({whitelist: ['1-5'], wait: [3000, 5000]}).catch(
+    reason => $.log(reason));
+
diff --git a/m_jx_factory_automation.js b/m_jx_factory_automation.js
new file mode 100644
index 0000000..27f1f66
--- /dev/null
+++ b/m_jx_factory_automation.js
@@ -0,0 +1,326 @@
+//20 * * * * m_jx_factory_automation.js
+//问题反馈:https://t.me/Wall_E_Channel
+const {Env} = require('./magic');
+const $ = new Env('M工厂自动化');
+let commodityName = process.env.M_JX_FACTORY_COMMODITY
+    ? process.env.M_JX_FACTORY_COMMODITY
+    : '你还没设置要生产的变量M_JX_FACTORY_COMMODITY'
+let stop = false;
+$.logic = async function () {
+    if (stop) {
+        return;
+    }
+    let info = await GetUserInfo();
+    $.log(JSON.stringify(info));
+
+    if (!info) {
+        $.putMsg('没有找到工厂信息');
+        return;
+    }
+    await GetUserComponent(info.user.encryptPin);
+    $.log(info.factoryList[0].name, '等级', info.user.currentLevel);
+    if (info?.productionList) {
+        let product = info?.productionList[0];
+        if (product.investedElectric !== product.needElectric) {
+            $.log('还没有生产完成');
+            return
+        }
+        let productionId = product.productionId;
+        await $.wait(300, 500)
+        let {active} = await ExchangeCommodity(productionId);
+        await $.wait(300, 500)
+        await QueryHireReward();
+        await $.wait(300, 500)
+        await queryprizedetails(active)
+        await $.wait(300, 500)
+    }
+    let factoryId = info?.deviceList[0].factoryId;
+    $.log('获取工厂id', factoryId);
+    let deviceId = info?.deviceList[0].deviceId;
+    $.log('获取设备id', deviceId);
+    let {commodityList} = await GetCommodityList();
+    let filter = commodityList.filter(o => o.name.includes(commodityName));
+    if (filter.length === 1) {
+        let commodity = filter[0];
+        if (commodity?.flashStartTime && commodity?.flashStartTime
+            > $.timestamp()) {
+            $.log(`还没到时间`)
+            return;
+        }
+        let data = await GetCommodityDetails(commodity.commodityId);
+        await $.wait(300, 500)
+        let newVar = await AddProduction(factoryId, deviceId, data.commodityId);
+        if (newVar?.productionId) {
+            $.putMsg(`${data.name}已经开始生产`)
+            info = await GetUserInfo();
+            let product = info?.productionList[0];
+            let productionId = product.productionId;
+            await InvestElectric(productionId);//添加电力
+            await InvestElectric(productionId);
+        }
+    } else {
+        $.putMsg(`没找到你要生产的 ${commodityName}`)
+        stop = true;
+    }
+};
+
+$.run({
+    wait: [2000, 3000]
+}).catch(
+    reason => $.log(reason));
+
+async function InvestElectric(productionId) {
+    let url = `https://m.jingxi.com/dreamfactory/userinfo/InvestElectric?zone=dream_factory&productionId=${productionId}&_time=1637743936757&_ts=1637743936757&_=1637743936758&sceneval=2&g_login_type=1&callback=jsonpCBKR&g_ty=ls`;
+    // noinspection DuplicatedCode
+    let headers = {
+        'Accept': '*/*',
+        'Connection': 'keep-alive',
+        'Referer': 'https://st.jingxi.com/pingou/dream_factory/index.html',
+        'Accept-Encoding': 'gzip, deflate, br',
+        'Host': 'm.jingxi.com',
+        'Accept-Language': 'zh-cn'
+    }
+    // noinspection DuplicatedCode
+    headers['Cookie'] = $.cookie
+    headers['User-Agent'] = `jdpingou;iPhone;5.2.2;14.3;${$.randomString(
+        40)};network/wifi;model/iPhone12,1;appBuild/100630;ADID/00000000-0000-0000-0000-000000000000;supportApplePay/1;hasUPPay/0;pushNoticeIsOpen/0;hasOCPay/0;supportBestPay/0;session/1;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`
+    let data = await $.get(url, headers)
+    // noinspection DuplicatedCode
+    if (data?.ret === 0) {
+        return data?.data
+    }
+    return false;
+}
+
+async function AddProduction(factoryId, deviceId, commodityDimId) {
+    let url = `https://m.jingxi.com/dreamfactory/userinfo/AddProduction?zone=dream_factory&factoryId=${factoryId}&deviceId=${deviceId}&commodityDimId=${commodityDimId}&replaceProductionId=&_time=1637282973549&_ts=1637282973549&_=1637282973550&sceneval=2&g_login_type=1&callback=jsonpCBKGGG&g_ty=ls`;
+    // noinspection DuplicatedCode
+    let headers = {
+        'Accept': '*/*',
+        'Connection': 'keep-alive',
+        'Referer': 'https://st.jingxi.com/pingou/dream_factory/index.html',
+        'Accept-Encoding': 'gzip, deflate, br',
+        'Host': 'm.jingxi.com',
+        'Accept-Language': 'zh-cn',
+        'Cookie': $.cookie
+    }
+    // noinspection DuplicatedCode
+    headers['User-Agent'] = `jdpingou;iPhone;5.2.2;14.3;${$.randomString(
+        40)};network/wifi;model/iPhone12,1;appBuild/100630;ADID/00000000-0000-0000-0000-000000000000;supportApplePay/1;hasUPPay/0;pushNoticeIsOpen/0;hasOCPay/0;supportBestPay/0;session/1;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`
+    let data = await $.get(url, headers)
+    // noinspection DuplicatedCode
+    if (data?.ret === 0) {
+        return data?.data
+    } else {
+        $.putMsg(data?.msg)
+    }
+    return false;
+}
+
+async function GetDeviceDetails() {
+    let url = `https://m.jingxi.com/dreamfactory/diminfo/GetDeviceDetails?zone=dream_factory&deviceId=1&_time=1637282971386&_ts=1637282971386&_=1637282971386&sceneval=2&g_login_type=1&callback=jsonpCBKFFF&g_ty=ls`;
+    // noinspection DuplicatedCode
+    let headers = {
+        'Accept': '*/*',
+        'Connection': 'keep-alive',
+        'Referer': 'https://st.jingxi.com/pingou/dream_factory/index.html',
+        'Accept-Encoding': 'gzip, deflate, br',
+        'Host': 'm.jingxi.com',
+        'Accept-Language': 'zh-cn',
+        'Cookie': $.cookie
+    }
+    // noinspection DuplicatedCode
+    headers['User-Agent'] = `jdpingou;iPhone;5.2.2;14.3;${$.randomString(
+        40)};network/wifi;model/iPhone12,1;appBuild/100630;ADID/00000000-0000-0000-0000-000000000000;supportApplePay/1;hasUPPay/0;pushNoticeIsOpen/0;hasOCPay/0;supportBestPay/0;session/1;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`
+    let data = await $.get(url, headers)
+    // noinspection DuplicatedCode
+    if (data?.ret === 0) {
+        return data?.data
+    }
+    return false;
+}
+
+async function GetUserComponent(pin) {
+    let url = `https://m.jingxi.com/dreamfactory/usermaterial/GetUserComponent?zone=dream_factory&pin=${pin}&_time=1637282950558&_ts=1637282950559&sceneval=2&g_login_type=1&_=1637282951435&sceneval=2&g_login_type=1&callback=jsonpCBKSS&g_ty=ls`;
+    // noinspection DuplicatedCode
+    let headers = {
+        'Accept': '*/*',
+        'Connection': 'keep-alive',
+        'Referer': 'https://st.jingxi.com/pingou/dream_factory/index.html',
+        'Accept-Encoding': 'gzip, deflate, br',
+        'Host': 'm.jingxi.com',
+        'Accept-Language': 'zh-cn',
+        'Cookie': $.cookie
+    }
+    // noinspection DuplicatedCode
+    headers['User-Agent'] = `jdpingou;iPhone;5.2.2;14.3;${$.randomString(
+        40)};network/wifi;model/iPhone12,1;appBuild/100630;ADID/00000000-0000-0000-0000-000000000000;supportApplePay/1;hasUPPay/0;pushNoticeIsOpen/0;hasOCPay/0;supportBestPay/0;session/1;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`
+    let data = await $.get(url, headers)
+    // noinspection DuplicatedCode
+    if (data?.ret === 0) {
+        return data?.data
+    }
+    return false;
+}
+
+// noinspection DuplicatedCode
+async function GetUserInfo() {
+    let url = `https://m.jingxi.com/dreamfactory/userinfo/GetUserInfo?zone=dream_factory&pin=&sharePin=&shareType=&materialTuanPin=&materialTuanId=&needPickSiteInfo=1&source=&_time=1637282934811&_ts=1637282934811&timeStamp=&h5st=20211119084854812%3B5505286748222516%3Bc0ff1%3Btk02w96e01bc918n2aG34crijQCFgW%2BYZgoTBRpLWz6TM%2FWXRBmShiIQLtGvxCMJkN0g1uyofC04iuOhphAyAm66c3U5%3B2b53e58445b6ec6a5487e95f6aeae526c6c93b4724a0e54e03f3a8105f1caea6%3B3.0%3B1637282934812&_stk=_time%2C_ts%2CmaterialTuanId%2CmaterialTuanPin%2CneedPickSiteInfo%2Cpin%2CsharePin%2CshareType%2Csource%2CtimeStamp%2Czone&_ste=1&_=1637282934818&sceneval=2&g_login_type=1&callback=jsonpCBKY&g_ty=ls`;
+    // noinspection DuplicatedCode
+    let headers = {
+        'Accept': '*/*',
+        'Connection': 'keep-alive',
+        'Referer': 'https://st.jingxi.com/pingou/dream_factory/index.html',
+        'Accept-Encoding': 'gzip, deflate, br',
+        'Host': 'm.jingxi.com',
+        'Accept-Language': 'zh-cn',
+        'Cookie': $.cookie
+    }
+    // noinspection DuplicatedCode
+    headers['User-Agent'] = `jdpingou;iPhone;5.2.2;14.3;${$.randomString(
+        40)};network/wifi;model/iPhone12,1;appBuild/100630;ADID/00000000-0000-0000-0000-000000000000;supportApplePay/1;hasUPPay/0;pushNoticeIsOpen/0;hasOCPay/0;supportBestPay/0;session/1;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`
+    let data = await $.get(url, headers)
+    // noinspection DuplicatedCode
+    if (data?.ret === 0) {
+        return data?.data
+    }
+    return false;
+}
+
+// noinspection DuplicatedCode
+async function ExchangeCommodity(productionId) {
+    let url = `https://m.jingxi.com/dreamfactory/userinfo/ExchangeCommodity?zone=dream_factory&productionId=${productionId}&exchangeType=1&_time=1637282949946&_ts=1637282949946&_=1637282949947&sceneval=2&g_login_type=1&callback=jsonpCBKJJ&g_ty=ls`;
+    // noinspection DuplicatedCode
+    let headers = {
+        'Accept': '*/*',
+        'Connection': 'keep-alive',
+        'Referer': 'https://st.jingxi.com/pingou/dream_factory/index.html',
+        'Accept-Encoding': 'gzip, deflate, br',
+        'Host': 'm.jingxi.com',
+        'Accept-Language': 'zh-cn',
+        'Cookie': $.cookie
+    }
+    // noinspection DuplicatedCode
+    headers['User-Agent'] = `jdpingou;iPhone;5.2.2;14.3;${$.randomString(
+        40)};network/wifi;model/iPhone12,1;appBuild/100630;ADID/00000000-0000-0000-0000-000000000000;supportApplePay/1;hasUPPay/0;pushNoticeIsOpen/0;hasOCPay/0;supportBestPay/0;session/1;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`
+    let data = await $.get(url, headers)
+    // noinspection DuplicatedCode
+    if (data?.ret === 0) {
+        return data?.data
+    }
+    return false;
+}
+
+// noinspection DuplicatedCode
+async function GetCommodityList() {
+    let url = `https://m.jingxi.com/dreamfactory/diminfo/GetCommodityList?zone=dream_factory&flag=2&pageNo=1&pageSize=12&_time=1636619666773&_ts=1636619666773&_=1636619666773&sceneval=2&g_login_type=1&callback=jsonpCBKKK&g_ty=ls`;
+    // noinspection DuplicatedCode
+    let headers = {
+        'Accept': '*/*',
+        'Connection': 'keep-alive',
+        'Referer': 'https://st.jingxi.com/pingou/dream_factory/index.html',
+        'Accept-Encoding': 'gzip, deflate, br',
+        'Host': 'm.jingxi.com',
+        'Accept-Language': 'zh-cn',
+        'Cookie': $.cookie
+    }
+    // noinspection DuplicatedCode
+    headers['User-Agent'] = `jdpingou;iPhone;5.2.2;14.3;${$.randomString(
+        40)};network/wifi;model/iPhone12,1;appBuild/100630;ADID/00000000-0000-0000-0000-000000000000;supportApplePay/1;hasUPPay/0;pushNoticeIsOpen/0;hasOCPay/0;supportBestPay/0;session/1;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`
+    let data = await $.get(url, headers)
+    // noinspection DuplicatedCode
+    if (data?.ret === 0) {
+        return data?.data
+    }
+    return false;
+}
+
+// noinspection DuplicatedCode
+async function GetCommodityDetails(commodityId) {
+    let url = `https://m.jingxi.com/dreamfactory/diminfo/GetCommodityDetails?zone=dream_factory&commodityId=${commodityId}&_time=1636437544857&_ts=1636437544857&_=1636437544857&sceneval=2&g_login_type=1&callback=jsonpCBKWWW&g_ty=ls`;
+    // noinspection DuplicatedCode
+    let headers = {
+        'Accept': '*/*',
+        'Connection': 'keep-alive',
+        'Referer': 'https://st.jingxi.com/pingou/dream_factory/index.html',
+        'Accept-Encoding': 'gzip, deflate, br',
+        'Host': 'm.jingxi.com',
+        'Accept-Language': 'zh-cn',
+        'Cookie': $.cookie
+    }
+    // noinspection DuplicatedCode
+    headers['User-Agent'] = `jdpingou;iPhone;5.2.2;14.3;${$.randomString(
+        40)};network/wifi;model/iPhone12,1;appBuild/100630;ADID/00000000-0000-0000-0000-000000000000;supportApplePay/1;hasUPPay/0;pushNoticeIsOpen/0;hasOCPay/0;supportBestPay/0;session/1;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`
+    let data = await $.get(url, headers)
+    // noinspection DuplicatedCode
+    return data?.data?.commodityList?.[0]
+}
+
+async function queryprizedetails(actives) {
+    let url = `https://m.jingxi.com/active/queryprizedetails?actives=${actives}&_time=1637282950925&_ts=1637282950925&_=1637282950925&sceneval=2&g_login_type=1&callback=jsonpCBKQQ&g_ty=ls`;
+    // noinspection DuplicatedCode
+    let headers = {
+        'Accept': '*/*',
+        'Connection': 'keep-alive',
+        'Referer': 'https://st.jingxi.com/pingou/dream_factory/index.html',
+        'Accept-Encoding': 'gzip, deflate, br',
+        'Host': 'm.jingxi.com',
+        'Accept-Language': 'zh-cn',
+        'Cookie': $.cookie
+    }
+    // noinspection DuplicatedCode
+    headers['User-Agent'] = `jdpingou;iPhone;5.2.2;14.3;${$.randomString(
+        40)};network/wifi;model/iPhone12,1;appBuild/100630;ADID/00000000-0000-0000-0000-000000000000;supportApplePay/1;hasUPPay/0;pushNoticeIsOpen/0;hasOCPay/0;supportBestPay/0;session/1;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`
+    let data = await $.get(url, headers)
+    // noinspection DuplicatedCode
+    if (data?.ret === 0) {
+        return data?.data
+    }
+    return false;
+}
+
+async function QueryHireReward() {
+    let url = `https://m.jingxi.com/dreamfactory/friend/QueryHireReward?zone=dream_factory&_time=1637282950550&_ts=1637282950550&_=1637282950550&sceneval=2&g_login_type=1&callback=jsonpCBKLL&g_ty=ls`;
+    // noinspection DuplicatedCode
+    let headers = {
+        'Accept': '*/*',
+        'Connection': 'keep-alive',
+        'Referer': 'https://st.jingxi.com/pingou/dream_factory/index.html',
+        'Accept-Encoding': 'gzip, deflate, br',
+        'Host': 'm.jingxi.com',
+        'Accept-Language': 'zh-cn',
+        'Cookie': $.cookie
+    }
+    // noinspection DuplicatedCode
+    headers['User-Agent'] = `jdpingou;iPhone;5.2.2;14.3;${$.randomString(
+        40)};network/wifi;model/iPhone12,1;appBuild/100630;ADID/00000000-0000-0000-0000-000000000000;supportApplePay/1;hasUPPay/0;pushNoticeIsOpen/0;hasOCPay/0;supportBestPay/0;session/1;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`
+    let data = await $.get(url, headers)
+    // noinspection DuplicatedCode
+    if (data?.ret === 0) {
+        return data?.data
+    }
+    return false;
+}
+
+async function GetShelvesList() {
+    let url = `https://m.jingxi.com/dreamfactory/userinfo/GetShelvesList?zone=dream_factory&pageNo=1&pageSize=12&_time=1637282954475&_ts=1637282954475&_=1637282954475&sceneval=2&g_login_type=1&callback=jsonpCBKVV&g_ty=ls`;
+    // noinspection DuplicatedCode
+    let headers = {
+        'Accept': '*/*',
+        'Connection': 'keep-alive',
+        'Referer': 'https://st.jingxi.com/pingou/dream_factory/index.html',
+        'Accept-Encoding': 'gzip, deflate, br',
+        'Host': 'm.jingxi.com',
+        'Accept-Language': 'zh-cn',
+        'Cookie': $.cookie
+    }
+    // noinspection DuplicatedCode
+    headers['User-Agent'] = `jdpingou;iPhone;5.2.2;14.3;${$.randomString(
+        40)};network/wifi;model/iPhone12,1;appBuild/100630;ADID/00000000-0000-0000-0000-000000000000;supportApplePay/1;hasUPPay/0;pushNoticeIsOpen/0;hasOCPay/0;supportBestPay/0;session/1;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`
+    let data = await $.get(url, headers)
+    // noinspection DuplicatedCode
+    if (data?.ret === 0) {
+        return data?.data
+    }
+    return false;
+}
\ No newline at end of file
diff --git a/m_jx_factory_commodity.js b/m_jx_factory_commodity.js
new file mode 100644
index 0000000..41bf5e1
--- /dev/null
+++ b/m_jx_factory_commodity.js
@@ -0,0 +1,97 @@
+//1 0,8-18/3 * * * m_jx_factory_commodity.js
+//问题反馈:https://t.me/Wall_E_Channel
+const {Env} = require('./magic');
+const $ = new Env('M京喜工厂商品');
+$.logic = async function () {
+    let {commodityList} = await GetCommodityList();
+    for (let i = 0; i < commodityList.length; i++) {
+        let data = await GetCommodityDetails(commodityList[i].commodityId);
+        let s = '';
+        let hb = data.description.match(/红包[0-9]+(\.?[0-9]+)?元/g)
+            || data.description.match(/以[0-9]+(\.?[0-9]+)?元/g);
+        if (hb) {
+            s = hb[0].replace('以', '红包');
+        } else {
+            let ms = data.description.match(/支付[0-9]+(\.?[0-9]+)?元/g);
+            if (ms?.length === 1) {
+                s = ms[0]
+            } else {
+                s = '';
+            }
+        }
+        console.log(`${data.name} ${s}`)
+        if (s) {
+            if (s.match(/[0-9]+(\.?[0-9]+)?/g)[0] * 1 < 10) {
+                $.putMsg(`【${data.name}】 ${s}`)
+            }
+        } else {
+            $.putMsg(`【${data.name}】${data.name}`)
+        }
+
+        await $.wait(2000, 3000)
+    }
+}
+
+$.run({
+    bot: true,
+    delimiter: '\n',
+    whitelist: [1]
+}).catch(
+    reason => $.log(reason));
+
+/**
+ * 商品列表
+ *
+ * try {jsonpCBKKK({"data":{"commodityList":[{"commodityId":1977,"exchangeLimitSeconds":172800,"exclusiveChannel":0,"expressText":"内蒙古、海南、西藏、甘肃、青海、宁夏、新疆、台湾、朝阳区、钓鱼岛、石家庄市、邢台市、保定市、张家口市、承德市、廊坊市、衡水市、郑州市、商丘市、周口市、大连市、哈尔滨市、佳木斯市、黑河市、大兴安岭地区、盐城市、常州市、淄博市、临沂市、日照市、长沙市、衡阳市、上饶市、成都市、自贡市、阿坝州、遵义市、西安市、宝鸡市、海淀区、丰台区、门头沟、通州区、顺义区、昌平区、江北区、渝中区、港澳、海外不发货","flashStartTime":0,"label":0,"limitEndTime":0,"limitStartTime":0,"limitType":4,"name":"收纳罐套装","picture":"//img10.360buyimg.com/mobilecms/s200x200_jfs/t1/206532/12/7952/7263/6180e459E8b1a3bf2/cc2183b1abde0cf3.png","predictProductionDays":"1","produceLevelMax":30,"produceLevelMin":1,"productLimFlag":0,"productionTotal":8938,"raceCompleteNum":0,"raceEndTime":0,"raceStockNum":0,"sendElectricPercent":1,"showStock":0,"starLevel":1,"status":1,"stockNum":534,"userLimitNum":2},{"commodityId":1998,"exchangeLimitSeconds":172800,"exclusiveChannel":0,"expressText":"内蒙古、西藏、甘肃、青海、宁夏、新疆、台湾、钓鱼岛、黑河市、播州区、五莲县、红花岗区、汇川区、信都区、襄都区、港澳、海外、北七家镇不发货","flashStartTime":0,"label":0,"limitEndTime":0,"limitStartTime":0,"limitType":0,"name":"虫草花","picture":"//img10.360buyimg.com/mobilecms/s200x200_jfs/t1/169987/13/24100/43372/618b85d7E3eef1f38/d4eea0fbc7fda08a.png","predictProductionDays":"5","produceLevelMax":30,"produceLevelMin":1,"productLimFlag":0,"productionTotal":1408,"raceCompleteNum":0,"raceEndTime":0,"raceStockNum":0,"sendElectricPercent":1,"showStock":0,"starLevel":2,"status":1,"stockNum":3594,"userLimitNum":1},{"commodityId":1999,"exchangeLimitSeconds":172800,"exclusiveChannel":0,"expressText":"西藏、甘肃、新疆、台湾、钓鱼岛、哈尔滨市、港澳、海外不发货","flashStartTime":0,"label":0,"limitEndTime":0,"limitStartTime":0,"limitType":0,"name":"桌面收纳柜","picture":"//img10.360buyimg.com/mobilecms/s200x200_jfs/t1/204474/24/14755/28897/618b7dfcE6fe73b24/bbbbf32a50ebf0d9.png","predictProductionDays":"6","produceLevelMax":30,"produceLevelMin":1,"productLimFlag":0,"productionTotal":10053,"raceCompleteNum":0,"raceEndTime":0,"raceStockNum":0,"sendElectricPercent":1,"showStock":0,"starLevel":3,"status":1,"stockNum":2950,"userLimitNum":1},{"commodityId":1958,"exchangeLimitSeconds":172800,"exclusiveChannel":0,"expressText":"甘肃、青海、新疆、台湾、钓鱼岛、尚义县、清镇市、仁怀市、银川市、雁塔区、红花岗区、汇川区、长安区、信都区、襄都区、未央区、阎良区、新城区、港澳、海外、莲池区不发货","flashStartTime":1636632000,"label":0,"limitEndTime":0,"limitStartTime":0,"limitType":4,"name":"美的微波炉","picture":"//img10.360buyimg.com/mobilecms/s200x200_jfs/t1/170109/37/22755/7422/6178b994Ea776a3b2/372067cdacb2e4c3.png","predictProductionDays":"1","produceLevelMax":30,"produceLevelMin":1,"productLimFlag":0,"productionTotal":8,"raceCompleteNum":0,"raceEndTime":0,"raceStockNum":0,"sendElectricPercent":1,"showStock":0,"starLevel":1,"status":1,"stockNum":1,"userLimitNum":1},{"commodityId":1984,"exchangeLimitSeconds":172800,"exclusiveChannel":0,"expressText":"海南、西藏、新疆、台湾、钓鱼岛、港澳、海外不发货","flashStartTime":0,"label":0,"limitEndTime":0,"limitStartTime":0,"limitType":0,"name":"拉面碗4个装","picture":"//img10.360buyimg.com/mobilecms/s200x200_jfs/t1/161607/9/21878/8106/6180fb2dEe528464a/65d83198fb081c85.png","predictProductionDays":"7","produceLevelMax":30,"produceLevelMin":1,"productLimFlag":0,"productionTotal":28886,"raceCompleteNum":0,"raceEndTime":0,"raceStockNum":0,"sendElectricPercent":1,"showStock":0,"starLevel":3,"status":1,"stockNum":1115,"userLimitNum":1},{"commodityId":1988,"exchangeLimitSeconds":172800,"exclusiveChannel":0,"expressText":"西藏、青海、新疆、长宁区、闵行区、青浦区不发货","flashStartTime":0,"label":0,"limitEndTime":0,"limitStartTime":0,"limitType":0,"name":"汤勺漏勺4支装","picture":"//img10.360buyimg.com/mobilecms/s200x200_jfs/t1/216578/33/2811/7981/6180fc82E1dce001d/8537f027ba303dfc.png","predictProductionDays":"4","produceLevelMax":30,"produceLevelMin":1,"productLimFlag":0,"productionTotal":11260,"raceCompleteNum":0,"raceEndTime":0,"raceStockNum":0,"sendElectricPercent":1,"showStock":0,"starLevel":2,"status":1,"stockNum":3740,"userLimitNum":1},{"commodityId":1991,"exchangeLimitSeconds":172800,"exclusiveChannel":0,"expressText":"宁夏、新疆、石家庄市、大连市、哈尔滨市、黑河市、二连浩特市、阿拉善盟、常州市、日照市、株洲市、上饶市、成都市、兰州市、天水市、嘉峪关市、陇南市、张掖市、酒泉市、甘南州、青浦区、昌平区不发货","flashStartTime":0,"label":0,"limitEndTime":0,"limitStartTime":0,"limitType":0,"name":"茶里乌龙茶包","picture":"//img10.360buyimg.com/mobilecms/s200x200_jfs/t1/156199/9/24504/10220/6188ce73E31cdc245/d016ad5cc40a6ad7.png","predictProductionDays":"5","produceLevelMax":30,"produceLevelMin":1,"productLimFlag":0,"productionTotal":4103,"raceCompleteNum":0,"raceEndTime":0,"raceStockNum":0,"sendElectricPercent":1,"showStock":0,"starLevel":2,"status":1,"stockNum":897,"userLimitNum":1},{"commodityId":1992,"exchangeLimitSeconds":172800,"exclusiveChannel":0,"expressText":"上海、黑龙江、内蒙古、海南、贵州、西藏、甘肃、青海、宁夏、新疆、台湾、钓鱼岛、港澳、海外不发货","flashStartTime":0,"label":0,"limitEndTime":0,"limitStartTime":0,"limitType":0,"name":"毛球修剪器","picture":"//img10.360buyimg.com/mobilecms/s200x200_jfs/t1/214717/8/3614/7172/6188d29bEe9fd503b/c854a3de8305fdc1.png","predictProductionDays":"6","produceLevelMax":30,"produceLevelMin":1,"productLimFlag":0,"productionTotal":7953,"raceCompleteNum":0,"raceEndTime":0,"raceStockNum":0,"sendElectricPercent":1,"showStock":0,"starLevel":3,"status":1,"stockNum":12048,"userLimitNum":1},{"commodityId":1993,"exchangeLimitSeconds":172800,"exclusiveChannel":0,"expressText":"","flashStartTime":0,"label":0,"limitEndTime":0,"limitStartTime":0,"limitType":0,"name":"秋冬毛绒围脖","picture":"//img10.360buyimg.com/mobilecms/s200x200_jfs/t1/197696/28/16685/9626/6188d2e7E97bdaa1b/56a2351716900b29.png","predictProductionDays":"5","produceLevelMax":30,"produceLevelMin":1,"productLimFlag":0,"productionTotal":5740,"raceCompleteNum":0,"raceEndTime":0,"raceStockNum":0,"sendElectricPercent":1,"showStock":0,"starLevel":2,"status":1,"stockNum":14261,"userLimitNum":1},{"commodityId":1994,"exchangeLimitSeconds":172800,"exclusiveChannel":0,"expressText":"内蒙古、海南、西藏、甘肃、青海、宁夏、新疆、台湾、钓鱼岛、哈尔滨市、黑河市、成都市、遵义市、昌平区、武进区、港澳、海外不发货","flashStartTime":0,"label":0,"limitEndTime":0,"limitStartTime":0,"limitType":0,"name":"多孔插排","picture":"//img10.360buyimg.com/mobilecms/s200x200_jfs/t1/213301/4/3641/5663/6188d3e4Eb9a5a627/3e28b9a27460f17d.png","predictProductionDays":"7","produceLevelMax":30,"produceLevelMin":1,"productLimFlag":0,"productionTotal":8457,"raceCompleteNum":0,"raceEndTime":0,"raceStockNum":0,"sendElectricPercent":1,"showStock":0,"starLevel":3,"status":1,"stockNum":1544,"userLimitNum":1},{"commodityId":1941,"exchangeLimitSeconds":172800,"exclusiveChannel":0,"expressText":"西藏、新疆、港澳、海外不发货","flashStartTime":0,"label":0,"limitEndTime":0,"limitStartTime":0,"limitType":0,"name":"珊瑚绒睡裤","picture":"//img10.360buyimg.com/mobilecms/s200x200_jfs/t1/170576/12/21719/9109/61726e03Ea7eb7800/e8463377da2c0e74.png","predictProductionDays":"7","produceLevelMax":30,"produceLevelMin":1,"productLimFlag":0,"productionTotal":57847,"raceCompleteNum":0,"raceEndTime":0,"raceStockNum":0,"sendElectricPercent":93,"showStock":0,"starLevel":3,"status":1,"stockNum":153,"userLimitNum":1}],"totalCount":11},"msg":"OK","nowTime":1636619667,"ret":0}
+)} catch (e) {}
+ */
+// noinspection DuplicatedCode
+async function GetCommodityList() {
+    let url = `https://m.jingxi.com/dreamfactory/diminfo/GetCommodityList?zone=dream_factory&flag=2&pageNo=1&pageSize=12&_time=1636619666773&_ts=1636619666773&_=1636619666773&sceneval=2&g_login_type=1&callback=jsonpCBKKK&g_ty=ls`;
+    // noinspection DuplicatedCode
+    let headers = {
+        'Accept': '*/*',
+        'Connection': 'keep-alive',
+        'Referer': 'https://st.jingxi.com/pingou/dream_factory/index.html',
+        'Accept-Encoding': 'gzip, deflate, br',
+        'Host': 'm.jingxi.com',
+        'Accept-Language': 'zh-cn',
+        'Cookie': $.cookie
+    }
+    // noinspection DuplicatedCode
+    headers['User-Agent'] = `jdpingou;iPhone;5.2.2;14.3;${$.randomString(
+        40)};network/wifi;model/iPhone12,1;appBuild/100630;ADID/00000000-0000-0000-0000-000000000000;supportApplePay/1;hasUPPay/0;pushNoticeIsOpen/0;hasOCPay/0;supportBestPay/0;session/1;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`
+    let data = await $.get(url, headers)
+    // noinspection DuplicatedCode
+    if (data?.ret === 0) {
+        return data?.data
+    }
+    return false;
+}
+
+/**
+ * 商品详情
+ *
+ * try {jsonpCBKWWW({"data":{"commodityList":[{"commodityId":1981,"createTime":1635842589,"description":"【活动价为12.9元,完成需支付4元下单】","deviceIds":"1","electricThreshold":0,"exchangeLimitSeconds":172800,"exclusiveChannel":0,"expressText":"内蒙古、西藏、甘肃、青海、新疆、台湾、钓鱼岛、晋中市、蒲县、濮阳市、哈尔滨市、黑河市、呼玛县、连云港市、扬州市、淄博市、日照市、长兴县、仙游县、攸县、衡阳市、隆回县、靖西市、富顺县、合江县、旺苍县、若尔盖县、石渠县、遵义市、昆明市、普洱市、德宏州、西安市、洋县、银川市、吴忠市、昌平区、蜀山区、管城回族区、云龙镇、大沥镇、高新技术产业开发区、港澳、海外不发货","flashStartTime":0,"isPingouFactSkuInfo":2,"label":0,"ladderActive":"[]","limitEndTime":0,"limitStartTime":0,"limitType":0,"materialIds":"520","name":"保暖毛圈袜5双","offlineTime":1636819199,"onlineTime":1635868800,"picture":"//img10.360buyimg.com/mobilecms/s200x200_jfs/t1/201640/24/13983/12979/6180fa27E7a8317b9/121ef886afc15c9e.png","pingouFactZoneName":"","predictProductDays":"7","price":12600,"prizePoolIds":"","produceLevelMax":30,"produceLevelMin":1,"productLimFlag":0,"productLimSeconds":1900800,"productionCondition":"限时22天完成生产 |内蒙古、西藏、甘肃、青海、新疆、台湾、钓鱼岛、晋中市、蒲县、濮阳市、哈尔滨市、黑河市、呼玛县、连云港市、扬州市、淄博市、日照市、长兴县、仙游县、攸县、衡阳市、隆回县、靖西市、富顺县、合江县、旺苍县、若尔盖县、石渠县、遵义市、昆明市、普洱市、德宏州、西安市、洋县、银川市、吴忠市、昌平区、蜀山区、管城回族区、云龙镇、大沥镇、高新技术产业开发区、港澳、海外不发货","raceCompleteNum":0,"raceEndTime":0,"raceStockNum":0,"sendElectricPercent":1,"showStock":0,"skuId":"10037609865072","starLevel":3,"status":1,"stockNum":0,"typeId":0,"updateTime":1636338700,"usedNum":4463,"userLimitNum":1,"userProductionNum":1}]},"msg":"OK","nowTime":1636437544,"ret":0}
+)} catch (e) {}
+ */
+// noinspection DuplicatedCode
+async function GetCommodityDetails(commodityId) {
+    let url = `https://m.jingxi.com/dreamfactory/diminfo/GetCommodityDetails?zone=dream_factory&commodityId=${commodityId}&_time=1636437544857&_ts=1636437544857&_=1636437544857&sceneval=2&g_login_type=1&callback=jsonpCBKWWW&g_ty=ls`;
+    // noinspection DuplicatedCode
+    let headers = {
+        'Accept': '*/*',
+        'Connection': 'keep-alive',
+        'Referer': 'https://st.jingxi.com/pingou/dream_factory/index.html',
+        'Accept-Encoding': 'gzip, deflate, br',
+        'Host': 'm.jingxi.com',
+        'Accept-Language': 'zh-cn',
+        'Cookie': $.cookie
+    }
+    // noinspection DuplicatedCode
+    headers['User-Agent'] = `jdpingou;iPhone;5.2.2;14.3;${$.randomString(
+        40)};network/wifi;model/iPhone12,1;appBuild/100630;ADID/00000000-0000-0000-0000-000000000000;supportApplePay/1;hasUPPay/0;pushNoticeIsOpen/0;hasOCPay/0;supportBestPay/0;session/1;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`
+    let data = await $.get(url, headers)
+    // noinspection DuplicatedCode
+    return data?.data?.commodityList?.[0]
+}
diff --git a/magic.js b/magic.js
new file mode 100644
index 0000000..424a631
--- /dev/null
+++ b/magic.js
@@ -0,0 +1,1002 @@
+// noinspection JSUnresolvedFunction,JSUnresolvedVariable
+
+const axios = require('axios');
+const fs = require("fs");
+const {format} = require("date-fns");
+const notify = require('./sendNotify');
+const jdCookieNode = require('./jdCookie.js');
+const CryptoJS = require("crypto-js");
+
+let cookies = [];
+let testMode = process.env.TEST_MODE?.includes('on') ? true
+    : __dirname.includes("magic")
+
+let mode = process.env.MODE ? process.env.MODE : "local"
+
+let wxBlackCookiePin = process.env.M_WX_BLACK_COOKIE_PIN
+    ? process.env.M_WX_BLACK_COOKIE_PIN : ''
+
+Object.keys(jdCookieNode).forEach((item) => {
+    cookies.push(jdCookieNode[item])
+})
+
+const JDAPP_USER_AGENTS = [
+    `jdapp;android;10.0.2;9;${uuid()};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`,
+    `jdapp;android;10.0.2;9;${uuid()};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`,
+    `jdapp;android;10.0.2;9;${uuid()};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`,
+    `jdapp;android;10.0.2;9;${uuid()};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`,
+    `jdapp;android;10.0.2;10;${uuid()};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`,
+    `jdapp;android;10.0.2;10;${uuid()};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`,
+    `jdapp;android;10.0.2;10;${uuid()};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`,
+    `jdapp;android;10.0.2;10;${uuid()};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`,
+    `jdapp;android;10.0.2;10;${uuid()};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`,
+    `jdapp;android;10.0.2;10;${uuid()};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`,
+    `jdapp;android;10.0.2;11;${uuid()};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`,
+    `jdapp;android;10.0.2;10;${uuid()};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`,
+    `jdapp;android;10.0.2;11;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;14.2;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;14.3;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;14.2;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;11.4;${uuid()};network/wifi;Mozilla/5.0 (iPhone; CPU iPhone OS 11_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15F79`,
+    `jdapp;android;10.0.2;10;;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;14.3;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;13.6;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;13.6;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;13.5;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;14.1;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;13.3;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;13.7;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;14.1;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;13.3;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;13.4;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;14.3;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;14.3;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;14.3;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;14.1;${uuid()};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`,
+    `jdapp;android;10.0.2;8.1.0;${uuid()};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`,
+    `jdapp;android;10.0.2;8.0.0;${uuid()};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`,
+    `jdapp;iPhone;10.0.2;14.0.1;${uuid()};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`,
+    `jdapp;android;10.0.2;8.1.0;${uuid()};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`,
+]
+
+//来源于kedaya大佬
+const ISV_OBFUSCATOR = {
+    'lzkj-isv.isvjcloud.com': [
+        'body=%7B%22url%22%3A%22https%3A%2F%2Flzkj-isv.isvjcloud.com%22%2C%22id%22%3A%22%22%7D&uuid=1d9f7760c9ffaad4eb&client=apple&clientVersion=10.0.10&st=1646999134752&sv=112&sign=d14c9517190f8a8b0e253e3dbbdee87a',
+    ],
+    'cjhy-isv.isvjcloud.com': [
+        'body=%7B%22url%22%3A%22https%3A%2F%2Fcjhy-isv.isvjcloud.com%22%2C%22id%22%3A%22%22%7D&uuid=b024526b380d35c9e3&client=apple&clientVersion=10.0.10&st=1646999134786&sv=111&sign=fd9417f9d8e872da6c55102bd69da99f',
+    ],
+    'txzj-isv.isvjcloud.com': [
+        'body=%7B%22url%22%3A%22https%3A%2F%2Ftxzj-isv.isvjcloud.com%22%2C%22id%22%3A%22%22%7D&uuid=f7fc9bef85a8620cdf&client=apple&clientVersion=10.0.10&st=1646999134805&sv=121&sign=bbe137e2f52dbf3a1f10fa2ffe749d05',
+    ],
+    'lzdz1-isv.isvjcloud.com': [
+        'body=%7B%22url%22%3A%20%22https%3A//lzdz1-isv.isvjcloud.com%22%2C%20%22id%22%3A%20%22%22%7D&uuid=72124265217d48b7955781024d65bbc4&client=apple&clientVersion=9.4.0&st=1621796702000&sv=120&sign=14f7faa31356c74e9f4289972db4b988'
+    ],
+    'cjhydz-isv.isvjcloud.com': [
+        'adid=7B411CD9-D62C-425B-B083-9AFC49B94228&area=16_1332_42932_43102&body=%7B%22url%22%3A%22https%3A%5C/%5C/cjhydz-isv.isvjcloud.com%22%2C%22id%22%3A%22%22%7D&build=167541&client=apple&clientVersion=9.4.0&d_brand=apple&d_model=iPhone8%2C1&eid=eidId10b812191seBCFGmtbeTX2vXF3lbgDAVwQhSA8wKqj6OA9J4foPQm3UzRwrrLdO23B3E2wCUY/bODH01VnxiEnAUvoM6SiEnmP3IPqRuO%2By/%2BZo&isBackground=N&joycious=48&lang=zh_CN&networkType=wifi&networklibtype=JDNetworkBaseAF&openudid=2f7578cb634065f9beae94d013f172e197d62283&osVersion=13.1.2&partner=apple&rfs=0000&scope=11&screen=750%2A1334&sign=60bde51b4b7f7ff6e1bc1f473ecf3d41&st=1613720203903&sv=110&uts=0f31TVRjBStG9NoZJdXLGd939Wv4AlsWNAeL1nxafUsZqiV4NLsVElz6AjC4L7tsnZ1loeT2A8Z5/KfI/YoJAUfJzTd8kCedfnLG522ydI0p40oi8hT2p2sNZiIIRYCfjIr7IAL%2BFkLsrWdSiPZP5QLptc8Cy4Od6/cdYidClR0NwPMd58K5J9narz78y9ocGe8uTfyBIoA9aCd/X3Muxw%3D%3D&uuid=hjudwgohxzVu96krv/T6Hg%3D%3D&wifiBssid=9cf90c586c4468e00678545b16176ed2'
+    ],
+}
+const $ = axios.create({timeout: 30000});
+$.defaults.headers['Accept'] = '*/*';
+$.defaults.headers['Connection'] = 'keep-alive';
+$.defaults.headers['Accept-Language'] = "zh-CN,zh-Hans;q=0.9";
+$.defaults.headers['Accept-Encoding'] = "gzip, deflate, br";
+
+function uuid(x = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") {
+    return x.replace(/[xy]/g, function (x) {
+        const r = 16 * Math.random() | 0, n = "x" === x ? r : 3 & r | 8;
+        return n.toString(36)
+    })
+}
+
+class Env {
+    constructor(name) {
+        this.name = name
+        this.username = '';
+        this.cookie = '';
+        this.cookies = cookies;
+        this.index = '';
+        this.ext = [];
+        this.msg = [];
+        this.delimiter = '';
+        this.filename = ''
+        this.lz = ''
+        this.appId = '';
+        this.algo = {};
+        this.bot = false;
+        this.expire = false;
+        this.accounts = {};
+    }
+
+    async run(data = {
+        wait: [1000, 2000],
+        bot: false,
+        delimiter: '',
+        o2o: false,
+        random: false,
+        once: false,
+        blacklist: [],
+        whitelist: []
+    }) {
+        console.log('运行参数:', data);
+        this.filename = process.argv[1];
+        console.log(`${this.now()} ${this.name} ${this.filename} 开始运行...`);
+        this.start = this.timestamp();
+        let accounts = "";
+        if (__dirname.includes("magic")) {
+            accounts = this.readFileSync(
+                '/home/magic/Work/wools/doc/account.json')
+        } else {
+            if (fs.existsSync('utils/account.json')) {
+                accounts = this.readFileSync('utils/account.json')
+            } else {
+                accounts = this.readFileSync('account.json')
+            }
+        }
+        accounts ? JSON.parse(accounts).forEach(
+            o => this.accounts[o.pt_pin] = o.remarks) : ''
+        await this.config()
+        if (data?.delimiter) {
+            this.delimiter = data?.delimiter
+        }
+        if (data?.bot) {
+            this.bot = data.bot;
+        }
+
+        console.log('原始ck长度', cookies.length)
+        if (data?.blacklist?.length > 0) {
+            for (const cki of this.__as(data.blacklist)) {
+                delete cookies[cki - 1];
+            }
+        }
+        this.delBlackCK()
+        console.log('排除黑名单后ck长度', cookies.length)
+        if (data?.whitelist?.length > 0) {
+            let cks = []
+            for (const cki of this.__as(data.whitelist)) {
+                if (cki - 1 < cookies.length) {
+                    cks.push(cookies[cki - 1])
+                }
+            }
+            cookies = cks;
+        }
+        console.log('设置白名单后ck长度', cookies.length)
+
+        if (data?.random) {
+            cookies = this.randomArray(cookies)
+        }
+        await this.verify()
+        this.cookies = cookies;
+        if (data?.before) {
+            for (let i = 0; i <= this.cookies.length; i++) {
+                if (this.cookies[i] && !this.expire) {
+                    let cookie = this.cookies[i];
+                    this.cookie = cookie;
+                    this.username = decodeURIComponent(
+                        cookie.match(/pt_pin=([^; ]+)(?=;?)/)[1]);
+                    $.defaults.headers['Cookie'] = this.cookie;
+                    this.index = i + 1;
+                    let me = {
+                        username: this.username,
+                        index: this.index,
+                        cookie: this.cookie
+                    };
+                    try {
+                        this.ext.push(Object.assign(me, await this.before()));
+                    } catch (e) {
+                        console.log(e)
+                    }
+                    if (data?.wait?.length > 0 && this.index
+                        !== cookies.length) {
+                        await this.wait(data?.wait[0], data?.wait[1])
+                    }
+                }
+            }
+        }
+        let once = false;
+        for (let i = 0; i <= this.cookies.length; i++) {
+            if (this.cookies[i] && !this.expire) {
+                this.index = i + 1;
+                if (data?.once && this.index !== data.once) {
+                    once = true;
+                    continue;
+                }
+                let cookie = this.cookies[i];
+                this.cookie = cookie;
+                this.username = decodeURIComponent(
+                    cookie.match(/pt_pin=([^; ]+)(?=;?)/)[1]);
+                $.defaults.headers['Cookie'] = this.cookie;
+                this.index = i + 1;
+                try {
+                    await this.logic()
+                    if (data?.o2o) {
+                        await this.send();
+                        testMode ? this.log(this.msg.join("\n")) : ''
+                        this.msg = [];
+                    }
+                    if (once) {
+                        break;
+                    }
+                } catch (e) {
+                    console.log(e.message || '')
+                }
+                if (data?.wait?.length > 0 && this.index !== cookies.length) {
+                    await this.wait(data?.wait[0], data?.wait[1])
+                }
+            }
+        }
+        await this.after()
+        console.log(`${this.now()} ${this.name} 运行结束,耗时 ${this.timestamp()
+        - this.start}ms\n`)
+        testMode && this.msg.length > 0 ? console.log(this.msg.join("\n")) : ''
+        if (!data?.o2o) {
+            await this.send();
+        }
+    }
+
+    async config() {
+
+    }
+
+    delBlackCK() {
+        let strArrTemp = []
+        for (let i = 0; i < cookies.length; i++) {
+            if (cookies[i]) {
+                let cookie = cookies[i]
+                let pt_pin = decodeURIComponent(
+                    cookie.match(/pt_pin=(.+?);/) && cookie.match(
+                    /pt_pin=(.+?);/)[1]);
+                if (wxBlackCookiePin.includes(pt_pin)) {
+                    this.log("剔除黑号CK:" + pt_pin);
+                    continue;
+                }
+                strArrTemp.push(cookie);
+            }
+        }
+        cookies = strArrTemp;
+    }
+
+    me() {
+        return this.ext[this.index - 1]
+    }
+
+    finish() {
+        this.ext[this.index - 1].finish = true
+    }
+
+    __as(es) {
+        console.log(es)
+
+        let b = [];
+        for (let e of es) {
+            if (typeof e === 'string') {
+                let start = e.split('-')[0] * 1
+                let end = e.split('-')[1] * 1
+                if (end - start === 1) {
+                    b.push(start)
+                    b.push(end)
+                } else {
+                    for (let i = start; i <= end; i++) {
+                        b.push(i)
+                    }
+                }
+            } else {
+                b.push(e)
+            }
+        }
+        console.log(b)
+        return b
+    }
+
+    deleteCookie() {
+        delete this.cookies[this.index - 1]
+        return {};
+    }
+
+    groupBy(arr, fn) {
+        const data = {};
+        arr.forEach(function (o) {
+            const k = fn(o);
+            data[k] = data[k] || []
+            data[k].push(o)
+        })
+
+        return data;
+    }
+
+    async send() {
+        if (this.msg?.length > 0) {
+            this.msg.push(
+                `\n时间:${this.now()} 时长:${((this.timestamp() - this.start)
+                    / 1000).toFixed(2)}s`)
+            if (this.bot) {
+                await notify.sendNotify("/" + this.name,
+                    this.msg.join(this.delimiter || ''))
+            } else {
+                await notify.sendNotify(this.name, this.msg.join("\n"))
+            }
+        }
+    }
+
+    async verify() {
+        let fn = this.filename
+
+        function av(s) {
+            return s.trim().match(/([a-z_])*$/)[0];
+        }
+
+        let x = '109M95O106F120V95B', y = '99M102F100O', z = '109H99V',
+            j = '102N97I99D116T111G114A121B', k = '112C112U',
+            l = '109N95G106B100K95U', m = '119V120M';
+        let reg = /[A-Z]/;
+        x.concat(y).split(reg).map(o => +o).filter(o => o > 0).forEach(
+            o => y += String.fromCharCode(o))
+        x.concat(z).split(reg).map(o => +o).filter(o => o > 0).forEach(
+            o => z += String.fromCharCode(o))
+        x.concat(j).split(reg).map(o => +o).filter(o => o > 0).forEach(
+            o => j += String.fromCharCode(o))
+        x.concat(k).split(reg).map(o => +o).filter(o => o > 0).forEach(
+            o => k += String.fromCharCode(o))
+        l.concat(m).split(reg).map(o => +o).filter(o => o > 0).forEach(
+            o => m += String.fromCharCode(o))
+        this.appId = fn ? this.name.slice(0, 1)
+            === String.fromCharCode(77)
+            ? (fn.includes(av(y)) ? '10032' :
+                fn.includes(av(z)) ? '10028' :
+                    fn.includes(av(j)) ? '10001' :
+                        fn.includes(av(k)) ? '10038' :
+                            fn.includes(av(m)) ? 'wx' : '') : ''
+            : '';
+        this.appId ? this.algo = await this._algo() : '';
+    }
+
+    async wait(min, max) {
+        if (min < 0) {
+            return;
+        }
+        if (max) {
+            return new Promise(
+                (resolve) => setTimeout(resolve, this.random(min, max)));
+        } else {
+            return new Promise((resolve) => setTimeout(resolve, min));
+        }
+    }
+
+    putMsg(msg) {
+        msg += ''
+        this.log(msg)
+        let r = [[' ', ''], ['优惠券', '券'], ['东券', '券'], ['店铺', ''],
+            ['恭喜', ''], ['获得', '']]
+        for (let ele of r) {
+            msg = msg.replace(ele[0], ele[1])
+        }
+        if (this.bot) {
+            this.msg.push(msg)
+        } else {
+            let username = this.accounts[this.username] || this.username;
+            username += this.index
+            if (this.msg.length > 0 && this.msg[this.msg.length - 1].includes(
+                username)) {
+                this.msg[this.msg.length - 1] = this.msg[this.msg.length
+                - 1].split(" ")[0] + '' + [this.msg[this.msg.length - 1].split(
+                    " ")[1], msg].join(',')
+            } else {
+                this.msg.push(`【${username}】${msg}`)
+            }
+        }
+    }
+
+    md5(str) {
+        return CryptoJS.MD5(str).toString()
+    }
+
+    HmacSHA256(param, key) {
+        return CryptoJS.HmacSHA256(param, key).toString()
+    }
+
+    log(...msg) {
+        this.s ? console.log(...msg) : console.log(
+            `${this.now()} ${this.accounts[this.username] || this.username}`,
+            ...msg)
+    }
+
+    //并
+    union(a, b) {
+        return a.concat(b.filter(o => !a.includes(o)))
+    }
+
+    //交
+    intersection(a, b) {
+        return a.filter(o => b.includes(o))
+    }
+
+    //交
+    different(a, b) {
+        return a.concat(b).filter(o => a.includes(o) && !b.includes(o))
+    }
+
+    build(url) {
+        if (url.match(/&callback=(jsonpCBK(.*))&/)) {
+            let cb = url.match(/&callback=(jsonpCBK(.*))&/);
+            url = url.replace(cb[1], this.randomCallback(cb[2].length || 0))
+        }
+        let stk = decodeURIComponent(this.getQueryString(url, '_stk') || '');
+        if (stk) {
+            let ens, hash, st = '',
+                ts = this.now('yyyyMMddHHmmssSSS').toString(),
+                tk = this.algo.tk, fp = this.algo.fp, em = this.algo.em;
+            if (tk && fp && em) {
+                hash = em(tk, fp, ts, this.appId, CryptoJS).toString(
+                    CryptoJS.enc.Hex)
+            } else {
+                const random = '5gkjB6SpmC9s';
+                tk = 'tk01wcdf61cb3a8nYUtHcmhSUFFCfddDPRvKvYaMjHkxo6Aj7dhzO+GXGFa9nPXfcgT+mULoF1b1YIS1ghvSlbwhE0Xc';
+                fp = '9686767825751161';
+                hash = CryptoJS.SHA512(
+                    `${tk}${fp}${ts}${this.appId}${random}`,
+                    tk).toString(CryptoJS.enc.Hex);
+            }
+            stk.split(',').map((item, index) => {
+                st += `${item}:${this.getQueryString(url, item)}${index
+                === stk.split(',').length - 1 ? '' : '&'}`;
+            })
+            ens = encodeURIComponent(
+                [''.concat(ts), ''.concat(fp),
+                    ''.concat(this.appId), ''.concat(tk),
+                    ''.concat(CryptoJS.HmacSHA256(st, hash.toString()).toString(
+                        CryptoJS.enc.Hex))].join(';'));
+            if (url.match(/[?|&]h5st=(.*?)&/)) {
+                url = url.replace(url.match(/[?|&]h5st=(.*?)&/)[1], 'H5ST')
+                .replace(/H5ST/, ens)
+            }
+            let matchArr = [/[?|&]_time=(\d+)/, /[?|&]__t=(\d+)/,
+                /[?|&]_ts=(\d+)/,
+                /[?|&]_=(\d+)/, /[?|&]t=(\d+)/, /[?|&]_cfd_t=(\d+)/]
+            for (let ms of matchArr) {
+                if (url.match(ms)) {
+                    url = url.replace(url.match(ms)[1], Date.now())
+                }
+            }
+            let t = this._tk();
+            if (url.match(/strPgUUNum=(.*?)&/)) {
+                url = url.replace(url.match(/strPgUUNum=(.*?)&/)[1], t.tk)
+                if (url.match(/strPhoneID=(.*?)&/)) {
+                    url = url.replace(url.match(/strPhoneID=(.*?)&/)[1], t.id)
+                }
+                if (url.match(/strPgtimestamp=(.*?)&/)) {
+                    url = url.replace(url.match(/strPgtimestamp=(.*?)&/)[1],
+                        t.ts)
+                }
+            }
+            if (url.match(/jxmc_jstoken=(.*?)&/)) {
+                url = url.replace(url.match(/jxmc_jstoken=(.*?)&/)[1], t.tk)
+                if (url.match(/phoneid=(.*?)&/)) {
+                    url = url.replace(url.match(/phoneid=(.*?)&/)[1], t.id)
+                }
+                if (url.match(/timestamp=(.*?)&/)) {
+                    url = url.replace(url.match(/timestamp=(.*?)&/)[1], t.ts)
+                }
+            }
+        }
+        return url;
+    }
+
+    getQueryString(url, name) {
+        let reg = new RegExp("(^|[&?])" + name + "=([^&]*)(&|$)");
+        let r = url.match(reg);
+        if (r != null) {
+            return unescape(r[2]);
+        }
+        return '';
+    }
+
+    unique(arr) {
+        return Array.from(new Set(arr))
+    }
+
+    async logic() {
+        console.log("default logic")
+    }
+
+    async before() {
+        return -1;
+    }
+
+    async after() {
+        return -1;
+    }
+
+    tryLock(username, key) {
+        try {
+            fs.accessSync(`/jd/log/lock/${key}_${username}`);
+            return false;
+        } catch (e) {
+            return true;
+        }
+    }
+
+    setLock(username, key) {
+        try {
+            try {
+                fs.accessSync(`/jd/log/lock`);
+            } catch (e) {
+                fs.mkdirSync(`/jd/log/lock`);
+            }
+            fs.mkdirSync(`/jd/log/lock/${key}_${username}`);
+            return false;
+        } catch (e) {
+            return true;
+        }
+    }
+
+    match(pattern, string) {
+        pattern = (pattern instanceof Array) ? pattern : [pattern];
+        for (let pat of pattern) {
+            const match = pat.exec(string);
+            if (match) {
+                const len = match.length;
+                if (len === 1) {
+                    return match;
+                } else if (len === 2) {
+                    return match[1];
+                } else {
+                    const r = [];
+                    for (let i = 1; i < len; i++) {
+                        r.push(match[i])
+                    }
+                    return r;
+                }
+            }
+        }
+        return '';
+    }
+
+    matchAll(pattern, string) {
+        pattern = (pattern instanceof Array) ? pattern : [pattern];
+        let match;
+        let result = [];
+        for (let p of pattern) {
+            while ((match = p.exec(string)) != null) {
+                let len = match.length;
+                if (len === 1) {
+                    result.push(match);
+                } else if (len === 2) {
+                    result.push(match[1]);
+                } else {
+                    let r = [];
+                    for (let i = 1; i < len; i++) {
+                        r.push(match[i])
+                    }
+                    result.push(r);
+                }
+            }
+        }
+        return result;
+    }
+
+    async countdown(mode = 1, s = 200) {
+        let d = new Date();
+        switch (mode) {
+            case 1:
+                d.setHours(d.getHours() + 1);
+                d.setMinutes(0)
+                break
+            case 2:
+                d.setMinutes(30)
+                break
+            case 3:
+                d.setMinutes(15)
+                break
+            case 4:
+                d.setMinutes(10)
+                break
+            case 5:
+                d.setMinutes(5)
+                break
+            default:
+                console.log("不支持")
+        }
+        d.setSeconds(0)
+        d.setMilliseconds(0)
+        let st = d.getTime() - Date.now() - 200
+        if (st > 0) {
+            console.log(`需要等待时间${st / 1000} 秒`);
+            await this.wait(st)
+        }
+    }
+
+    readFileSync(path) {
+        try {
+            return fs.readFileSync(path).toString();
+        } catch (e) {
+            console.log(path, '文件不存在进行创建')
+            this.writeFileSync(path, '');
+            return '';
+        }
+    }
+
+    writeFileSync(path, data) {
+        fs.writeFileSync(path, data)
+    }
+
+    random(min, max) {
+        return Math.min(Math.floor(min + Math.random() * (max - min)), max);
+
+    }
+
+    async notify(text, desc) {
+        return notify.sendNotify(text, desc);
+    }
+
+    async get(url, headers) {
+        url = this.appId ? this.build(url) : url
+        return new Promise((resolve, reject) => {
+            $.get(url, {headers: headers}).then(
+                data => resolve(this.handler(data) || data))
+            .catch(e => reject(e))
+        })
+    }
+
+    async post(url, body, headers) {
+        url = this.appId ? this.build(url) : url
+        return new Promise((resolve, reject) => {
+            $.post(url, body, {headers: headers})
+            .then(data => resolve(this.handler(data) || data))
+            .catch(e => reject(e));
+        })
+    }
+
+    async request(url, headers, body) {
+        return new Promise((resolve, reject) => {
+            let __config = headers?.headers ? headers : {headers: headers};
+            (body ? $.post(url, body, __config) : $.get(url, __config))
+            .then(data => {
+                this.__lt(data);
+                resolve(data)
+            })
+            .catch(e => reject(e));
+        })
+    }
+
+    __lt(data) {
+        if (this.appId.length !== 2) {
+            return
+        }
+        let scs = data?.headers['set-cookie'] || data?.headers['Set-Cookie']
+            || ''
+        if (!scs) {
+            if (data?.data?.LZ_TOKEN_KEY && data?.data?.LZ_TOKEN_VALUE) {
+                this.lz = `LZ_TOKEN_KEY=${data.data.LZ_TOKEN_KEY};LZ_TOKEN_VALUE=${data.data.LZ_TOKEN_VALUE};`;
+            }
+            return;
+        }
+        let LZ_TOKEN_KEY = '', LZ_TOKEN_VALUE = '', JSESSIONID = '',
+            jcloud_alb_route = '', ci_session = ''
+        let sc = typeof scs != 'object' ? scs.split(',') : scs
+        for (let ck of sc) {
+            let name = ck.split(";")[0].trim()
+            if (name.split("=")[1]) {
+                name.includes('LZ_TOKEN_KEY=') ? LZ_TOKEN_KEY = name.replace(
+                    / /g, '') + ';' : ''
+                name.includes('LZ_TOKEN_VALUE=')
+                    ? LZ_TOKEN_VALUE = name.replace(/ /g, '') + ';' : ''
+                name.includes('JSESSIONID=') ? JSESSIONID = name.replace(/ /g,
+                    '') + ';' : ''
+                name.includes('jcloud_alb_route=')
+                    ? jcloud_alb_route = name.replace(/ /g, '') + ';' : ''
+                name.includes('ci_session=') ? ci_session = name.replace(/ /g,
+                    '') + ';' : ''
+            }
+        }
+        if (JSESSIONID && LZ_TOKEN_KEY && LZ_TOKEN_VALUE) {
+            this.lz = `${JSESSIONID}${LZ_TOKEN_KEY}${LZ_TOKEN_VALUE}`
+        } else if (LZ_TOKEN_KEY && LZ_TOKEN_VALUE) {
+            this.lz = `${LZ_TOKEN_KEY}${LZ_TOKEN_VALUE}`
+        } else if (JSESSIONID && jcloud_alb_route) {
+            this.lz = `${JSESSIONID}${jcloud_alb_route}`
+        } else if (JSESSIONID) {
+            this.lz = `${JSESSIONID}`
+        }
+        if (ci_session) {
+            this.lz = `${ci_session}`
+        }
+        // testMode ? this.log('lz', this.lz) : ''
+    }
+
+    handler(res) {
+        let data = res?.data || res?.body || res;
+        if (!data) {
+            return;
+        }
+        if (typeof data === 'string') {
+            data = data.replace(/[\n\r| ]/g, '');
+            if (data.includes("try{jsonpCB")) {
+                data = data.replace(/try{jsonpCB.*\({/, '{')
+                .replace(/}\)([;])?}catch\(e\){}/, '}')
+            } else if (data.includes('jsonpCB')) {
+                let st = data.replace(/[\n\r]/g, '').replace(/jsonpCB.*\({/,
+                    '{');
+                data = st.substring(0, st.length - 1)
+            } else if (data.match(/try{.*\({/)) {
+                data = data.replace(/try{.*\({/, '{')
+                .replace(/}\)([;])?}catch\(e\){}/, '}')
+            } else {
+                testMode ? console.log('例外', data) : ''
+                data = /.*?({.*}).*/g.exec(data)[1]
+            }
+            testMode ? console.log(data) : ''
+            testMode ? console.log('----------------分割线--------------------')
+                : ''
+            return JSON.parse(data)
+        }
+        testMode ? console.log(JSON.stringify(data)) : ''
+        testMode ? console.log('----------------分割线---------------------') : ''
+        return data;
+    }
+
+    randomNum(length) {
+        length = length || 32;
+        let t = "0123456789", a = t.length, n = '';
+        for (let i = 0; i < length; i++) {
+            n += t.charAt(Math.floor(Math.random() * a));
+        }
+        return n
+    }
+
+    randomString(e) {
+        return this.uuid()
+    }
+
+    uuid(x = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") {
+        return uuid(x)
+    }
+
+    async unfollow(shopId = this.shopId) {
+        let url = 'https://api.m.jd.com/client.action?g_ty=ls&g_tk=518274330'
+        let body = `functionId=followShop&body={"follow":"false","shopId":"${shopId
+        || this.shopId}","award":"true","sourceRpc":"shop_app_home_follow"}&osVersion=13.7&appid=wh5&clientVersion=9.2.0&loginType=2&loginWQBiz=interact`
+        let headers = {
+            'Accept': 'application/json, text/plain, */*',
+            'Accept-Encoding': 'gzip, deflate, br',
+            'Content-Type': 'application/x-www-form-urlencoded',
+            'Host': 'api.m.jd.com',
+            'Connection': 'keep-alive',
+            'Accept-Language': 'zh-cn',
+            'Cookie': this.cookie
+        }
+        headers['User-Agent'] = `Mozilla/5.0 (iPhone; CPU iPhone OS 14_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.4(0x1800042c) NetType/4G Language/zh_CN miniProgram`
+        let {data} = await this.request(url, headers, body);
+        this.log(data.msg)
+        return data;
+    }
+
+    async getShopInfo(venderId = this.venderId) {
+        try {
+            let url = `https://wq.jd.com/mshop/QueryShopMemberInfoJson?venderId=${venderId
+            || this.venderId}`
+            let headers = {
+                "Accept": "*/*",
+                "Accept-Encoding": "gzip, deflate, br",
+                "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
+                "Referer": 'https://h5.m.jd.com/',
+                "User-Agent": `Mozilla/5.0 (Linux; U; Android 10; zh-cn; MI 8 Build/QKQ1.190828.002) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/79.0.3945.147 Mobile Safari/537.36 XiaoMi/MiuiBrowser/13.5.40`,
+                'Cookie': this.cookie
+            }
+            return await this.get(url, headers);
+        } catch (e) {
+            return {}
+        }
+    }
+
+    randomCallback(e = 1) {
+        let t = "abcdefghigklmnopqrstuvwsyz", a = t.length, n = '';
+        for (let i = 0; i < e; i++) {
+            n += t.charAt(Math.floor(Math.random() * a));
+        }
+        return "jsonpCBK" + n.toUpperCase()
+    }
+
+    randomArray(arr, count) {
+        count = count || arr.length
+        let shuffled = arr.slice(0), i = arr.length, min = i - count, temp,
+            index;
+        while (i-- > min) {
+            index = Math.floor((i + 1) * Math.random());
+            temp = shuffled[index];
+            shuffled[index] = shuffled[i];
+            shuffled[i] = temp;
+        }
+        return shuffled.slice(min);
+    }
+
+    now(fmt) {
+        return format(Date.now(), fmt || 'yyyy-MM-dd HH:mm:ss.SSS')
+    }
+
+    formatDate(date, fmt) {
+        // noinspection JSCheckFunctionSignatures
+        return format(typeof date === 'object' ? date : new Date(
+            typeof date === 'string' ? date * 1 : date),
+            fmt || 'yyyy-MM-dd')
+    }
+
+    //yyyy-MM-dd HH:mm:ss
+    parseDate(date) {
+        let d = new Date(Date.parse(date.replace(/-/g, "/")));
+        d.setHours(d.getHours() + 8)
+        return d;
+    }
+
+    timestamp() {
+        return new Date().getTime()
+    }
+
+    _tk() {
+        let id = function (n) {
+            let src = 'abcdefghijklmnopqrstuvwxyz1234567890', res = '';
+            for (let i = 0; i < n; i++) {
+                res += src[Math.floor(src.length * Math.random())];
+            }
+            return res;
+        }(40), ts = Date.now().toString(), tk = this.md5(
+            '' + decodeURIComponent(this.username) + ts + id
+            + 'tPOamqCuk9NLgVPAljUyIHcPRmKlVxDy');
+        return {ts: ts, id: id, tk: tk}
+    }
+
+    ua(type = 'jd') {
+        return JDAPP_USER_AGENTS[this.random(0, JDAPP_USER_AGENTS.length)]
+    }
+
+    async sign(fn, body = {}) {
+        let b = {"fn": fn, "body": body};
+        let h = {"key": "fMQ8sw1y5zF4RZgT"}
+        try {
+            let {data} = await this.request(`http://140.238.59.174:17840/sign`,
+                h, b);
+            return {fn: data.fn, sign: data.body};
+        } catch (e) {
+            console.log("sign接口异常")
+            //console.log("请自行配置sign实现")
+        }
+        return {fn: "", sign: ""};
+    }
+
+    async _algo() {
+        if (this.appId.length === 2) {
+            if (this.domain.includes('lzkj') || this.domain.includes('lzdz')
+                || this.domain.includes('cjhy')) {
+                let url = `https://${this.domain}/wxTeam/activity?activityId=${this.activityId}`
+                await this.request(url, {
+                    'Accept-Encoding': 'gzip, deflate, br',
+                    'Connection': 'keep-alive',
+                    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
+                    "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Mobile/15E148 Safari/604.1",
+                    'Accept-Language': 'zh-cn',
+                    'Cookie': this.cookie
+                })
+            }
+            return ''
+        } else {
+            let fp = function () {
+                let e = "0123456789", a = 13, i = ''
+                for (; a--;) {
+                    i += e[Math.random() * e.length | 0]
+                }
+                return (i + Date.now()).slice(0, 16)
+            }();
+            let data = await this.post(
+                'https://cactus.jd.com/request_algo?g_ty=ajax', JSON.stringify({
+                    "version": "1.0",
+                    "fp": fp,
+                    "appId": this.appId,
+                    "timestamp": this.timestamp(),
+                    "platform": "web",
+                    "expandParams": ''
+                }), {
+                    'Authority': 'cactus.jd.com',
+                    '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',
+                    'Content-Type': 'application/json',
+                    'Origin': 'https://st.jingxi.com',
+                    'Referer': 'https://st.jingxi.com/',
+                });
+            return {
+                fp: fp.toString(),
+                tk: data?.data?.result?.tk || data?.result?.tk,
+                em: new Function(
+                    `return ${data?.data?.result?.algo
+                    || data?.result?.algo}`)()
+            }
+        }
+    }
+
+    async isvObfuscator() {
+        let url = `https://api.m.jd.com/client.action?functionId=isvObfuscator`
+        let body = ''
+        switch (this.domain) {
+            case 'cjhy-isv.isvjcloud.com':
+            case 'lzkj-isv.isvjcloud.com':
+            case 'txzj-isv.isvjcloud.com':
+            case 'lzdz-isv.isvjcloud.com':
+            case 'cjhydz-isv.isvjcloud.com':
+                body = this.randomArray(ISV_OBFUSCATOR[this.domain], 1)[0]
+                break
+            default:
+                body = 'adid=7B411CD9-D62C-425B-B083-9AFC49B94228&area=16_1332_42932_43102&body=%7B%22url%22%3A%22https%3A%5C/%5C/cjhydz-isv.isvjcloud.com%22%2C%22id%22%3A%22%22%7D&build=167541&client=apple&clientVersion=9.4.0&d_brand=apple&d_model=iPhone8%2C1&eid=eidId10b812191seBCFGmtbeTX2vXF3lbgDAVwQhSA8wKqj6OA9J4foPQm3UzRwrrLdO23B3E2wCUY/bODH01VnxiEnAUvoM6SiEnmP3IPqRuO%2By/%2BZo&isBackground=N&joycious=48&lang=zh_CN&networkType=wifi&networklibtype=JDNetworkBaseAF&openudid=2f7578cb634065f9beae94d013f172e197d62283&osVersion=13.1.2&partner=apple&rfs=0000&scope=11&screen=750%2A1334&sign=60bde51b4b7f7ff6e1bc1f473ecf3d41&st=1613720203903&sv=110&uts=0f31TVRjBStG9NoZJdXLGd939Wv4AlsWNAeL1nxafUsZqiV4NLsVElz6AjC4L7tsnZ1loeT2A8Z5/KfI/YoJAUfJzTd8kCedfnLG522ydI0p40oi8hT2p2sNZiIIRYCfjIr7IAL%2BFkLsrWdSiPZP5QLptc8Cy4Od6/cdYidClR0NwPMd58K5J9narz78y9ocGe8uTfyBIoA9aCd/X3Muxw%3D%3D&uuid=hjudwgohxzVu96krv/T6Hg%3D%3D&wifiBssid=9cf90c586c4468e00678545b16176ed2'
+        }
+        let headers = {
+            "Accept": "*/*",
+            "Accept-Encoding": "gzip, deflate, br",
+            "Accept-Language": "zh-cn",
+            "Connection": "keep-alive",
+            "Content-Type": "application/x-www-form-urlencoded",
+            "Host": "api.m.jd.com",
+            "Cookie": this.cookie,
+            "User-Agent": this.UA,
+        }
+        let {data} = await this.request(url, headers, body)
+        return data;
+    }
+
+    async api(fn, body) {
+        let url = `https://${this.domain}/${fn}`
+        let ck = `IsvToken=${this.Token};` + this.lz + (this.Pin
+            && "AUTH_C_USER=" + this.Pin + ";" || "")
+        this.domain.includes('cjhy') ? ck += 'APP_ABBR=CJHY;' : ''
+        let headers = {
+            "Host": this.domain,
+            "Accept": "application/json",
+            "Accept-Encoding": "gzip, deflate, br",
+            "Accept-Language": "zh-cn",
+            "Connection": "keep-alive",
+            "Content-Type": "application/x-www-form-urlencoded",
+            "Origin": `https://${this.domain}`,
+            "Cookie": ck,
+            "Referer": `${this.activityUrl}&sid=&un_area=`,
+            "User-Agent": this.UA
+        }
+        let {data} = await this.request(url, headers, body);
+        return data;
+    }
+
+    async wxStop(err) {
+        let flag = false;
+        if (!err) {
+            return flag
+        }
+        let stopKeywords = ['来晚了', '已发完', '非法操作', '奖品发送失败', '活动还未开始',
+            '发放完', '全部被领取', '余额不足', '已结束']
+        process.env.M_WX_STOP_KEYWORD ? process.env.M_WX_STOP_KEYWORD.split(
+            '@').forEach((item) => stopKeywords.push(item)) : ''
+        for (let e of stopKeywords) {
+            if (err.includes(e)) {
+                flag = true;
+                break
+            }
+        }
+        return flag;
+    }
+
+    async sendMessage(chat_id, text, count = 1) {
+        let url = `https://api.telegram.org/bot${process.env.TG_BOT_TOKEN}/sendMessage`
+        let body = {
+            'chat_id': chat_id,
+            'text': text,
+            'disable_web_page_preview': true
+        }
+        let headers = {
+            'Content-Type': 'application/json',
+            'Cookie': '10089'
+        }
+        let {data} = await this.request(url, headers, body);
+        this.log('发送数据', text)
+        if (!data?.ok && count === 1) {
+            $.log('重试中', text)
+            await $.wait(1000, 2000)
+            await this.sendMessage(chat_id, text, count++);
+        }
+    }
+}
+
+module.exports = {Env, CryptoJS};
diff --git a/magic.json b/magic.json
new file mode 100644
index 0000000..7fa4ad9
--- /dev/null
+++ b/magic.json
@@ -0,0 +1,15 @@
+{
+    "user_id": 9513068,
+    "bot_token": "1657567:AAGO7sxIVvhdSHSJt_k_0u_C1w7U",
+    "api_id": "37419",
+    "api_hash": "f81a30b54255566c15b3d578",
+    "//proxy 需要代理 true 不需要道理 false": 1,
+    "proxy": true,
+    "proxy_add": "127.0.0.1",
+    "proxy_port": 7890,
+    "proxy_username": "",
+    "proxy_password": "",
+    "//base_path 填脚本所在目录": 1,
+    "base_path": "填脚本所在目录",
+    "car_group_id": -1001533334185
+}
\ No newline at end of file
diff --git a/magic.py b/magic.py
new file mode 100644
index 0000000..078d782
--- /dev/null
+++ b/magic.py
@@ -0,0 +1,191 @@
+import asyncio
+import datetime
+import json
+import os
+import re
+import urllib.parse
+
+from cacheout import FIFOCache
+from pyrogram import Client, filters
+
+cache = FIFOCache(maxsize=512)
+
+platform = "v4"
+if os.path.exists("/jd/config/magic.json"):
+    with open("/jd/config/magic.json", 'r', encoding='utf-8') as f:
+        BOT = json.load(f)
+
+if os.path.exists("/ql/config/magic.json"):
+    platform = "ql"
+    with open("/ql/config/magic.json", 'r', encoding='utf-8') as f:
+        BOT = json.load(f)
+
+if os.path.exists("/ql/data/config/magic.json"):
+    platform = "ql2"
+    with open("/ql/data/config/magic.json", 'r', encoding='utf-8') as f:
+        BOT = json.load(f)
+
+api_id = int(BOT['api_id'])
+api_hash = BOT['api_hash']
+my_id = int(BOT['user_id'])
+my_bot_id = int(BOT['bot_token'].split(":")[0])
+base_path = BOT['base_path']
+
+if platform == "v4":
+    _ConfigSH = '/jd/config/config.sh'
+elif platform == 'ql':
+    _ConfigSH = '/ql/config/config.sh'
+else:
+    _ConfigSH = '/ql/data/config/config.sh'
+
+if BOT['proxy']:
+    proxy = {
+        'hostname': BOT['proxy_add'],  # 改成自己的
+        'port': int(BOT['proxy_port']),
+        'username': BOT['proxy_username'],
+        'password': BOT['proxy_password']
+    }
+    app = Client('magic', api_id, api_hash, proxy=proxy)
+else:
+    app = Client('magic', api_id, api_hash)
+
+# 监控的自动车
+car_group_id = int(BOT['car_group_id'])
+
+monitor_flag = 'https://i.walle.com/api?data='
+
+# 你的脚本配置
+car_config = [
+    {'name': 'M加购有礼', 'env': 'M_WX_ADD_CART_URL', 'js': 'm_jd_wx_addCart.js', 'cmd': 'now'},
+    {'name': 'M幸运抽奖', 'env': 'M_WX_LUCK_DRAW_URL', 'js': 'm_jd_wx_luckDraw.js', 'cmd': 'now'},
+    {'name': 'M集卡抽奖', 'env': 'M_WX_COLLECT_CARD_URL', 'js': 'm_jd_wx_collectCard.js', 'cmd': 'now'},
+    {'name': 'M关注有礼', 'env': 'M_FOLLOW_SHOP_ARGV', 'js': 'm_jd_follow_shop.js', 'cmd': 'now'}
+]
+
+
+@app.on_message(filters.chat(my_bot_id) & filters.regex("在吗"))
+async def handler(client, message):
+    await message.reply("老板啥事!")
+
+
+@app.on_message(filters.chat(car_group_id) & filters.text)
+async def handler(client, message):
+    try:
+        if message.entities is None:
+            return
+        text = message.entities[0]['url']
+        if text is None:
+            return
+        if 'i.walle.com' not in text:
+            return
+        text = urllib.parse.unquote(text.replace(monitor_flag, ''))
+        zd = 1
+        if 'jd_zdjr_activityId' in text:
+            zd = re.search(f'jd_zdjr_activityId="(.*)"', text)[1]
+        if zd != 1:
+            if cache.get(zd) is not None:
+                await client.send_message(my_bot_id, f'跑过 {text}')
+                return
+            cache.set(zd, zd)
+        else:
+            if cache.get(text) is not None:
+                await client.send_message(my_bot_id, f'跑过 {text}')
+                return
+            cache.set(text, text)
+        name = ''
+        js = ''
+        command = ''
+        for v in car_config:
+            if v['env'] in text:
+                name = v['name']
+                js = v['js']
+                command = v['cmd']
+                break
+        if len(name) == 0:
+            await client.send_message(my_bot_id, f'未知变量`{text}`')
+            return
+        messages = text.split("\n")
+        change = ""
+        for message in messages:
+            if "export " not in message:
+                continue
+            kv = message.replace("export ", "")
+            key = kv.split("=")[0]
+            value = re.findall(r'"([^"]*)"', kv)[0]
+            configs = rwcon("str")
+            if kv in configs:
+                continue
+            if key in configs:
+                configs = re.sub(f'{key}=("|\').*("|\')', kv, configs)
+                change += f"【替换】 `{name}` 环境变量成功\n`{kv}\n`"
+            else:
+                if platform == 'v4':
+                    end_line = 0
+                    configs = rwcon("list")
+                    for config in configs:
+                        if "第五区域" in config and "↑" in config:
+                            end_line = configs.index(config) - 1
+                            break
+                    configs.insert(end_line, f'export {key}="{value}"\n')
+                else:
+                    configs = rwcon("str")
+                    configs += f'export {key}="{value}"\n'
+                change += f"【新增】 `{name}` 环境变量成功\n`{kv}\n`"
+                await client.send_message(my_bot_id, change)
+            rwcon(configs)
+        if len(change) == 0:
+            await client.send_message(my_bot_id, f'【取消】{name}环境变量无需改动')
+            return
+        if len(js) > 0:
+            await client.send_message(my_bot_id, f'开始运行 {js}')
+            if platform == 'v4':
+                await cmd(client, f'jtask {base_path}/{js} {command}')
+            else:
+                await cmd(client, f'task {base_path}/{js} {command}')
+        else:
+            await client.send_message(my_bot_id, f'无需执行')
+    except Exception as e:
+        await client.send_message(my_bot_id, f'{str(e)}')
+
+
+async def cmd(client, cmd_text):
+    '''定义执行cmd命令'''
+    try:
+        p = await asyncio.create_subprocess_shell(
+            cmd_text, stdout=asyncio.subprocess.PIPE,
+            stderr=asyncio.subprocess.PIPE)
+        res_bytes, res_err = await p.communicate()
+        res = res_bytes.decode('utf-8')
+        if len(res) > 0:
+            if platform == "v4":
+                base = "/jd"
+            elif platform == "ql":
+                base = "/ql"
+            else:
+                base = "/ql/data"
+            tmp_log = f'{base}/log/bot/{cmd_text.split("/")[-1].split(".js")[0]}-{datetime.datetime.now().strftime("%H-%M-%S.%f")}.log'
+            with open(tmp_log, 'w+', encoding='utf-8') as f:
+                f.write(res)
+    except Exception as e:
+        await client.send_message(my_bot_id, f'日志目录有误,{str(e)}')
+
+
+# 读写config.sh
+def rwcon(arg):
+    if arg == "str":
+        with open(_ConfigSH, 'r', encoding='utf-8') as f1:
+            configs = f1.read()
+        return configs
+    elif arg == "list":
+        with open(_ConfigSH, 'r', encoding='utf-8') as f1:
+            configs = f1.readlines()
+        return configs
+    elif isinstance(arg, str):
+        with open(_ConfigSH, 'w', encoding='utf-8') as f1:
+            f1.write(arg)
+    elif isinstance(arg, list):
+        with open(_ConfigSH, 'w', encoding='utf-8') as f1:
+            f1.write("".join(arg))
+
+
+app.run()
diff --git a/mount.sh b/mount.sh
new file mode 100644
index 0000000..23b9152
--- /dev/null
+++ b/mount.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+ln -s /ql/data/config /ql/config
+ln -s /ql/data/db /ql/db
+ln -s /ql/data/jbot /ql/jbot
+ln -s /ql/data/log /ql/log
+ln -s /ql/data/scripts /ql/scripts
+echo "# 旧版青龙目录挂载完成。"
\ No newline at end of file
diff --git a/test.js b/test.js
new file mode 100644
index 0000000..8edfc12
--- /dev/null
+++ b/test.js
@@ -0,0 +1,34 @@
+const {Env} = require('./magic');
+const $ = new Env('MTest');
+
+$.logic = async function () {
+    let activityContent = {
+        "result": true,
+        "data": {
+            "id": "173f89d8cc6d413e81a357b07137d56d",
+            "userId": 197936,
+            "venderType": 0,
+            "endTime": 1649381820000,
+            "list": [{
+                "type": "dq",
+                "takeNum": null,
+                "discount": "20",
+                "quota": "499"
+            }],
+            "hasFollow": false,
+            "openCard": false,
+            "shopMember": false,
+            "shopgiftActivity": null
+        },
+        "count": 0,
+        "errorMessage": ""
+    }
+    $.content = activityContent.data.list
+    let ts = $.content.filter(o => ['jd', 'jf'].includes(o.type));
+    if (ts.length === 0) {
+        $.putMsg(`不是豆子或积分不跑`);
+    }
+
+};
+$.run({whitelist: [1]})
+.catch(reason => $.log(reason));